diff --git a/src/bootsupport/modules/logger-0.9.5.tm b/src/bootsupport/modules/logger-0.9.5.tm new file mode 100644 index 00000000..739e1c91 --- /dev/null +++ b/src/bootsupport/modules/logger-0.9.5.tm @@ -0,0 +1,1297 @@ +# logger.tcl -- +# +# Tcl implementation of a general logging facility. +# +# Copyright (c) 2003 by David N. Welton +# Copyright (c) 2004-2011 by Michael Schlenker +# Copyright (c) 2006,2015 by Andreas Kupries +# +# See the file license.terms. + +# The logger package provides an 'object oriented' log facility that +# lets you have trees of services, that inherit from one another. +# This is accomplished through the use of Tcl namespaces. + + +package require Tcl 8.5 9 +package provide logger 0.9.5 + +namespace eval ::logger { + namespace eval tree {} + namespace export init enable disable services servicecmd import + + # The active services. + variable services {} + + # The log 'levels'. + variable levels [list debug info notice warn error critical alert emergency] + + # The default global log level used for new logging services + variable enabled "debug" + + # Tcl return codes (in numeric order) + variable RETURN_CODES [list "ok" "error" "return" "break" "continue"] +} + +# Try to load msgcat and fall back to format if it fails +if {[catch {package require msgcat}]} { + interp alias {} ::logger::mc {} ::format +} else { + namespace eval ::logger { + namespace import ::msgcat::mc + } +} + +# ::logger::_nsExists -- +# +# Workaround for missing namespace exists in Tcl 8.2 and 8.3. +# + +if {[package vcompare [package provide Tcl] 8.4] < 0} { + proc ::logger::_nsExists {ns} { + expr {![catch {namespace parent $ns}]} + } +} else { + proc ::logger::_nsExists {ns} { + namespace exists $ns + } +} + +# ::logger::_cmdPrefixExists -- +# +# Utility function to check if a given callback prefix exists, +# this should catch all oddities in prefix names, including spaces, +# glob patterns, non normalized namespaces etc. +# +# Arguments: +# prefix - The command prefix to check +# +# Results: +# 1 or 0 for yes or no +# +proc ::logger::_cmdPrefixExists {prefix} { + set cmd [lindex $prefix 0] + set full [namespace eval :: namespace which [list $cmd]] + if {[string equal $full ""]} {return 0} else {return 1} + # normalize namespaces + set ns [namespace qualifiers $cmd] + set cmd ${ns}::[namespace tail $cmd] + set matches [::info commands ${ns}::*] + if {[lsearch -exact $matches $cmd] != -1} {return 1} + return 0 +} + +# ::logger::walk -- +# +# Walk namespaces, starting in 'start', and evaluate 'code' in +# them. +# +# Arguments: +# start - namespace to start in. +# code - code to execute in namespaces walked. +# +# Side Effects: +# Side effects of code executed. +# +# Results: +# None. + +proc ::logger::walk { start code } { + set children [namespace children $start] + foreach c $children { + logger::walk $c $code + namespace eval $c $code + } +} + +proc ::logger::init {service} { + variable levels + variable services + variable enabled + + if {[string length [string trim $service {:}]] == 0} { + return -code error \ + -errorcode [list LOGGER EMPTY_SERVICENAME] \ + [::logger::mc "Service name invalid. May not consist only of : or be empty"] + } + # We create a 'tree' namespace to house all the services, so + # they are in a 'safe' namespace sandbox, and won't overwrite + # any commands. + namespace eval tree::${service} { + variable service + variable levels + variable oldname + variable enabled + } + + lappend services $service + + set [namespace current]::tree::${service}::service $service + set [namespace current]::tree::${service}::levels $levels + set [namespace current]::tree::${service}::oldname $service + set [namespace current]::tree::${service}::enabled $enabled + + namespace eval tree::${service} { + # Callback to use when the service in question is shut down. + variable delcallback [namespace current]::no-op + + # Callback when the loglevel is changed + variable levelchangecallback [namespace current]::no-op + + # State variable to decide when to call levelcallback + variable inSetLevel 0 + + # The currently configured levelcommands + variable lvlcmds + array set lvlcmds {} + + # List of procedures registered via the trace command + variable traceList "" + + # Flag indicating whether or not tracing is currently enabled + variable tracingEnabled 0 + + # We use this to disable a service completely. In Tcl 8.4 + # or greater, by using this, disabled log calls are a + # no-op! + + proc no-op args {} + + proc stdoutcmd {level text} { + variable service + puts "\[[clock format [clock seconds]]\] \[$service\] \[$level\] \'$text\'" + } + + proc stderrcmd {level text} { + variable service + puts stderr "\[[clock format [clock seconds]]\] \[$service\] \[$level\] \'$text\'" + } + + + # setlevel -- + # + # This command differs from enable and disable in that + # it disables all the levels below that selected, and + # then enables all levels above it, which enable/disable + # do not do. + # + # Arguments: + # lv - the level, as defined in $levels. + # + # Side Effects: + # Runs disable for the level, and then enable, in order + # to ensure that all levels are set correctly. + # + # Results: + # None. + + + proc setlevel {lv} { + variable inSetLevel 1 + set oldlvl [currentloglevel] + + # do not allow enable and disable to do recursion + if {[catch { + disable $lv 0 + set newlvl [enable $lv 0] + } msg] == 1} { + return -code error -errorcode $::errorCode $msg + } + # do the recursion here + logger::walk [namespace current] [list setlevel $lv] + + set inSetLevel 0 + lvlchangewrapper $oldlvl $newlvl + return + } + + # enable -- + # + # Enable a particular 'level', and above, for the + # service, and its 'children'. + # + # Arguments: + # lv - the level, as defined in $levels. + # + # Side Effects: + # Enables logging for the particular level, and all + # above it (those more important). It also walks + # through all services that are 'children' and enables + # them at the same level or above. + # + # Results: + # None. + + proc enable {lv {recursion 1}} { + variable levels + set lvnum [lsearch -exact $levels $lv] + if { $lvnum == -1 } { + return -code error \ + -errorcode [list LOGGER INVALID_LEVEL] \ + [::logger::mc "Invalid level '%s' - levels are %s" $lv $levels] + } + + variable enabled + set newlevel $enabled + set elnum [lsearch -exact $levels $enabled] + if {($elnum == -1) || ($elnum > $lvnum)} { + set newlevel $lv + } + + variable service + while { $lvnum < [llength $levels] } { + interp alias {} [namespace current]::[lindex $levels $lvnum] \ + {} [namespace current]::[lindex $levels $lvnum]cmd + incr lvnum + } + + if {$recursion} { + logger::walk [namespace current] [list enable $lv] + } + lvlchangewrapper $enabled $newlevel + set enabled $newlevel + } + + # disable -- + # + # Disable a particular 'level', and below, for the + # service, and its 'children'. + # + # Arguments: + # lv - the level, as defined in $levels. + # + # Side Effects: + # Disables logging for the particular level, and all + # below it (those less important). It also walks + # through all services that are 'children' and disables + # them at the same level or below. + # + # Results: + # None. + + proc disable {lv {recursion 1}} { + variable levels + set lvnum [lsearch -exact $levels $lv] + if { $lvnum == -1 } { + return -code error \ + -errorcode [list LOGGER INVALID_LEVEL] \ + [::logger::mc "Invalid level '%s' - levels are %s" $lv $levels] + } + + variable enabled + set newlevel $enabled + set elnum [lsearch -exact $levels $enabled] + if {($elnum > -1) && ($elnum <= $lvnum)} { + if {$lvnum+1 >= [llength $levels]} { + set newlevel "none" + } else { + set newlevel [lindex $levels [expr {$lvnum+1}]] + } + } + + while { $lvnum >= 0 } { + + interp alias {} [namespace current]::[lindex $levels $lvnum] {} \ + [namespace current]::no-op + incr lvnum -1 + } + if {$recursion} { + logger::walk [namespace current] [list disable $lv] + } + lvlchangewrapper $enabled $newlevel + set enabled $newlevel + } + + # currentloglevel -- + # + # Get the currently enabled log level for this service. + # + # Arguments: + # none + # + # Side Effects: + # none + # + # Results: + # current log level + # + + proc currentloglevel {} { + variable enabled + return $enabled + } + + # lvlchangeproc -- + # + # Set or introspect a callback for when the logger instance + # changes its loglevel. + # + # Arguments: + # cmd - the Tcl command to call, it is called with two parameters, old and new log level. + # or none for introspection + # + # Side Effects: + # None. + # + # Results: + # If no arguments are given return the current callback cmd. + + proc lvlchangeproc {args} { + variable levelchangecallback + + switch -exact -- [llength [::info level 0]] { + 1 {return $levelchangecallback} + 2 { + if {[::logger::_cmdPrefixExists [lindex $args 0]]} { + set levelchangecallback [lindex $args 0] + } else { + return -code error \ + -errorcode [list LOGGER INVALID_CMD] \ + [::logger::mc "Invalid cmd '%s' - does not exist" [lindex $args 0]] + } + } + default { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc "Wrong # of arguments. Usage: \${log}::lvlchangeproc ?cmd?"] + } + } + } + + proc lvlchangewrapper {old new} { + variable inSetLevel + + # we are called after disable and enable are finished + if {$inSetLevel} {return} + + # no action if level does not change + if {[string equal $old $new]} {return} + + variable levelchangecallback + # no action if levelchangecallback isn't a valid command + if {[::logger::_cmdPrefixExists $levelchangecallback]} { + catch { + uplevel \#0 [linsert $levelchangecallback end $old $new] + } + } + } + + # logproc -- + # + # Command used to create a procedure that is executed to + # perform the logging. This could write to disk, out to + # the network, or something else. + # If two arguments are given, use an existing command. + # If three arguments are given, create a proc. + # + # Arguments: + # lv - the level to log, which must be one of $levels. + # args - either zero, one or two arguments. + # if zero this returns the current command registered + # if one, this is a cmd name that is called for this level + # if two, these are an argument and proc body + # + # Side Effects: + # Creates a logging command to take care of the details + # of logging an event. + # + # Results: + # If called with zero length args, returns the name of the currently + # configured logging procedure. + # + # + + proc logproc {lv args} { + variable levels + variable lvlcmds + + set lvnum [lsearch -exact $levels $lv] + if { ($lvnum == -1) && ($lv != "trace") } { + return -code error \ + -errorcode [list LOGGER INVALID_LEVEL] \ + [::logger::mc "Invalid level '%s' - levels are %s" $lv $levels] + } + switch -exact -- [llength $args] { + 0 { + return $lvlcmds($lv) + } + 1 { + set cmd [lindex $args 0] + if {[string equal "[namespace current]::${lv}cmd" $cmd]} {return} + if {[llength [::info commands $cmd]]} { + proc ${lv}cmd args [format { + uplevel 1 [list %s [expr {[llength $args]==1 ? [lindex $args end] : $args}]] + } $cmd] + } else { + return -code error \ + -errorcode [list LOGGER INVALID_CMD] \ + [::logger::mc "Invalid cmd '%s' - does not exist" $cmd] + } + set lvlcmds($lv) $cmd + } + 2 { + foreach {arg body} $args {break} + proc ${lv}cmd args [format {\ + _setservicename args + set val [%s [expr {[llength $args]==1 ? [lindex $args end] : $args}]] + _restoreservice + set val} ${lv}customcmd] + proc ${lv}customcmd $arg $body + set lvlcmds($lv) [namespace current]::${lv}customcmd + } + default { + return -code error \ + -errorcode [list LOGGER WRONG_USAGE] \ + [::logger::mc \ + "Usage: \${log}::logproc level ?cmd?\nor \${log}::logproc level argname body" ] + } + } + } + + + # delproc -- + # + # Set or introspect a callback for when the logger instance + # is deleted. + # + # Arguments: + # cmd - the Tcl command to call. + # or none for introspection + # + # Side Effects: + # None. + # + # Results: + # If no arguments are given return the current callback cmd. + + proc delproc {args} { + variable delcallback + + switch -exact -- [llength [::info level 0]] { + 1 {return $delcallback} + 2 { if {[::logger::_cmdPrefixExists [lindex $args 0]]} { + set delcallback [lindex $args 0] + } else { + return -code error \ + -errorcode [list LOGGER INVALID_CMD] \ + [::logger::mc "Invalid cmd '%s' - does not exist" [lindex $args 0]] + } + } + default { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc "Wrong # of arguments. Usage: \${log}::delproc ?cmd?"] + } + } + } + + + # delete -- + # + # Delete the namespace and its children. + + proc delete {} { + variable delcallback + variable service + + logger::walk [namespace current] delete + if {[::logger::_cmdPrefixExists $delcallback]} { + uplevel \#0 [lrange $delcallback 0 end] + } + # clean up the global services list + set idx [lsearch -exact [logger::services] $service] + if {$idx !=-1} { + set ::logger::services [lreplace [logger::services] $idx $idx] + } + + namespace delete [namespace current] + + } + + # services -- + # + # Return all child services + + proc services {} { + variable service + + set children [list] + foreach srv [logger::services] { + if {[string match "${service}::*" $srv]} { + lappend children $srv + } + } + return $children + } + + # servicename -- + # + # Return the name of the service + + proc servicename {} { + variable service + return $service + } + + proc _setservicename {argname} { + variable service + variable oldname + upvar 1 $argname arg + if {[llength $arg] <= 1} { + return + } + + set count -1 + set newname "" + while {[string equal [lindex $arg [expr {$count+1}]] "-_logger::service"]} { + incr count 2 + set newname [lindex $arg $count] + } + if {[string equal $newname ""]} { + return + } + set oldname $service + set service $newname + # Pop off "-_logger::service " from argument list + set arg [lreplace $arg 0 $count] + } + + proc _restoreservice {} { + variable service + variable oldname + set service $oldname + return + } + + proc trace { action args } { + variable service + + # Allow other boolean values (true, false, yes, no, 0, 1) to be used + # as synonymns for "on" and "off". + + if {[string is boolean $action]} { + set xaction [expr {($action && 1) ? "on" : "off"}] + } else { + set xaction $action + } + + # Check for required arguments for actions/subcommands and dispatch + # to the appropriate procedure. + + switch -- $xaction { + "status" { + return [uplevel 1 [list logger::_trace_status $service $args]] + } + "on" { + if {[llength $args]} { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc "wrong # args: should be \"trace on\""] + } + return [logger::_trace_on $service] + } + "off" { + if {[llength $args]} { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc "wrong # args: should be \"trace off\""] + } + return [logger::_trace_off $service] + } + "add" { + if {![llength $args]} { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc "wrong # args: should be \"trace add ?-ns? ...\""] + } + return [uplevel 1 [list ::logger::_trace_add $service $args]] + } + "remove" { + if {![llength $args]} { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc "wrong # args: should be \"trace remove ?-ns? ...\""] + } + return [uplevel 1 [list ::logger::_trace_remove $service $args]] + } + + default { + return -code error \ + -errorcode [list LOGGER INVALID_ARG] \ + [::logger::mc "Invalid action \"%s\": must be status, add, remove,\ + on, or off" $action] + } + } + } + + # Walk the parent service namespaces to see first, if they + # exist, and if any are enabled, and then, as a + # consequence, enable this one + # too. + + enable $enabled + variable parent [namespace parent] + while {[string compare $parent "::logger::tree"]} { + # If the 'enabled' variable doesn't exist, create the + # whole thing. + if { ! [::info exists ${parent}::enabled] } { + logger::init [string range $parent 16 end] + } + set enabled [set ${parent}::enabled] + enable $enabled + set parent [namespace parent $parent] + } + } + + # Now create the commands for different levels. + + namespace eval tree::${service} { + set parent [namespace parent] + + # We 'inherit' the commands from the parents. This + # means that, if you want to share the same methods with + # children, they should be instantiated after the parent's + # methods have been defined. + + variable lvl ; # prevent creative writing to the global scope + if {[string compare $parent "::logger::tree"]} { + foreach lvl [::logger::levels] { + # OPTIMIZE: do not allow multiple aliases in the hierarchy + # they can always be replaced by more efficient + # direct aliases to the target procs. + interp alias {} [namespace current]::${lvl}cmd \ + {} ${parent}::${lvl}cmd -_logger::service $service + } + # inherit the starting loglevel of the parent service + setlevel [${parent}::currentloglevel] + } else { + foreach lvl [concat [::logger::levels] "trace"] { + proc ${lvl}cmd args [format {\ + _setservicename args + set val [stdoutcmd %s [expr {[llength $args]==1 ? [lindex $args end] : $args}]] + _restoreservice + set val } $lvl] + + set lvlcmds($lvl) [namespace current]::${lvl}cmd + } + setlevel $::logger::enabled + } + unset lvl ; # drop the temp iteration variable + } + + return ::logger::tree::${service} +} + +# ::logger::services -- +# +# Returns a list of all active services. +# +# Arguments: +# None. +# +# Side Effects: +# None. +# +# Results: +# List of active services. + +proc ::logger::services {} { + variable services + return $services +} + +# ::logger::enable -- +# +# Global enable for a certain level. NOTE - this implementation +# isn't terribly effective at the moment, because it might hit +# children before their parents, who will then walk down the +# tree attempting to disable the children again. +# +# Arguments: +# lv - level above which to enable logging. +# +# Side Effects: +# Enables logging in a given level, and all higher levels. +# +# Results: +# None. + +proc ::logger::enable {lv} { + variable services + if {[catch { + foreach sv $services { + ::logger::tree::${sv}::enable $lv + } + } msg] == 1} { + return -code error -errorcode $::errorCode $msg + } +} + +proc ::logger::disable {lv} { + variable services + if {[catch { + foreach sv $services { + ::logger::tree::${sv}::disable $lv + } + } msg] == 1} { + return -code error -errorcode $::errorCode $msg + } +} + +proc ::logger::setlevel {lv} { + variable services + variable enabled + variable levels + if {[lsearch -exact $levels $lv] == -1} { + return -code error \ + -errorcode [list LOGGER INVALID_LEVEL] \ + [::logger::mc "Invalid level '%s' - levels are %s" $lv $levels] + } + set enabled $lv + if {[catch { + foreach sv $services { + ::logger::tree::${sv}::setlevel $lv + } + } msg] == 1} { + return -code error -errorcode $::errorCode $msg + } +} + +# ::logger::levels -- +# +# Introspect the available log levels. Provided so a caller does +# not need to know implementation details or code the list +# himself. +# +# Arguments: +# None. +# +# Side Effects: +# None. +# +# Results: +# levels - The list of valid log levels accepted by enable and disable + +proc ::logger::levels {} { + variable levels + return $levels +} + +# ::logger::servicecmd -- +# +# Get the command token for a given service name. +# +# Arguments: +# service - name of the service. +# +# Side Effects: +# none +# +# Results: +# log - namespace token for this service + +proc ::logger::servicecmd {service} { + variable services + if {[lsearch -exact $services $service] == -1} { + return -code error \ + -errorcode [list LOGGER NO_SUCH_SERVICE] \ + [::logger::mc "Service \"%s\" does not exist." $service] + } + return "::logger::tree::${service}" +} + +# ::logger::import -- +# +# Import the logging commands. +# +# Arguments: +# service - name of the service. +# +# Side Effects: +# creates aliases in the target namespace +# +# Results: +# none + +proc ::logger::import {args} { + variable services + + if {[llength $args] == 0 || [llength $args] > 7} { + return -code error \ + -errorcode [list LOGGER WRONG_NUM_ARGS] \ + [::logger::mc \ + "Wrong # of arguments: \"logger::import ?-all?\ + ?-force?\ + ?-prefix prefix? ?-namespace namespace? service\""] + } + + # process options + # + set import_all 0 + set force 0 + set prefix "" + set ns [uplevel 1 namespace current] + while {[llength $args] > 1} { + set opt [lindex $args 0] + set args [lrange $args 1 end] + switch -exact -- $opt { + -all { set import_all 1} + -prefix { set prefix [lindex $args 0] + set args [lrange $args 1 end] + } + -namespace { + set ns [lindex $args 0] + set args [lrange $args 1 end] + } + -force { + set force 1 + } + default { + return -code error \ + -errorcode [list LOGGER UNKNOWN_ARG] \ + [::logger::mc \ + "Unknown argument: \"%s\" :\nUsage:\ + \"logger::import ?-all? ?-force?\ + ?-prefix prefix? ?-namespace namespace? service\"" $opt] + } + } + } + + # + # build the list of commands to import + # + + set cmds [logger::levels] + lappend cmds "trace" + if {$import_all} { + lappend cmds setlevel enable disable logproc delproc services + lappend cmds servicename currentloglevel delete + } + + # + # check the service argument + # + + set service [lindex $args 0] + if {[lsearch -exact $services $service] == -1} { + return -code error \ + -errorcode [list LOGGER NO_SUCH_SERVICE] \ + [::logger::mc "Service \"%s\" does not exist." $service] + } + + # + # setup the namespace for the import + # + + set sourcens [logger::servicecmd $service] + set localns [uplevel 1 namespace current] + + if {[string match ::* $ns]} { + set importns $ns + } else { + set importns ${localns}::$ns + } + + # fake namespace exists for Tcl 8.2 - 8.3 + if {![_nsExists $importns]} { + namespace eval $importns {} + } + + + # + # prepare the import + # + + set imports "" + foreach cmd $cmds { + set cmdname ${importns}::${prefix}$cmd + set collision [llength [info commands $cmdname]] + if {$collision && !$force} { + return -code error \ + -errorcode [list LOGGER IMPORT_NAME_EXISTS] \ + [::logger::mc "can't import command \"%s\": already exists" $cmdname] + } + lappend imports ${importns}::${prefix}$cmd ${sourcens}::${cmd} + } + + # + # and execute the aliasing after checking all is well + # + + foreach {target source} $imports { + proc $target {args} "uplevel 1 \[linsert \$args 0 $source \]" + } +} + +# ::logger::initNamespace -- +# +# Creates a logger for the specified namespace and makes the log +# commands available to said namespace as well. Allows the initial +# setting of a default log level. +# +# Arguments: +# ns - Namespace to initialize, is also the service name, modulo a ::-prefix +# level - Initial log level, optional, defaults to 'warn'. +# +# Side Effects: +# creates aliases in the target namespace +# +# Results: +# none + +proc ::logger::initNamespace {ns {level {}}} { + set service [string trimleft $ns :] + if {$level == ""} { + # No user-specified level. Figure something out. + # - If the parent service exists then the 'logger::init' + # below will automatically inherit its level. Good enough. + # - Without a parent service go and use a default level of 'warn'. + set parent [string trimleft [namespace qualifiers $service] :] + set hasparent [expr {($parent != {}) && [_nsExists ::logger::tree::${parent}]}] + if {!$hasparent} { + set level warn + } + } + + namespace eval $ns [list ::logger::init $service] + namespace eval $ns [list ::logger::import -force -all -namespace log $service] + if {$level != ""} { + namespace eval $ns [list log::setlevel $level] + } + return +} + +# This procedure handles the "logger::trace status" command. Given no +# arguments, returns a list of all procedures that have been registered +# via "logger::trace add". Given one or more procedure names, it will +# return 1 if all were registered, or 0 if any were not. + +proc ::logger::_trace_status { service procList } { + upvar #0 ::logger::tree::${service}::traceList traceList + + # If no procedure names were given, just return the registered list + + if {![llength $procList]} { + return $traceList + } + + # Get caller's namespace for qualifying unqualified procedure names + + set caller_ns [uplevel 1 namespace current] + set caller_ns [string trimright $caller_ns ":"] + + # Search for any specified proc names that are *not* registered + + foreach procName $procList { + # Make sure the procedure namespace is qualified + + if {![string match "::*" $procName]} { + set procName ${caller_ns}::$procName + } + + # Check if the procedure has been registered for tracing + + if {[lsearch -exact $traceList $procName] == -1} { + return 0 + } + } + + return 1 +} + +# This procedure handles the "logger::trace on" command. If tracing +# is turned off, it will enable Tcl trace handlers for all of the procedures +# registered via "logger::trace add". Does nothing if tracing is already +# turned on. + +proc ::logger::_trace_on { service } { + set tcl_version [package provide Tcl] + + if {[package vcompare $tcl_version "8.4"] < 0} { + return -code error \ + -errorcode [list LOGGER TRACE_NOT_AVAILABLE] \ + [::logger::mc "execution tracing is not available in Tcl %s" $tcl_version] + } + + namespace eval ::logger::tree::${service} { + if {!$tracingEnabled} { + set tracingEnabled 1 + ::logger::_enable_traces $service $traceList + } + } + + return 1 +} + +# This procedure handles the "logger::trace off" command. If tracing +# is turned on, it will disable Tcl trace handlers for all of the procedures +# registered via "logger::trace add", leaving them in the list so they +# tracing on all of them can be enabled again with "logger::trace on". +# Does nothing if tracing is already turned off. + +proc ::logger::_trace_off { service } { + namespace eval ::logger::tree::${service} { + if {$tracingEnabled} { + ::logger::_disable_traces $service $traceList + set tracingEnabled 0 + } + } + + return 1 +} + +# This procedure is used by the logger::trace add and remove commands to +# process the arguments in a common fashion. If the -ns switch is given +# first, this procedure will return a list of all existing procedures in +# all of the namespaces given in remaining arguments. Otherwise, each +# argument is taken to be either a pattern for a glob-style search of +# procedure names or, failing that, a namespace, in which case this +# procedure returns a list of all the procedures matching the given +# pattern (or all in the named namespace, if no procedures match). + +proc ::logger::_trace_get_proclist { inputList } { + set procList "" + + if {[string equal [lindex $inputList 0] "-ns"]} { + # Verify that at least one target namespace was supplied + + set inputList [lrange $inputList 1 end] + if {![llength $inputList]} { + return -code error \ + -errorcode [list LOGGER TARGET_MISSING] \ + [::logger::mc "Must specify at least one namespace target"] + } + + # Rebuild the argument list to contain namespace procedures + + foreach namespace $inputList { + # Don't allow tracing of the logger (or child) namespaces + + if {![string match "::logger::*" $namespace]} { + set nsProcList [::info procs ${namespace}::*] + set procList [concat $procList $nsProcList] + } + } + } else { + # Search for procs or namespaces matching each of the specified + # patterns. + + foreach pattern $inputList { + set matches [uplevel 1 ::info proc $pattern] + + if {![llength $matches]} { + if {[uplevel 1 namespace exists $pattern]} { + set matches [::info procs ${pattern}::*] + } + + # Matched procs will be qualified due to above pattern + + set procList [concat $procList $matches] + } elseif {[string match "::*" $pattern]} { + # Patterns were pre-qualified - add them directly + + set procList [concat $procList $matches] + } else { + # Qualify each proc with the namespace it was in + + set ns [uplevel 1 namespace current] + if {$ns == "::"} { + set ns "" + } + foreach proc $matches { + lappend procList ${ns}::$proc + } + } + } + } + + return $procList +} + +# This procedure handles the "logger::trace add" command. If the tracing +# feature is enabled, it will enable the Tcl entry and leave trace handlers +# for each procedure specified that isn't already being traced. Each +# procedure is added to the list of procedures that the logger trace feature +# should log when tracing is enabled. + +proc ::logger::_trace_add { service procList } { + upvar #0 ::logger::tree::${service}::traceList traceList + + # Handle -ns switch and glob search patterns for procedure names + + set procList [uplevel 1 [list logger::_trace_get_proclist $procList]] + + # Enable tracing for each procedure that has not previously been + # specified via logger::trace add. If tracing is off, this will just + # store the name of the procedure for later when tracing is turned on. + + foreach procName $procList { + if {[lsearch -exact $traceList $procName] == -1} { + lappend traceList $procName + ::logger::_enable_traces $service [list $procName] + } + } +} + +# This procedure handles the "logger::trace remove" command. If the tracing +# feature is enabled, it will remove the Tcl entry and leave trace handlers +# for each procedure specified. Each procedure is removed from the list +# of procedures that the logger trace feature should log when tracing is +# enabled. + +proc ::logger::_trace_remove { service procList } { + upvar #0 ::logger::tree::${service}::traceList traceList + + # Handle -ns switch and glob search patterns for procedure names + + set procList [uplevel 1 [list logger::_trace_get_proclist $procList]] + + # Disable tracing for each proc that previously had been specified + # via logger::trace add. If tracing is off, this will just + # remove the name of the procedure from the trace list so that it + # will be excluded when tracing is turned on. + + foreach procName $procList { + set index [lsearch -exact $traceList $procName] + if {$index != -1} { + set traceList [lreplace $traceList $index $index] + ::logger::_disable_traces $service [list $procName] + } + } +} + +# This procedure enables Tcl trace handlers for all procedures specified. +# It is used both to enable Tcl's tracing for a single procedure when +# removed via "logger::trace add", as well as to enable all traces +# via "logger::trace on". + +proc ::logger::_enable_traces { service procList } { + upvar #0 ::logger::tree::${service}::tracingEnabled tracingEnabled + + if {$tracingEnabled} { + foreach procName $procList { + ::trace add execution $procName enter \ + [list ::logger::_trace_enter $service] + ::trace add execution $procName leave \ + [list ::logger::_trace_leave $service] + } + } +} + +# This procedure disables Tcl trace handlers for all procedures specified. +# It is used both to disable Tcl's tracing for a single procedure when +# removed via "logger::trace remove", as well as to disable all traces +# via "logger::trace off". + +proc ::logger::_disable_traces { service procList } { + upvar #0 ::logger::tree::${service}::tracingEnabled tracingEnabled + + if {$tracingEnabled} { + foreach procName $procList { + ::trace remove execution $procName enter \ + [list ::logger::_trace_enter $service] + ::trace remove execution $procName leave \ + [list ::logger::_trace_leave $service] + } + } +} + +######################################################################## +# Trace Handlers +######################################################################## + +# This procedure is invoked upon entry into a procedure being traced +# via "logger::trace add" when tracing is enabled via "logger::trace on" +# to log information about how the procedure was called. + +proc ::logger::_trace_enter { service cmd op } { + # Parse the command + set procName [uplevel 1 namespace origin [lindex $cmd 0]] + set args [lrange $cmd 1 end] + + # Display the message prefix + set callerLvl [expr {[::info level] - 1}] + set calledLvl [::info level] + + lappend message "proc" $procName + lappend message "level" $calledLvl + lappend message "script" [uplevel ::info script] + + # Display the caller information + set caller "" + if {$callerLvl >= 1} { + # Display the name of the caller proc w/prepended namespace + catch { + set callerProcName [lindex [::info level $callerLvl] 0] + set caller [uplevel 2 namespace origin $callerProcName] + } + } + + lappend message "caller" $caller + + # Display the argument names and values + set argSpec [uplevel 1 ::info args $procName] + set argList "" + if {[llength $argSpec]} { + foreach argName $argSpec { + lappend argList $argName + + if {$argName == "args"} { + lappend argList $args + break + } else { + lappend argList [lindex $args 0] + set args [lrange $args 1 end] + } + } + } + + lappend message "procargs" $argList + set message [list $op $message] + + ::logger::tree::${service}::tracecmd $message +} + +# This procedure is invoked upon leaving into a procedure being traced +# via "logger::trace add" when tracing is enabled via "logger::trace on" +# to log information about the result of the procedure call. + +proc ::logger::_trace_leave { service cmd status rc op } { + variable RETURN_CODES + + # Parse the command + set procName [uplevel 1 namespace origin [lindex $cmd 0]] + + # Gather the caller information + set callerLvl [expr {[::info level] - 1}] + set calledLvl [::info level] + + lappend message "proc" $procName "level" $calledLvl + lappend message "script" [uplevel ::info script] + + # Get the name of the proc being returned to w/prepended namespace + set caller "" + catch { + set callerProcName [lindex [::info level $callerLvl] 0] + set caller [uplevel 2 namespace origin $callerProcName] + } + + lappend message "caller" $caller + + # Convert the return code from numeric to verbal + + if {$status < [llength $RETURN_CODES]} { + set status [lindex $RETURN_CODES $status] + } + + lappend message "status" $status + lappend message "result" $rc + + # Display the leave message + + set message [list $op $message] + ::logger::tree::${service}::tracecmd $message + + return 1 +} + diff --git a/src/bootsupport/modules/natsort-0.1.1.6.tm b/src/bootsupport/modules/natsort-0.1.1.6.tm index 1d91b53f..7f7c33cd 100644 --- a/src/bootsupport/modules/natsort-0.1.1.6.tm +++ b/src/bootsupport/modules/natsort-0.1.1.6.tm @@ -5,8 +5,9 @@ package require flagfilter namespace import ::flagfilter::check_flags namespace eval natsort { + #REVIEW - determine and document the purpose of scriptdir being added to tm path proc scriptdir {} { - set possibly_linked_script [file dirname [file normalize [file join [info script] ...]]] + set possibly_linked_script [file dirname [file normalize [file join [info script] __dummy__]]] if {[file isdirectory $possibly_linked_script]} { return $possibly_linked_script } else { @@ -14,7 +15,11 @@ namespace eval natsort { } } if {![interp issafe]} { - tcl::tm::add [scriptdir] + set sdir [scriptdir] + #puts stderr "natsort tcl::tm::add $sdir" + if {$sdir ni [tcl::tm::list]} { + catch {tcl::tm::add $sdir} + } } } @@ -36,6 +41,7 @@ namespace eval natsort { } else { puts stderr "|>natsort_call_err> unable to interpret 2nd argument to do_error: '$then' should be one of '$levels' or 'exit '" } + flush stderr if {$::tcl_interactive} { #may not always be desirable - but assumed to be more useful not to exit despite request, to aid in debugging if {[string tolower $type] eq "exit"} { @@ -43,6 +49,7 @@ namespace eval natsort { if {![string is digit -strict $code]} { puts stderr "|>natsort_call_err> unable to interpret 2nd argument to do_error: '$then' should be: 'exit '" } + flush stderr } return -code error $msg } else { @@ -1422,6 +1429,9 @@ namespace eval natsort { proc called_directly_namematch {} { global argv0 + if {[info script] eq ""} { + return 0 + } #see https://wiki.tcl-lang.org/page/main+script #trailing ... let's us resolve symlinks in last component of the path (could be something else like ___ but ... seems unlikely to collide with anything in the filesystem) if {[info exists argv0] @@ -1440,12 +1450,18 @@ namespace eval natsort { #Review issues around comparing names vs using inodes (esp with respect to samba shares) proc called_directly_inodematch {} { global argv0 + if {[info exists argv0] - && [file exists [info script]] && [file exists $argv0]} { + && [file exists [info script]] && [file exists $argv0]} { file stat $argv0 argv0Info file stat [info script] scriptInfo - expr {$argv0Info(dev) == $scriptInfo(dev) - && $argv0Info(ino) == $scriptInfo(ino)} + if {$argv0Info(ino) == 0 || $scriptInfo(ino) == 0 || $argv0Info(dev) == 0 || $scriptInfo(dev) == 0} { + #vfs? + #e.g //zipfs:/ + return 0 + } + return [expr {$argv0Info(dev) == $scriptInfo(dev) + && $argv0Info(ino) == $scriptInfo(ino)}] } else { return 0 } @@ -1460,6 +1476,11 @@ namespace eval natsort { #-- choose a policy and leave the others commented. #set is_called_directly $is_namematch #set is_called_directly $is_inodematch + + #puts "NATSORT: called_directly_namematch - $is_namematch" + #puts "NATSORT: called_directly_inodematch - $is_inodematch" + #flush stdout + set is_called_directly [expr {$is_namematch || $is_inodematch}] #set is_called_directly [expr {$is_namematch && $is_inodematch}] ### @@ -1921,6 +1942,8 @@ namespace eval natsort { #set args [check_flags -caller test1 -defaults [list -collate nocase -algorithm sort -topchars "\uFFFF" -winlike 0 -debug 0 -stacktrace 0 -showsplits 0] -required {all} -extras {none} -commandprocessors {{-cmd -default help} {-cmd -cmdarg1 -default "."} {-cmd -cmdarg2 -default j}} -values $::argv ] #set args [check_flags -caller test1 -defaults [list -collate nocase -algorithm sort -topchars "\uFFFF" -winlike 0 -debug 0 -stacktrace 0 -showsplits 0] -required {all} -extras {none} -commandprocessors {ls {ls lsdir -default "\uFFFF"}} -values $::argv ] + puts stderr "natsort directcall exit" + flush stderr exit 0 if {$::argc} { diff --git a/src/bootsupport/modules/overtype-1.6.5.tm b/src/bootsupport/modules/overtype-1.6.5.tm index 143794fb..f7e4c1a5 100644 --- a/src/bootsupport/modules/overtype-1.6.5.tm +++ b/src/bootsupport/modules/overtype-1.6.5.tm @@ -163,7 +163,7 @@ proc overtype::string_columns {text} { tcl::namespace::eval overtype::priv { } -#could return larger than colwidth +#could return larger than renderwidth proc _get_row_append_column {row} { upvar outputlines outputlines set idx [expr {$row -1}] @@ -171,14 +171,14 @@ proc _get_row_append_column {row} { return 1 } else { upvar opt_overflow opt_overflow - upvar colwidth colwidth + upvar renderwidth renderwidth set existinglen [punk::ansi::printing_length [lindex $outputlines $idx]] set endpos [expr {$existinglen +1}] if {$opt_overflow} { return $endpos } else { - if {$endpos > $colwidth} { - return $colwidth + 1 + if {$endpos > $renderwidth} { + return $renderwidth + 1 } else { return $endpos } @@ -213,7 +213,20 @@ tcl::namespace::eval overtype { if {[llength $args] < 2} { error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} } - lassign [lrange $args end-1 end] underblock overblock + set optargs [lrange $args 0 end-2] + if {[llength $optargs] % 2 == 0} { + lassign [lrange $args end-1 end] underblock overblock + set argsflags [lrange $args 0 end-2] + } else { + set optargs [lrange $args 0 end-1] + if {[llength $optargs] %2 == 0} { + set overblock [lindex $args end] + set underblock "" + set argsflags [lrange $args 0 end-1] + } else { + error "renderspace expects opt-val pairs followed by: or just " + } + } set opts [tcl::dict::create\ -bias ignored\ -width \uFFEF\ @@ -230,12 +243,15 @@ tcl::namespace::eval overtype { -exposed2 \uFFFD\ -experimental 0\ -looplimit \uFFEF\ + -crm_mode 0\ + -reverse_mode 0\ ] #-ellipsis args not used if -wrap is true - set argsflags [lrange $args 0 end-2] foreach {k v} $argsflags { switch -- $k { - -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental { + -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines + - -transparent - -exposed1 - -exposed2 - -experimental + - -reverse_mode - -crm_mode { tcl::dict::set opts $k $v } default { @@ -261,6 +277,8 @@ tcl::namespace::eval overtype { set opt_exposed1 [tcl::dict::get $opts -exposed1] ;#widechar_exposed_left - todo set opt_exposed2 [tcl::dict::get $opts -exposed2] ;#widechar_exposed_right - todo # -- --- --- --- --- --- + set opt_crm_mode [tcl::dict::get $opts -crm_mode] + set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] # ---------------------------- # -experimental dev flag to set flags etc @@ -295,9 +313,10 @@ tcl::namespace::eval overtype { # ---------------------------- #modes - set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l - set autowrap_mode $opt_wrap - set reverse_mode 0 + set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l + set autowrap_mode $opt_wrap + set reverse_mode $opt_reverse_mode + set crm_mode $opt_crm_mode set underblock [tcl::string::map {\r\n \n} $underblock] @@ -307,33 +326,35 @@ tcl::namespace::eval overtype { #set underlines [split $underblock \n] #underblock is a 'rendered' block - so width height make sense - #colwidth & colheight were originally named with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. - #The naming is now confusing. It should be something like renderwidth renderheight ?? review + #only non-cursor affecting and non-width occupying ANSI codes should be present. + #ie SGR codes and perhaps things such as PM - although generally those should have been pushed to the application already + #renderwidth & renderheight were originally used with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. if {$opt_width eq "\uFFEF" || $opt_height eq "\uFFEF"} { - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } if {$opt_height ne "\uFFEF"} { - set colheight $opt_height + set renderheight $opt_height } } else { - set colwidth $opt_width - set colheight $opt_height + set renderwidth $opt_width + set renderheight $opt_height } # -- --- --- --- #REVIEW - do we need ansi resets in the underblock? if {$underblock eq ""} { - set underlines [lrepeat $colheight ""] + set underlines [lrepeat $renderheight ""] } else { + set underblock [textblock::join_basic -- $underblock] ;#ensure properly rendered - ansi per-line resets & replays set underlines [split $underblock \n] } #if {$underblock eq ""} { # set blank "\x1b\[0m\x1b\[0m" # #set underlines [list "\x1b\[0m\x1b\[0m"] - # set underlines [lrepeat $colheight $blank] + # set underlines [lrepeat $renderheight $blank] #} else { # #lines_as_list -ansiresets 1 will do nothing if -ansiresets 1 isn't specified - REVIEW # set underlines [lines_as_list -ansiresets 1 $underblock] @@ -341,7 +362,7 @@ tcl::namespace::eval overtype { # -- --- --- --- #todo - reconsider the 'line' as the natural chunking mechanism for the overlay. - #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth + #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output renderwidth #In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time. #(in cases where there are interline moves or cursor jumps anyway) #This works - but doesn't seem efficient. @@ -409,7 +430,7 @@ tcl::namespace::eval overtype { set replay_codes_underlay [tcl::dict::create 1 ""] #lappend replay_codes_overlay "" - set replay_codes_overlay "" + set replay_codes_overlay "[punk::ansi::a]" set unapplied "" set cursor_saved_position [tcl::dict::create] set cursor_saved_attributes "" @@ -452,14 +473,25 @@ tcl::namespace::eval overtype { } #review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary - #but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l - set LASTCALL [list -info 1 -insert_mode $insert_mode -autowrap_mode $autowrap_mode -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] + set LASTCALL [list -info 1\ + -insert_mode $insert_mode\ + -crm_mode $crm_mode\ + -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -transparent $opt_transparent\ + -width $renderwidth\ + -exposed1 $opt_exposed1\ + -exposed2 $opt_exposed2\ + -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] set rinfo [renderline -experimental $opt_experimental\ -info 1\ + -crm_mode $crm_mode\ -insert_mode $insert_mode\ - -cursor_restore_attributes $cursor_saved_attributes\ -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -cursor_restore_attributes $cursor_saved_attributes\ -transparent $opt_transparent\ - -width $colwidth\ + -width $renderwidth\ -exposed1 $opt_exposed1\ -exposed2 $opt_exposed2\ -overflow $opt_overflow\ @@ -471,7 +503,10 @@ tcl::namespace::eval overtype { set instruction [tcl::dict::get $rinfo instruction] set insert_mode [tcl::dict::get $rinfo insert_mode] set autowrap_mode [tcl::dict::get $rinfo autowrap_mode] ;# - #set reverse_mode [tcl::dict::get $rinfo reverse_mode];#how to support in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + set reverse_mode [tcl::dict::get $rinfo reverse_mode] + #how to support reverse_mode in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + # - review - the answer is probably that we don't need to - it is set/reset only during application of overtext + set crm_mode [tcl::dict::get $rinfo crm_mode] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] set overflow_right_column [tcl::dict::get $rinfo overflow_right_column] @@ -486,7 +521,36 @@ tcl::namespace::eval overtype { set insert_lines_below [tcl::dict::get $rinfo insert_lines_below] tcl::dict::set replay_codes_underlay [expr {$renderedrow+1}] [tcl::dict::get $rinfo replay_codes_underlay] #lset replay_codes_overlay [expr $overidx+1] [tcl::dict::get $rinfo replay_codes_overlay] - set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + if {0 && $reverse_mode} { + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + #review + #JMN3 + set existing_reverse_state 0 + #split_codes_single is single esc sequence - but could have multiple sgr codes within one esc sequence + #e.g \x1b\[0;31;7m has a reset,colour red and reverse + set codeinfo [punk::ansi::codetype::sgr_merge [list $replay_codes_overlay] -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + } @@ -520,7 +584,7 @@ tcl::namespace::eval overtype { incr row if {$data_mode} { set col [_get_row_append_column $row] - if {$col > $colwidth} { + if {$col > $renderwidth} { } } else { @@ -563,10 +627,10 @@ tcl::namespace::eval overtype { #we need renderline to return the number of the maximum column filled (or min if we ever do r-to-l) set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -601,10 +665,10 @@ tcl::namespace::eval overtype { } set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -640,9 +704,9 @@ tcl::namespace::eval overtype { puts stdout ">>>[a+ red bold]overflow_right during restore_cursor[a]" - set sub_info [overtype::renderline -info 1 -width $colwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] + set sub_info [overtype::renderline -info 1 -width $renderwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] set foldline [tcl::dict::get $sub_info result] - set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed.. + set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed..? set autowrap_mode [tcl::dict::get $sub_info autowrap_mode] ;#nor this.. linsert outputlines $renderedrow $foldline #review - row & col set by restore - but not if there was no save.. @@ -740,7 +804,7 @@ tcl::namespace::eval overtype { } } lf_overflow { - #linefeed after colwidth e.g at column 81 for an 80 col width + #linefeed after renderwidth e.g at column 81 for an 80 col width #we may also have other control sequences that came after col 80 e.g cursor save if 0 { @@ -833,10 +897,10 @@ tcl::namespace::eval overtype { } else { set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } } @@ -845,12 +909,12 @@ tcl::namespace::eval overtype { #doesn't seem to be used by fruit.ans testfile #used by dzds.ans #note that cursor_forward may move deep into the next line - or even span multiple lines !TODO - set c $colwidth + set c $renderwidth set r $post_render_row - if {$post_render_col > $colwidth} { + if {$post_render_col > $renderwidth} { set i $c while {$i <= $post_render_col} { - if {$c == $colwidth+1} { + if {$c == $renderwidth+1} { incr r if {$opt_appendlines} { if {$r < [llength $outputlines]} { @@ -874,7 +938,7 @@ tcl::namespace::eval overtype { set col $c } wrapmovebackward { - set c $colwidth + set c $renderwidth set r $post_render_row if {$post_render_col < 1} { set c 1 @@ -883,7 +947,7 @@ tcl::namespace::eval overtype { if {$c == 0} { if {$r > 1} { incr r -1 - set c $colwidth + set c $renderwidth } else { #leave r at 1 set c 1 #testfile besthpav.ans first line top left border alignment @@ -941,7 +1005,7 @@ tcl::namespace::eval overtype { #2nd half of grapheme would overflow - treggering grapheme is returned in unapplied. There may also be overflow_right from earlier inserts #todo - consider various options .. re-render a single trailing space or placeholder on same output line, etc if {$autowrap_mode} { - if {$colwidth < 2} { + if {$renderwidth < 2} { #edge case of rendering to a single column output - any 2w char will just cause a loop if we don't substitute with something, or drop the character set idx 0 set triggering_grapheme_index -1 @@ -960,7 +1024,7 @@ tcl::namespace::eval overtype { } else { set overflow_handled 1 #handled by dropping entire overflow if any - if {$colwidth < 2} { + if {$renderwidth < 2} { set idx 0 set triggering_grapheme_index -1 foreach u $unapplied_list { @@ -1141,12 +1205,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + #set renderwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] - #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {$colwidth - $overblock_width}] + set under_exposed_max [expr {$renderwidth - $overblock_width}] if {$under_exposed_max > 0} { #background block is wider if {$under_exposed_max % 2 == 0} { @@ -1176,14 +1239,14 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] set undertext "$undertext[string repeat { } $udiff]" } set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] #review - right-to-left langs should elide on left! - extra option required if {$overflowlength > 0} { @@ -1196,8 +1259,8 @@ tcl::namespace::eval overtype { #overlay line data is wider - trim if overflow not specified in opts - and overtype an ellipsis at right if it was specified if {![tcl::dict::get $opts -overflow]} { - #lappend outputlines [tcl::string::range $overtext 0 [expr {$colwidth - 1}]] - #set overtext [tcl::string::range $overtext 0 $colwidth-1 ] + #lappend outputlines [tcl::string::range $overtext 0 [expr {$renderwidth - 1}]] + #set overtext [tcl::string::range $overtext 0 $renderwidth-1 ] if {$opt_ellipsis} { set show_ellipsis 1 if {!$opt_ellipsiswhitespace} { @@ -1286,12 +1349,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] set left_exposed $under_exposed_max @@ -1307,8 +1369,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1336,10 +1398,17 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline\ + -info 1\ + -insert_mode 0\ + -transparent $opt_transparent\ + -exposed1 $opt_exposed1 -exposed2 $opt_exposed2\ + -overflow $opt_overflow\ + -startcolumn [expr {1 + $startoffset}]\ + $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] if {!$opt_overflow} { @@ -1433,12 +1502,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] switch -- $opt_blockalign { left { @@ -1484,8 +1552,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1513,7 +1581,7 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] @@ -1566,6 +1634,7 @@ tcl::namespace::eval overtype { #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #puts stderr "--> [ansistring VIEW -lf 1 -nul 1 $rinfo] <--" set overflow_right [tcl::dict::get $rinfo overflow_right] set unapplied [tcl::dict::get $rinfo unapplied] lappend outputlines [tcl::dict::get $rinfo result] @@ -1629,6 +1698,7 @@ tcl::namespace::eval overtype { -cursor_column 1\ -cursor_row ""\ -insert_mode 1\ + -crm_mode 0\ -autowrap_mode 1\ -reverse_mode 0\ -info 0\ @@ -1649,7 +1719,9 @@ tcl::namespace::eval overtype { set argsflags [lrange $args 0 end-2] tcl::dict::for {k v} $argsflags { switch -- $k { - -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -autowrap_mode - -reverse_mode - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { + -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row + - -crm_mode - -insert_mode - -autowrap_mode - -reverse_mode + - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { tcl::dict::set opts $k $v } default { @@ -1676,6 +1748,7 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_autowrap_mode [tcl::dict::get $opts -autowrap_mode] ;#DECAWM - char or movement can go beyond leftmost/rightmost col to prev/next line set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] ;#DECSNM + set opt_crm_mode [tcl::dict::get $opts -crm_mode];# CRM - show control character mode # -- --- --- --- --- --- --- --- --- --- --- --- set temp_cursor_saved [tcl::dict::get $opts -cursor_restore_attributes] @@ -1721,6 +1794,10 @@ tcl::namespace::eval overtype { set cursor_row $opt_row_context } + set insert_mode $opt_insert_mode ;#default 1 + set autowrap_mode $opt_autowrap_mode ;#default 1 + set crm_mode $opt_crm_mode ;#default 0 (Show Control Character mode) + set reverse_mode $opt_reverse_mode #----- # @@ -1768,6 +1845,7 @@ tcl::namespace::eval overtype { } set understacks [list] set understacks_gx [list] + set pm_list [list] set i_u -1 ;#underlay may legitimately be empty set undercols [list] @@ -1834,6 +1912,7 @@ tcl::namespace::eval overtype { #underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc + #keep any remaining PMs in place if {$code ne ""} { set c1c2 [tcl::string::range $code 0 1] @@ -1841,6 +1920,8 @@ tcl::namespace::eval overtype { \x1b\[ 7CSI\ \x9b 8CSI\ \x1b\( 7GFX\ + \x1b^ 7PMX\ + \x1bX 7SOS\ ] $c1c2] 0 3];# leadernorm is 1st 2 chars mapped to normalised indicator - or is original 2 chars switch -- $leadernorm { @@ -1875,6 +1956,26 @@ tcl::namespace::eval overtype { } } } + 7PMX - 7SOS { + #we can have PMs or SOS (start of string) in the underlay - though mostly the PMs should have been processed.. + #attach the PM/SOS (entire ANSI sequence) to the previous grapheme! + #It should not affect the size - but terminal display may get thrown out if terminal doesn't support them. + + #note that there may in theory already be ANSI stored - we don't assume it was a pure grapheme string + set graphemeplus [lindex $undercols end] + if {$graphemeplus ne "\0"} { + append graphemeplus $code + } else { + set graphemeplus $code + } + lset undercols end $graphemeplus + #The grapheme_width_cached function will be called on this later - and doesn't account for ansi. + #we need to manually cache the item with it's proper width + variable grapheme_widths + #stripped and plus version keys pointing to same length + dict set grapheme_widths $graphemeplus [grapheme_width_cached [::punk::ansi::ansistrip $graphemeplus]] + + } default { } @@ -1937,9 +2038,9 @@ tcl::namespace::eval overtype { } if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } else { - set colwidth [llength $undercols] + set renderwidth [llength $undercols] } @@ -2017,12 +2118,30 @@ tcl::namespace::eval overtype { } append pt_overchars $pt #will get empty pt between adjacent codes - foreach grapheme [punk::char::grapheme_split $pt] { - lappend overstacks $o_codestack - lappend overstacks_gx $o_gxstack - incr i_o - lappend overlay_grapheme_control_list [list g $grapheme] - lappend overlay_grapheme_control_stacks $o_codestack + if {!$crm_mode} { + foreach grapheme [punk::char::grapheme_split $pt] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } else { + foreach grapheme_original [punk::char::grapheme_split $pt] { + set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original] + foreach grapheme [punk::char::grapheme_split $pt_crm] { + if {$grapheme eq "\n"} { + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"] + } else { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + } } #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc @@ -2030,40 +2149,91 @@ tcl::namespace::eval overtype { # that pure resets are fairly common - more so than leading resets with other info # that non-sgr codes are not that common, so ok to check for resets before verifying it is actually SGR at all. if {$code ne ""} { - lappend overlay_grapheme_control_stacks $o_codestack - #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) - if {[punk::ansi::codetype::is_sgr_reset $code]} { - set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set o_codestack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #basic simplification first - remove straight dupes - set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars - set o_codestack [lremove $o_codestack {*}$dup_posns] - lappend o_codestack $code - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[regexp {\x1b7|\x1b\[s} $code]} { - #experiment - #cursor_save - for the replays review. - #jmn - #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] - lappend overlay_grapheme_control_list [list other $code] - } elseif {[regexp {\x1b8|\x1b\[u} $code]} { - #experiment - #cursor_restore - for the replays - set o_codestack [list $temp_cursor_saved] - lappend overlay_grapheme_control_list [list other $code] + #we need to immediately set crm_mode here if \x1b\[3h received + if {$code eq "\x1b\[3h"} { + set crm_mode 1 + } elseif {$code eq "\x1b\[3l"} { + set crm_mode 0 + } + #else crm_mode could be set either way from options + if {$crm_mode && $code ne "\x1b\[00001E"} { + #treat the code as type 'g' like above - only allow through codes to reset mode REVIEW for now just \x1b\[3l ? + #we need to somehow convert further \n in the graphical rep to an instruction for newline that will bypass further crm_mode processing or we would loop. + set code_as_pt [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $code] + #split using standard split for first foreach loop - grapheme based split when processing 2nd foreach loop + set chars [split $code_as_pt ""] + set codeparts [list] ;#list of 2-el lists each element {crmcontrol } or {g } + foreach c $chars { + if {$c eq "\n"} { + #use CNL (cursor next line) \x1b\[00001E ;#leading zeroes ok for this processor - used as debugging aid to distinguish + lappend codeparts [list crmcontrol "\x1b\[00001E"] + } else { + if {[llength $codeparts] > 0 && [lindex $codeparts end 0] eq "g"} { + set existing [lindex $codeparts end 1] + lset codeparts end [list g [string cat $existing $c]] + } else { + lappend codeparts [list g $c] + } + } + } + + set partidx 0 + foreach record $codeparts { + lassign $record rtype rval + switch -exact -- $rtype { + g { + append pt_overchars $rval + foreach grapheme [punk::char::grapheme_split $rval] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + crmcontrol { + #leave o_codestack + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol $rval] + } + } + } } else { - if {[punk::ansi::codetype::is_gx_open $code]} { - set o_gxstack [list "gx0_on"] - lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } elseif {[punk::ansi::codetype::is_gx_close $code]} { - set o_gxstack [list] - lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } else { + lappend overlay_grapheme_control_stacks $o_codestack + #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) + if {[punk::ansi::codetype::is_sgr_reset $code]} { + set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set o_codestack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #basic simplification first - remove straight dupes + set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars + set o_codestack [lremove $o_codestack {*}$dup_posns] + lappend o_codestack $code + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[regexp {\x1b7|\x1b\[s} $code]} { + #experiment + #cursor_save - for the replays review. + #jmn + #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] + lappend overlay_grapheme_control_list [list other $code] + } elseif {[regexp {\x1b8|\x1b\[u} $code]} { + #experiment + #cursor_restore - for the replays + set o_codestack [list $temp_cursor_saved] lappend overlay_grapheme_control_list [list other $code] + } else { + if {[punk::ansi::codetype::is_gx_open $code]} { + set o_gxstack [list "gx0_on"] + lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } elseif {[punk::ansi::codetype::is_gx_close $code]} { + set o_gxstack [list] + lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } else { + lappend overlay_grapheme_control_list [list other $code] + } } } } @@ -2135,9 +2305,6 @@ tcl::namespace::eval overtype { #movements only occur within the overlay range. #an underlay is however not necessary.. e.g #renderline -overflow 1 "" data - #foreach {pt code} $overmap {} - set insert_mode $opt_insert_mode ;#default 1 - set autowrap_mode $opt_autowrap_mode ;#default 1 #set re_mode {\x1b\[\?([0-9]*)(h|l)} ;#e.g DECAWM #set re_col_move {\x1b\[([0-9]*)(C|D|G)$} @@ -2163,13 +2330,28 @@ tcl::namespace::eval overtype { switch -- $type { g { set ch $item + #crm_mode affects both graphic and control + if {$crm_mode} { + set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $ch] + set chars [string map [list \n "\x1b\[00001E"] $chars] + if {[llength [split $chars ""]] > 1} { + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + #incr idx_over + break + } else { + set ch $chars + } + } incr idx_over; #idx_over (until unapplied reached anyway) is per *grapheme* in the overlay - not per col. if {($idx < ($opt_colstart -1))} { incr idx [grapheme_width_cached $ch] continue } #set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our active data width - set within_undercols [expr {$idx <= $colwidth-1}] + set within_undercols [expr {$idx <= $renderwidth-1}] #https://www.enigma.com/resources/blog/the-secret-world-of-newline-characters #\x85 NEL in the c1 control set is treated by some terminal emulators (e.g Hyper) as a newline, @@ -2311,6 +2493,7 @@ tcl::namespace::eval overtype { } else { #todo - punk::char::char_width set g [lindex $outcols $idx] + #JMN set uwidth [grapheme_width_cached $g] if {[lindex $outcols $idx] eq ""} { #2nd col of 2-wide char in underlay @@ -2485,13 +2668,29 @@ tcl::namespace::eval overtype { } - other { + other - crmcontrol { + if {$crm_mode && $type ne "crmcontrol" && $item ne "\x1b\[00001E"} { + if {$item eq "\x1b\[3l"} { + set crm_mode 0 + } else { + #When our initial overlay split was done - we weren't in crm_mode - so there are codes that weren't mapped to unicode control character representations + #set within_undercols [expr {$idx <= $renderwidth-1}] + #set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $item] + set chars [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $item] + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + + break + } + } + #todo - consider CSI s DECSLRM vs ansi.sys \x1b\[s - we need \x1b\[s for oldschool ansi art - but may have to enable only for that. - #we should probably therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore + #we should possibly therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore? set code [tcl::string::map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $item] #since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied' - set matchinfo [list] #remap of DEC cursor_save/cursor_restore from ESC sequence to equivalent CSI #probably not ideal - consider putting cursor_save/cursor_restore in functions so they can be called from the appropriate switch branch instead of using this mapping @@ -2501,7 +2700,7 @@ tcl::namespace::eval overtype { set c1c2c3 [tcl::string::range $code 0 2] #set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)} #tcl 8.7 - faster to use inline list than to store it in a local var outside of loop. - #(surprising - but presumably ) + #(somewhat surprising) set leadernorm [tcl::string::range [tcl::string::map [list\ \x1b\[< 1006\ \x1b\[ 7CSI\ @@ -2509,7 +2708,7 @@ tcl::namespace::eval overtype { \x1b\] 7OSC\ \x9d 8OSC\ \x1b 7ESC\ - ] $c1c2c3] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars + ] $c1c2c3] 0 3] ;#leadernorm is 1st 1,2 or 3 chars mapped to 4char normalised indicator - or is original first chars (1,2 or 3 len) #we leave the tail of the code unmapped for now switch -- $leadernorm { @@ -2528,7 +2727,10 @@ tcl::namespace::eval overtype { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } default { + puts stderr "Sequence detected as ANSI, but not handled in leadernorm switch. code: [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" #we haven't made a mapping for this + #could in theory be 1,2 or 3 in len + #although we shouldn't be getting here if the regexp for ansi codes is kept in sync with our switch branches set codenorm $code } } @@ -2551,44 +2753,44 @@ tcl::namespace::eval overtype { {7CSI} - {8CSI} { set param [tcl::string::range $codenorm 4 end-1] #puts stdout "--> CSI [tcl::string::index $leadernorm 0] bit param:$param" - switch -- [tcl::string::index $codenorm end] { - D { - #Col move - #puts stdout "<-back" - #cursor back - #left-arrow/move-back when ltr mode + set code_end [tcl::string::index $codenorm end] ;#used for e.g h|l set/unset mode + switch -exact -- $code_end { + A { + #Row move - up + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set num $param if {$num eq ""} {set num 1} + incr cursor_row -$num - set version 2 - if {$version eq "2"} { - #todo - startcolumn offset! - if {$cursor_column - $num >= 1} { - incr idx -$num - incr cursor_column -$num - } else { - if {!$autowrap_mode} { - set cursor_column 1 - set idx 0 - } else { - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - incr cursor_column -$num - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction wrapmovebackward - break - } - } - } else { - incr idx -$num - incr cursor_column -$num - if {$idx < $opt_colstart-1} { - #wrap to previous line and position cursor at end of data - set idx [expr {$opt_colstart-1}] - set cursor_column $opt_colstart - } + if {$cursor_row < 1} { + set cursor_row 1 } + + #ensure rest of *overlay* is emitted to remainder + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction up + #retain cursor_column + break + } + B { + #CUD - Cursor Down + #Row move - down + set num $param + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #move down + if {$num eq ""} {set num 1} + incr cursor_row $num + + + incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction down + #retain cursor_column + break } C { + #CUF - Cursor Forward #Col move #puts stdout "->forward" #todo - consider right-to-left cursor mode (e.g Hebrew).. some day. @@ -2692,80 +2894,215 @@ tcl::namespace::eval overtype { } } } - G { + D { #Col move - #move absolute column - #adjust to colstart - as column 1 is within overlay - #??? - set idx [expr {$param + $opt_colstart -1}] - set cursor_column $param - error "renderline absolute col move ESC G unimplemented" - } - A { - #Row move - up - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #puts stdout "<-back" + #cursor back + #left-arrow/move-back when ltr mode set num $param if {$num eq ""} {set num 1} - incr cursor_row -$num - if {$cursor_row < 1} { - set cursor_row 1 + set version 2 + if {$version eq "2"} { + #todo - startcolumn offset! + if {$cursor_column - $num >= 1} { + incr idx -$num + incr cursor_column -$num + } else { + if {!$autowrap_mode} { + set cursor_column 1 + set idx 0 + } else { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr cursor_column -$num + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction wrapmovebackward + break + } + } + } else { + incr idx -$num + incr cursor_column -$num + if {$idx < $opt_colstart-1} { + #wrap to previous line and position cursor at end of data + set idx [expr {$opt_colstart-1}] + set cursor_column $opt_colstart + } } - - #ensure rest of *overlay* is emitted to remainder + } + E { + #CNL - Cursor Next Line + if {$param eq ""} { + set downmove 1 + } else { + set downmove [expr {$param}] + } + puts stderr "renderline CNL down-by-$downmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row + $downmove}] + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction up - #retain cursor_column - break + set instruction move + break + } - B { - #Row move - down - set num $param + F { + #CPL - Cursor Previous Line + if {$param eq ""} { + set upmove 1 + } else { + set upmove [expr {$param}] + } + puts stderr "renderline CPL up-by-$upmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row -$upmove}] + if {$cursor_row < 1} { + set cursor_row 1 + } + set idx [expr {$cursor_column - 1}] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #move down - if {$num eq ""} {set num 1} - incr cursor_row $num - - - incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction down - #retain cursor_column - break + set instruction move + break + + } + G { + #CHA - Cursor Horizontal Absolute (move to absolute column no) + if {$param eq ""} { + set targetcol 1 + } else { + set targetcol $param + if {![string is integer -strict $targetcol]} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Unrecognised parameter '$param'" + } + set targetcol [expr {$param}] + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$targetcol > $max} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Param '$param' > max: $max" + set targetcol $max + } + } + #adjust to colstart - as column 1 is within overlay + #??? REVIEW + set idx [expr {($targetcol -1) + $opt_colstart -1}] + + + set cursor_column $targetcol + #puts stderr "renderline absolute col move ESC G (TEST)" } H - f { - #$re_both_move - lassign [split $param {;}] row col - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #lassign $matchinfo _match row col + #CSI n;m H - CUP - Cursor Position - if {$col eq ""} {set col 1} - set max [llength $outcols] - if {$overflow_idx == -1} { - incr max - } - if {$col > $max} { - set cursor_column $max + #CSI n;m f - HVP - Horizontal Vertical Position REVIEW - same as CUP with differences (what?) in some terminal modes + # - 'counts as effector format function (like CR or LF) rather than an editor function (like CUD or CNL)' + # - REVIEW + #see Annex A at: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf + + #test e.g ansicat face_2.ans + #$re_both_move + lassign [split $param {;}] paramrow paramcol + #missing defaults to 1 + #CSI ;5H = CSI 1;5H -> row 1 col 5 + #CSI 17;H = CSI 17H = CSI 17;1H -> row 17 col 1 + + if {$paramcol eq ""} {set paramcol 1} + if {$paramrow eq ""} {set paramrow 1} + if {![string is integer -strict $paramcol] || ![string is integer -strict $paramrow]} { + puts stderr "renderline CUP (CSI H) unrecognised param $param" + #ignore? } else { - set cursor_column $col + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$paramcol > $max} { + set target_column $max + } else { + set target_column [expr {$paramcol}] + } + + + if {$paramrow < 1} { + puts stderr "renderline CUP (CSI H) bad row target 0. Assuming 1" + set target_row 1 + } else { + set target_row [expr {$paramrow}] + } + if {$target_row == $cursor_row} { + #col move only - no need for break and move + #puts stderr "renderline CUP col move only to col $target_column param:$param" + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + } else { + set cursor_row $target_row + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } } - set idx [expr {$cursor_column -1}] + } + J { + puts stderr "overtype::renderline ED - ERASE IN DISPLAY (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of screen + } + 1 { + #clear from cursor to beginning of screen + } + 2 { + #clear entire screen + #ansi.sys - move cursor to upper left REVIEW + set cursor_row 1 + set cursor_column 1 + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } + 3 { + #clear entire screen. presumably cursor doesn't move - otherwise it would be same as 2J ? - if {$row eq ""} {set row 1} - set cursor_row $row - if {$cursor_row < 1} { - set cursor_row 1 + } + default { + } } - incr idx_over - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction move - break + } + K { + puts stderr "overtype::renderline EL - ERASE IN LINE (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line + } + 1 { + #clear from cursor to beginning of line + } + 2 { + #clear entire line + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } } X { - puts stderr "X - $param" + puts stderr "overtype::renderline X ECH ERASE CHARACTER - $param" #ECH - erase character if {$param eq "" || $param eq "0"} {set param 1}; #param=count of chars to erase priv::render_erasechar $idx $param @@ -2789,78 +3126,119 @@ tcl::namespace::eval overtype { break } s { - # - todo - make ansi.sys CSI s cursor save only apply for certain cases? - may need to support DECSLRM instead which uses same code - - #$re_cursor_save - #cursor save could come after last column - if {$overflow_idx != -1 && $idx == $overflow_idx} { - #bartman2.ans test file - fixes misalignment at bottom of dialog bubble - #incr cursor_row - #set cursor_column 1 - #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) - set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] - } else { - set cursor_saved_position [list row $cursor_row column $cursor_column] - } - #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. - #we need the SGR and gx overlay codes prior to the cursor_save + #code conflict between ansi emulation and DECSLRM - REVIEW + #ANSISYSSC (when no parameters) - like other terminals - essentially treat same as DECSC + # todo - when parameters - support DECSLRM instead + + if {$param ne ""} { + #DECSLRM - should only be recognised if DECLRMM is set (vertical split screen mode) + lassign [split $param {;} margin_left margin_right + puts stderr "overtype DECSLRM not yet supported - got [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$margin_left eq ""} { + set margin_left 1 + } + set columns_per_page 80 ;#todo - set to 'page width (DECSCPP set columns per page)' - could be 132 or?? + if {$margin_right eq ""} { + set margin_right $columns_per_page + } + puts stderr "DECSLRM margin left: $margin_left margin right: $margin_right" + if {![string is integer -strict $margin_left] || $margin_left < 0} { + puts stderr "DECSLRM invalid margin_left" + } + if {![string is integer -strict $margin_right] || $margin_right < 0} { + puts stderr "DECSLRM invalid margin_right" + } + set scrolling_region_size [expr {$margin_right - $margin_left}] + if {$scrolling_region_size < 2 || $scrolling_region_size > $columns_per_page} { + puts stderr "DECSLRM region size '$scrolling_regsion_size' must be between 1 and $columns_per_page" + } + #todo - #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. - #set sgr_stack [lindex $understacks $idx] - #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) - - set sgr_stack [list] - set gx_stack [list] - - #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. - #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. - - foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { - lassign $gc type code - #types g other sgr gx0 - switch -- $type { - gx0 { - #code is actually a stand-in for the graphics on/off code - not the raw code - #It is either gx0_on or gx0_off - set gx_stack [list $code] - } - sgr { - #code is the raw code - if {[punk::ansi::codetype::is_sgr_reset $code]} { - #jmn - set sgr_stack [list "\x1b\[m"] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set sgr_stack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #often we don't get resets - and codes just pile up. - #as a first step to simplifying - at least remove earlier straight up dupes - set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) - set sgr_stack [lremove $sgr_stack {*}$dup_posns] - lappend sgr_stack $code + + } else { + #DECSC + #//notes on expected behaviour: + #DECSC - saves following items in terminal's memory + #cursor position + #character attributes set by the SGR command + #character sets (G0,G1,G2 or G3) currently in GL and GR + #Wrap flag (autowrap or no autowrap) + #State of origin mode (DECOM) + #selective erase attribute + #any single shift 2 (SS2) or single shift 3(SSD) functions sent + + #$re_cursor_save + #cursor save could come after last column + if {$overflow_idx != -1 && $idx == $overflow_idx} { + #bartman2.ans test file - fixes misalignment at bottom of dialog bubble + #incr cursor_row + #set cursor_column 1 + #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) + set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] + } else { + set cursor_saved_position [list row $cursor_row column $cursor_column] + } + #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. + #we need the SGR and gx overlay codes prior to the cursor_save + + #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. + #set sgr_stack [lindex $understacks $idx] + #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) + + set sgr_stack [list] + set gx_stack [list] + + #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. + #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. + + foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { + lassign $gc type code + #types g other sgr gx0 + switch -- $type { + gx0 { + #code is actually a stand-in for the graphics on/off code - not the raw code + #It is either gx0_on or gx0_off + set gx_stack [list $code] + } + sgr { + #code is the raw code + if {[punk::ansi::codetype::is_sgr_reset $code]} { + #jmn + set sgr_stack [list "\x1b\[m"] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set sgr_stack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #often we don't get resets - and codes just pile up. + #as a first step to simplifying - at least remove earlier straight up dupes + set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) + set sgr_stack [lremove $sgr_stack {*}$dup_posns] + lappend sgr_stack $code + } } } } - } - set cursor_saved_attributes "" - switch -- [lindex $gx_stack 0] { - gx0_on { - append cursor_saved_attributes "\x1b(0" - } - gx0_off { - append cursor_saved_attributes "\x1b(B" + set cursor_saved_attributes "" + switch -- [lindex $gx_stack 0] { + gx0_on { + append cursor_saved_attributes "\x1b(0" + } + gx0_off { + append cursor_saved_attributes "\x1b(B" + } } - } - #append cursor_saved_attributes [join $sgr_stack ""] - append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] + #append cursor_saved_attributes [join $sgr_stack ""] + append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] - #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. + #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. - #don't incr index - or the save will cause cursor to move to the right - #carry on - + #don't incr index - or the save will cause cursor to move to the right + #carry on + } } u { + #ANSISYSRC save cursor (when no parameters) (DECSC) + #$re_cursor_restore #we are going to jump somewhere.. for now we will assume another line, and process accordingly. #The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line) @@ -2903,7 +3281,6 @@ tcl::namespace::eval overtype { } ~ { #$re_vt_sequence - #lassign $matchinfo _match key mod lassign [split $param {;}] key mod #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ @@ -2972,64 +3349,129 @@ tcl::namespace::eval overtype { } h - l { + #set mode unset mode #we are matching only last char to get to this arm - but are there other sequences ending in h|l we need to handle? #$re_mode if first after CSI is "?" #some docs mention ESC=h|l - not seen on windows terminals.. review #e.g https://www2.math.upenn.edu/~kazdan/210/computer/ansi.html - if {[tcl::string::index $codenorm 4] eq "?"} { - set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l - #lassign $matchinfo _match num type - switch -- $num { - 5 { - #DECSNM - reverse video - #How we simulate this to render within a block of text is an open question. - #track all SGR stacks and constantly flip based on the current SGR reverse state? - #It is the job of the calling loop to do this - so at this stage we'll just set the states - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set reverse_mode 1 - } else { - #reset (disable) - set reverse_mode 0 + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? = + switch -exact -- $modegroup { + ? { + set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l + switch -- $num { + 5 { + #DECSNM - reverse video + #How we simulate this to render within a block of text is an open question. + #track all SGR stacks and constantly flip based on the current SGR reverse state? + #It is the job of the calling loop to do this - so at this stage we'll just set the states + + if {$code_end eq "h"} { + #set (enable) + set reverse_mode 1 + } else { + #reset (disable) + set reverse_mode 0 + } + + } + 7 { + #DECAWM autowrap + if {$code_end eq "h"} { + #set (enable) + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } + #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. + if {$idx >= $overflow_idx} { + puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + } else { + #reset (disable) + set autowrap_mode 0 + set overflow_idx -1 + } } + 25 { + if {$code_end eq "h"} { + #visible cursor + } else { + #invisible cursor + + } + } } - 7 { - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set autowrap_mode 1 - if {$opt_width ne "\uFFEF"} { - set overflow_idx $opt_width + } + = { + set num [tcl::string::range $codenorm 5 end-1] ;#param between = and h|l + puts stderr "overtype::renderline CSI=...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + #e.g CSI 4 h + set num [tcl::string::range $codenorm 4 end-1] ;#param before h|l + switch -exact -- $num { + 3 { + puts stderr "CRM MODE $code_end" + #CRM - Show control character mode + # 'No control functions are executed except LF,FF and VT which are represented in the CRM FONT before a CRLF(new line) is executed' + # + #use ansistring VIEW -nul 1 -lf 2 -ff 2 -vt 2 + #https://vt100.net/docs/vt510-rm/CRM.html + if {$code_end eq "h"} { + set crm_mode 1 } else { - #review - this is also the cursor position when adding a char at end of line? - set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + set crm_mode 0 } - #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. - if {$idx >= $overflow_idx} { - puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + 4 { + #IRM - Insert/Replace Mode + if {$code_end eq "h"} { + set insert_mode 1 + } else { + #replace mode + set insert_mode 0 } - } else { - #reset (disable) - set autowrap_mode 0 - set overflow_idx -1 } + default { + puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + } + } + } + } + | { + switch -- [tcl::string::index $codenorm end-1] { + {$} { + #CSI ... $ | DECSCPP set columns per page- (recommended in vt510 docs as preferable to DECCOLM) + #real terminals generally only supported 80/132 + #some other virtuals support any where from 2 to 65,536? + #we will allow arbitrary widths >= 2 .. to some as yet undetermined limit. + #CSI $ | + #empty or 0 param is 80 for compatibility - other numbers > 2 accepted + set page_width -1 ;#flag as unset + if {$param eq ""} { + set page_width 80 + } elseif {[string is integer -strict $param] && $param >=2 0} { + set page_width [expr {$param}] ;#we should allow leading zeros in the number - but lets normalize using expr + } else { + puts stderr "overtype::renderline unacceptable DECSPP value '$param'" } - 25 { - if {$type eq "h"} { - #visible cursor - } else { - #invisible cursor + if {$page_width > 2} { + puts stderr "overtype::renderline DECSCPP - not implemented - but selected width '$page_width' looks ok" + #if cursor already beyond new page_width - will move to right colum - otherwise no cursor movement - } } - } - } else { - puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + puts stderr "overtype::renderline unrecognised CSI code ending in pipe (|) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } } } default { @@ -3038,8 +3480,9 @@ tcl::namespace::eval overtype { } } 7ESC { - #$re_other_single - switch -- [tcl::string::index $codenorm end] { + #re_other_single {\x1b(D|M|E)$} + #also PM \x1b^...(ST) + switch -- [tcl::string::index $codenorm 4] { D { #\x84 #index (IND) @@ -3080,20 +3523,66 @@ tcl::namespace::eval overtype { puts stderr "ESC E unimplemented" } + ^ { + #puts stderr "renderline PM" + #Privacy Message. + if {[string index $code end] eq "\007"} { + set pm_content [string range $code 2 end-1] ;#ST is \007 + } else { + set pm_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #We don't want to render it - but we need to make it available to the application + #see the textblock library in punk, for the exception we make here for single backspace. + #It is unlikely to be encountered as a useful PM - so we hack to pass it through as a fix + #for spacing issues on old terminals which miscalculate the single-width 'Symbols for Legacy Computing' + if {$pm_content eq "\b"} { + #puts stderr "renderline PM sole backspace special handling for \U1FB00 - \U1FBFF" + #esc^\b\007 or esc^\besc\\ + #HACKY pass-through - targeting terminals that both mis-space legacy symbols *and* don't support PMs + #The result is repair of the extra space. If the terminal is a modern one and does support PM - the \b should be hidden anyway. + #If the terminal has the space problem AND does support PMs - then this just won't fix it. + #The fix relies on the symbol-supplier to cooperate by appending esc^\b\esc\\ to the problematic symbols. + + #priv::render_addchar $idx $code [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode + #idx has been incremented after last grapheme added + priv::render_append_to_char [expr {$idx -1}] $code + } + #lappend to a dict element in the result for application-specific processing + lappend pm_list $pm_content + } + N - O { + puts stderr "overtype::renderline single shift command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + P { + puts stderr "overtype::renderline DEVICE CONTROL STRING command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + X { + #SOS + if {[string index $code end] eq "\007"} { + set sos_content [string range $code 2 end-1] ;#ST is \007 + } else { + set sos_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #return in some useful form to the caller + #TODO! + lappend sos_list [list string $sos_content row $cursor_row column $cursor_column] + puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + _ { + #APC Application Program Command + #just warn for now.. + puts stderr "overtype::renderline ESC_ APC command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } default { - puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented codenorm:[ansistring VIEW -lf 1 -vt 1 -nul 1 $codenorm]" } } } + default { + } } - #switch -regexp -matchvar matchinfo -- $code\ - #$re_mode { - #}\ - #default { - # puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" - #} } default { @@ -3275,8 +3764,10 @@ tcl::namespace::eval overtype { overflow_right $overflow_right\ unapplied $unapplied\ unapplied_list $unapplied_list\ - insert_mode $insert_mode\ - autowrap_mode $autowrap_mode\ + insert_mode $insert_mode\ + autowrap_mode $autowrap_mode\ + crm_mode $crm_mode\ + reverse_mode $reverse_mode\ insert_lines_above $insert_lines_above\ insert_lines_below $insert_lines_below\ cursor_saved_position $cursor_saved_position\ @@ -3287,6 +3778,7 @@ tcl::namespace::eval overtype { replay_codes $replay_codes\ replay_codes_underlay $replay_codes_underlay\ replay_codes_overlay $replay_codes_overlay\ + pm_list $pm_list\ ] if {$opt_returnextra == 1} { return $result @@ -3370,8 +3862,9 @@ tcl::namespace::eval overtype::piper { } interp alias "" piper_renderline "" overtype::piper::renderline -#intended for single grapheme - but will work for multiple -#cannot contain ansi or newlines +#intended primarily for single grapheme - but will work for multiple +#WARNING: query CAN contain ansi or newlines - but if cache was not already set manually,the answer will be incorrect! +#We deliberately allow this for PM/SOS attached within a column #(a cache of ansifreestring_width calls - as these are quite regex heavy) proc overtype::grapheme_width_cached {ch} { variable grapheme_widths @@ -3439,6 +3932,7 @@ tcl::namespace::eval overtype::priv { tcl::dict::set cache_is_sgr $code $answer return $answer } + # better named render_to_unapplied? proc render_unapplied {overlay_grapheme_control_list gci} { upvar idx_over idx_over upvar unapplied unapplied @@ -3532,7 +4026,7 @@ tcl::namespace::eval overtype::priv { set ustacks [lreplace $ustacks $i $i] set gxstacks [lreplace $gxstacks $i $i] } else { - + puts stderr "render_delchar - attempt to delchar at index $i >= number of outcols $nxt - shouldn't happen" } } proc render_erasechar {i count} { @@ -3563,21 +4057,68 @@ tcl::namespace::eval overtype::priv { upvar outcols o lset o $i $c } + + #Initial usecase is for old-terminal hack to add PM-wrapped \b + #review - can be used for other multibyte sequences that occupy one column? + #combiners? diacritics? + proc render_append_to_char {i c} { + upvar outcols o + if {$i > [llength $o]-1} { + error "render_append_to_char cannot append [ansistring VIEW -lf 1 -nul 1 $c] to existing char at index $i while $i >= llength outcols [llength $o]" + } + set existing [lindex $o $i] + if {$existing eq "\0"} { + lset o $i $c + } else { + lset o $i [string cat $existing $c] + } + } #is actually addgrapheme? proc render_addchar {i c sgrstack gx0stack {insert_mode 0}} { upvar outcols o upvar understacks ustacks upvar understacks_gx gxstacks - if 0 { - if {$c eq "c"} { - puts "i:$i c:$c sgrstack:[ansistring VIEW $sgrstack]" - puts "understacks:[ansistring VIEW $ustacks]" - upvar overstacks overstacks - puts "overstacks:[ansistring VIEW $overstacks]" - puts "info level 0:[info level 0]" - } + # -- --- --- + #this is somewhat of a hack.. probably not really the equivalent of proper reverse video? review + #we should ideally be able to reverse the video of a sequence that already includes SGR reverse/noreverse attributes + upvar reverse_mode do_reverse + #if {$do_reverse} { + # lappend sgrstack [a+ reverse] + #} else { + # lappend sgrstack [a+ noreverse] + #} + + #JMN3 + if {$do_reverse} { + #note we can't just look for \x1b\[7m or \x1b\[27m + # it may be a more complex sequence like \x1b\[0\;\;7\;31m etc + + set existing_reverse_state 0 + set codeinfo [punk::ansi::codetype::sgr_merge $sgrstack -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set sgrstack [list [dict get $codeinfo mergeresult] $rflip] + #set sgrstack [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] } + + # -- --- --- set nxt [llength $o] if {!$insert_mode} { diff --git a/src/bootsupport/modules/punk/ansi-0.1.1.tm b/src/bootsupport/modules/punk/ansi-0.1.1.tm index 85cb9f27..7a2f9443 100644 --- a/src/bootsupport/modules/punk/ansi-0.1.1.tm +++ b/src/bootsupport/modules/punk/ansi-0.1.1.tm @@ -553,28 +553,51 @@ tcl::namespace::eval punk::ansi { $obj destroy return $result } - proc example {} { + proc example {args} { + set base [punk::repo::find_project] + set default_ansibase [file join $base src/testansi] + + set argd [punk::args::get_dict [tstr -return string { + *proc -name punk::ansi::example -help "Display .ans image files in a grid that will fit in console + " + -colwidth -default 82 -help "Width of each column - default of 82 will fit a standard 80wide ansi image (when framed) + You can specify a narrower width to truncate images on the right side" + -folder -default "${$default_ansibase}" -help "Base folder for files if relative paths are used. + Defaults to /src/testansi - where projectbase is determined from current directory. + " + *values -min 0 -max -1 + files -default {belinda.ans bot.ans flower.ans fish.ans} -multiple true -help "List of filenames - leave empty to display 4 defaults" + }] $args] + set colwidth [dict get $argd opts -colwidth] + set ansibase [file normalize [dict get $argd opts -folder]] + set fnames [dict get $argd values files] + + #assumes fixed column widths e.g 80col images will fit in 82-width frames (common standard for old ansi art) (of arbitrary height) #todo - review dependency on punk::repo ? package require textblock package require punk::repo package require punk::console - set fnames [list belinda.ans bot.ans flower.ans fish.ans] - set base [punk::repo::find_project] - set ansibase [file join $base src/testansi] if {![file exists $ansibase]} { - puts stderr "Missing testansi folder at $base/src/testansi" + puts stderr "Missing folder at $ansibase" puts stderr "Ensure ansi test files exist: $fnames" #error "punk::ansi::example Cannot find example files" } - set missingbase [a+ yellow][textblock::block 80 23 ?][a] + set missingbase [a+ yellow][textblock::block [expr {$colwidth-2}] 23 ?][a] ;#assuming standard frame - subtract 2 for left/right borders set pics [list] foreach f $fnames { - if {![file exists $ansibase/$f]} { - set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$ansibase/$f[a]"] + if {[file pathtype $f] ne "absolute"} { + set filepath [file normalize $ansibase/$f] + } else { + set filepath [file normalize $f] + } + if {![file exists $filepath]} { + set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$f[a]"] lappend pics [tcl::dict::create filename $f pic $p status missing] } else { - set img [join [lines_as_list -line trimline -block trimtail [ansicat $ansibase/$f]] \n] + #set img [join [lines_as_list -line trimline -block trimtail [ansicat $filepath]] \n] + #-line trimline will wreck some images + set img [join [lines_as_list -block trimtail [ansicat $filepath]] \n] lappend pics [tcl::dict::create filename $f pic $img status ok] } } @@ -582,30 +605,73 @@ tcl::namespace::eval punk::ansi { set termsize [punk::console:::get_size] set margin 4 set freewidth [expr {[tcl::dict::get $termsize columns]-$margin}] - set per_row [expr {$freewidth / 80}] - - set rowlist [list] - set row [list] - set i 1 + set per_row [expr {$freewidth / $colwidth}] + + set rowlist [list] ;# { { } { } } + set heightlist [list] ;# { { } { } } + set maxheights [list] ;# { } + set row [list] ;#wip row + set rowh [list] ;#wip row img heights + set i 1 ;#track image index of whole pics list + set rowindex 0 foreach picinfo $pics { set subtitle "" if {[tcl::dict::get $picinfo status] ne "ok"} { set subtitle [tcl::dict::get $picinfo status] } set title [tcl::dict::get $picinfo filename] - lappend row [textblock::frame -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + set fr [textblock::frame -width $colwidth -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + # -- --- --- --- + #we need the max height of a row element to use join_basic instead of join below + # -- --- --- --- + set fr_height [textblock::height $fr] + lappend row $fr + lappend rowh $fr_height + + set rowmax [lindex $maxheights $rowindex] + if {$rowmax eq ""} { + #empty result means no maxheights entry for this row yet + set rowmax $fr_height + lappend maxheights $rowmax + } else { + if {$fr_height > $rowmax} { + set rowmax $fr_height + lset maxheights end $rowmax + } + } + # -- --- --- --- + if {$i % $per_row == 0} { lappend rowlist $row + lappend heightlist $rowh + incr rowindex set row [list] + set rowh [list] } elseif {$i == [llength $pics]} { lappend rowlist $row + lappend heightlist $rowh } incr i } - + #puts "--> maxheights: $maxheights" + #puts "--> heightlist: $heightlist" set result "" - foreach r $rowlist { - append result [textblock::join_basic -- {*}$r] \n + set rowindex 0 + set blankline [string repeat " " $colwidth] + foreach imgs $rowlist heights $heightlist { + set maxheight [lindex $maxheights $rowindex] + set adjusted_row [list] + foreach i $imgs h $heights { + if {$h < $maxheight} { + #add blank lines to bottom of shorter images so join_basic can be used. + #textblock::join of ragged-height images would work and remove the need for all the height calculation + #.. but it requires much more processing + append i [string repeat \n$blankline [expr {$maxheight - $h}]] + } + lappend adjusted_row $i + } + append result [textblock::join_basic -- {*}$adjusted_row] \n + incr rowindex } @@ -3199,6 +3265,28 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu return \x1b8 } # -- --- --- --- --- + #CRM Show Control Character Mode + proc enable_crm {} { + return \x1b\[3h + } + proc disable_crm {} { + return \x1b\[3l + } + + #DECSNM + #Note this can invert the enclosed section including any already reversed by SGR 7 - depending on terminal support. + #e.g + #set test [a+ reverse]aaa[a+ noreverse]bbb + # - $test above can't just be reversed by putting another [a+ reverse] in front of it. + # - but the following will work (even if underlying terminal doesn't support ?5 sequences) + #overtype::renderspace -width 20 [enable_inverse]$test + proc enable_inverse {} { + return \x1b\[?5h + } + proc disable_inverse {} { + return \x1b\[?5l + } + #DECAWM - automatic line wrapping proc enable_line_wrap {} { @@ -3399,6 +3487,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu #the purpose of backspace (or line cr) in embedded text is unclear. Should it allow some sort of character combining/overstrike as it has sometimes done historically (nroff/less)? e.g a\b` as an alternative combiner or bolding if same char #This should presumably only be done if the over_strike (os) capability is enabled in the terminal. Either way - it presumably won't affect printing width? set line [punk::ansi::ansistrip $line] + #ANSI (e.g PM/SOS) can contain \b or \n or \t but won't contribute to length + #ansistrip must come before any other processing of these chars. + #we can't use simple \b processing if we get ansi codes and aren't actually processing them (e.g moves) set line [punk::char::strip_nonprinting_ascii $line] ;#only strip nonprinting after ansistrip - some like BEL are part of ansi @@ -3748,6 +3839,7 @@ tcl::namespace::eval punk::ansi { -filter_fg 0\ -filter_bg 0\ -filter_reset 0\ + -info 0\ ] #codes *must* already have been split so that one esc per element in codelist @@ -3760,7 +3852,8 @@ tcl::namespace::eval punk::ansi { set opts $defaultopts_sgr_merge_singles foreach {k v} $args { switch -- $k { - -filter_fg - -filter_bg - -filter_reset { + -filter_fg - -filter_bg - -filter_reset - + -info { tcl::dict::set opts $k $v } default { @@ -4139,19 +4232,24 @@ tcl::namespace::eval punk::ansi { set codemerge [tcl::string::trimright $codemerge {;}] if {$unmergeable ne ""} { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" } else { - return "\x1b\[${codemerge}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m[join $othercodes ""]" } } else { if {$unmergeable eq ""} { #there were no SGR codes - not even resets - return [join $othercodes ""] + set mergeresult [join $othercodes ""] } else { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${unmergeable}m[join $othercodes ""]" } } + if {[tcl::dict::get $opts -info]} { + return [dict create sgr $codemerge unmergeable $unmergeable othercodes $othercodes mergeresult $mergeresult codestate $codestate] + } else { + return $mergeresult + } } #has_sgr_reset - rather than support this function - create an sgr normalize function that removes dead params and brings reset to front of param list? @@ -4240,7 +4338,7 @@ tcl::namespace::eval punk::ansi::ta { #we also need to track the start of ST terminated code and not add it for replay (in the ansistring functions) #variable re_ST {(?:\x1bX|\u0098|\x1b\^|\u009E|\x1b_|\u009F)(?:[^\x1b\007\u009c]*)(?:\x1b\\|\007|\u009c)} ;#downsides: early terminating with nests, mixes 7bit 8bit start/ends (does that exist in the wild?) #keep our 8bit/7bit start-end codes separate - variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} + variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} @@ -4252,7 +4350,7 @@ tcl::namespace::eval punk::ansi::ta { # -- --- --- --- #handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regext TRIE generator that works with Tcl regexes #This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone. - variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} + variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} # -- --- --- --- @@ -5674,7 +5772,12 @@ tcl::namespace::eval punk::ansi::ansistring { ENQ [list \x05 \u2405]\ ACK [list \x06 \u2406]\ BEL [list \x07 \u2407]\ + BS [list \x08 \u2408]\ + HT [list \x09 \u2409]\ + LF [list \x0a \u240a]\ + VT [list \x0b \u240b]\ FF [list \x0c \u240c]\ + CR [list \x0d \u240d]\ SO [list \x0e \u240e]\ SF [list \x0f \u240f]\ DLE [list \x10 \u2410]\ @@ -5688,12 +5791,15 @@ tcl::namespace::eval punk::ansi::ansistring { CAN [list \x18 \u2418]\ EM [list \x19 \u2419]\ SUB [list \x1a \u241a]\ + ESC [list \x1b \u241b]\ FS [list \x1c \u241c]\ GS [list \x1d \u241d]\ RS [list \x1e \u241e]\ US [list \x1f \u241f]\ + SP [list \x20 \u2420]\ DEL [list \x7f \u2421]\ ] + #alternate symbols for space # \u2422 Blank Symbol (b with forwardslash overly) # \u2423 Open Box (square bracket facing up like a tray/box) @@ -5836,6 +5942,7 @@ tcl::namespace::eval punk::ansi::ansistring { -cr 1\ -lf 0\ -vt 0\ + -ff 1\ -ht 1\ -bs 1\ -sp 1\ @@ -5850,16 +5957,22 @@ tcl::namespace::eval punk::ansi::ansistring { set opt_cr [tcl::dict::get $opts -cr] set opt_lf [tcl::dict::get $opts -lf] set opt_vt [tcl::dict::get $opts -vt] + set opt_ff [tcl::dict::get $opts -ff] set opt_ht [tcl::dict::get $opts -ht] set opt_bs [tcl::dict::get $opts -bs] set opt_sp [tcl::dict::get $opts -sp] # -- --- --- --- --- + # -lf 2, -vt 2 and -ff 2 are useful for CRM mode (Show Control Character Mode) in the terminal - where a newline is expected to display after the character. set visuals_opt $debug_visuals + set visuals_opt [dict remove $visuals_opt CR ESC LF VT FF HT BS SP] + if {$opt_esc} { tcl::dict::set visuals_opt ESC [list \x1b \u241b] + } else { + tcl::dict::unset visuals_opt ESC } if {$opt_cr} { tcl::dict::set visuals_opt CR [list \x0d \u240d] @@ -5870,9 +5983,20 @@ tcl::namespace::eval punk::ansi::ansistring { if {$opt_lf == 2} { tcl::dict::set visuals_opt LF [list \x0a \u240a\n] } - if {$opt_vt} { + if {$opt_vt == 1} { tcl::dict::set visuals_opt VT [list \x0b \u240b] } + if {$opt_vt == 2} { + tcl::dict::set visuals_opt VT [list \x0b \u240b\n] + } + switch -exact -- $opt_ff { + 1 { + tcl::dict::set visuals_opt FF [list \x0c \u240c] + } + 2 { + tcl::dict::set visuals_opt FF [list \x0c \u240c\n] + } + } if {$opt_ht} { tcl::dict::set visuals_opt HT [list \x09 \u2409] } diff --git a/src/bootsupport/modules/punk/char-0.1.0.tm b/src/bootsupport/modules/punk/char-0.1.0.tm index ed4b22e4..e47ba051 100644 --- a/src/bootsupport/modules/punk/char-0.1.0.tm +++ b/src/bootsupport/modules/punk/char-0.1.0.tm @@ -552,13 +552,26 @@ tcl::namespace::eval punk::char { string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] } } else { + #review - use -profile? proc encodable "s {enc [encoding system]}" { set encname [encname $enc] - string eq $s [encoding convertfrom $encname [encoding convertto $encname $s]] + if {![catch { + string eq $s [encoding convertfrom $encname [encoding convertto $encname $s]] + } result]} { + return $result + } else { + return 0 + } } proc decodable "s {enc [encoding system]}" { set encname [encname $enc] - string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] + if {![catch { + string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] + } result]} { + return $result + } else { + return 0 + } } } #-- --- --- --- --- --- --- --- diff --git a/src/bootsupport/modules/punk/console-0.1.1.tm b/src/bootsupport/modules/punk/console-0.1.1.tm index 3c64c7e3..6368aeae 100644 --- a/src/bootsupport/modules/punk/console-0.1.1.tm +++ b/src/bootsupport/modules/punk/console-0.1.1.tm @@ -13,11 +13,51 @@ # @@ Meta End +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_punk::console 0 0.1.1] +#[copyright "2024"] +#[titledesc {punk console}] [comment {-- Name section and table of contents description --}] +#[moddesc {punk console}] [comment {-- Description at end of page heading --}] +#[require punk::console] +#[keywords module console terminal] +#[description] +#[para] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section Overview] +#[para] overview of punk::console +#[subsection Concepts] +#[para] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements -##e.g package require frobz +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by punk::console +#[list_begin itemized] + +package require Tcl 8.6- package require punk::ansi +#*** !doctools +#[item] [package {Tcl 8.6-}] +#[item] [package {punk::ansi}] + + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + #if {"windows" eq $::tcl_platform(platform)} { @@ -30,6 +70,13 @@ package require punk::ansi # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval punk::console { + #*** !doctools + #[subsection {Namespace punk::console}] + #[para] + + #*** !doctools + #[list_begin definitions] + variable tabwidth 8 ;#default only - will attempt to detect and set to that configured in terminal #Note that windows terminal cooked mode seems to use 8 for interactive use even if set differently #e.g typing tab characters may still be echoed 8-spaced while writing to stdout my obey the terminal's tab stops. @@ -1028,23 +1075,37 @@ namespace eval punk::console { return [split [get_cursor_pos $inoutchannels] ";"] } - #todo - determine cursor on/off state before the call to restore properly. May only be possible + #todo - determine cursor on/off state before the call to restore properly. proc get_size {{inoutchannels {stdin stdout}}} { lassign $inoutchannels in out #we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810 #chan eof is faster whether chan exists or not than - if {[catch {chan eof $in} is_eof]} { - error "punk::console::get_size input channel $in seems to be closed ([info level 1])" + if {[catch {chan eof $out} is_eof]} { + error "punk::console::get_size output channel $out seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on input channel $in ([info level 1])" + error "punk::console::get_size eof on output channel $out ([info level 1])" } } - if {[catch {chan eof $out} is_eof]} { - error "punk::console::get_size output channel $out seems to be closed ([info level 1])" + #we don't need to care about the input channel if chan configure on the output can give us the info. + #short circuit ansi cursor movement method if chan configure supports the -winsize value + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + #this mechanism is much faster than ansi cursor movements + #REVIEW check if any x-platform anomalies with this method? + #can -winsize key exist but contain erroneous info? We will check that we get 2 ints at least + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + #continue on to ansi mechanism if we didn't get 2 ints + } + + if {[catch {chan eof $in} is_eof]} { + error "punk::console::get_size input channel $in seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on output channel $out ([info level 1])" + error "punk::console::get_size eof on input channel $in ([info level 1])" } } @@ -1067,18 +1128,28 @@ namespace eval punk::console { } } - #faster - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore - proc get_size_cursorrestore {} { + #faster than get_size when it is using ansi mechanism - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore + proc get_size_cursorrestore {{inoutchannels {stdin stdout}}} { + lassign $inoutchannels in out + #we use the same shortcircuit mechanism as get_size to avoid ansi at all if the output channel will give us the info directly + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + } + if {[catch { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. - puts -nonewline [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] - lassign [get_cursor_pos_list] lines cols - puts -nonewline [punk::ansi::cursor_restore][punk::console::cursor_on];flush stdout + puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] + lassign [get_cursor_pos_list $inoutchannels] lines cols + puts -nonewline $out [punk::ansi::cursor_restore][punk::console::cursor_on];flush $out set result [list columns $cols rows $lines] } errM]} { - puts -nonewline [punk::ansi::cursor_restore_dec] - puts -nonewline [punk::ansi::cursor_on] + puts -nonewline $out [punk::ansi::cursor_restore_dec] + puts -nonewline $out [punk::ansi::cursor_on] error "$errM" } else { return $result @@ -1803,6 +1874,9 @@ namespace eval punk::console { } #run the test and allow warnings to be emitted to stderr on package load. User should know the terminal and/or Tcl version are not optimal for unicode character work #set testresult [test1] + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::console ---}] } @@ -1825,4 +1899,7 @@ package provide punk::console [namespace eval punk::console { variable version set version 0.1.1 }] -return \ No newline at end of file +return + +#*** !doctools +#[manpage_end] diff --git a/src/bootsupport/modules/punk/du-0.1.0.tm b/src/bootsupport/modules/punk/du-0.1.0.tm index f0e96a28..1eca1f47 100644 --- a/src/bootsupport/modules/punk/du-0.1.0.tm +++ b/src/bootsupport/modules/punk/du-0.1.0.tm @@ -967,7 +967,7 @@ namespace eval punk::du { dict set effective_opts -with_times $timed_types dict set effective_opts -with_sizes $sized_types - return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors] + return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden $flaggedhidden flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors] } #zipfs attributes/behaviour fairly different to tclvfs - keep separate diff --git a/src/bootsupport/modules/punk/lib-0.1.1.tm b/src/bootsupport/modules/punk/lib-0.1.1.tm index cb786f22..63f32dee 100644 --- a/src/bootsupport/modules/punk/lib-0.1.1.tm +++ b/src/bootsupport/modules/punk/lib-0.1.1.tm @@ -328,7 +328,17 @@ tcl::namespace::eval punk::lib::compat { # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval punk::lib { tcl::namespace::export * - #variable xyz + variable has_struct_list + set has_struct_list [expr {![catch {package require struct::list}]}] + variable has_struct_set + set has_struct_set [expr {![catch {package require struct::set}]}] + variable has_punk_ansi + set has_punk_ansi [expr {![catch {package require punk::ansi}]}] + set has_twapi 0 + if {"windows" eq $::tcl_platform(platform)} { + set has_twapi [expr {![catch {package require twapi}]}] + } + #*** !doctools #[subsection {Namespace punk::lib}] @@ -614,7 +624,9 @@ namespace eval punk::lib { } proc pdict {args} { - if {[catch {package require punk::ansi} errM]} { + package require punk::args + variable has_punk_ansi + if {!$has_punk_ansi} { set sep " = " } else { #set sep " [a+ Web-seagreen]=[a] " @@ -691,14 +703,15 @@ namespace eval punk::lib { # - Copy proc and attempt rework so we can get back to this as a baseline for functionality proc showdict {args} { ;# analogous to parray (except that it takes the dict as a value) #set sep " [a+ Web-seagreen]=[a] " - if {[catch {package require punk::ansi} errM]} { - set sep " = " + variable has_punk_ansi + if {!$has_punk_ansi} { set RST "" + set sep " = " set sep_mismatch " mismatch " } else { - set sep " [punk::ansi::a+ Green]=[punk::ansi::a] " ;#stick to basic default colours for wider terminal support set RST [punk::ansi::a] - set sep_mismatch " [punk::ansi::a+ Brightred undercurly underline undt-white]mismatch[punk::ansi::a] " + set sep " [punk::ansi::a+ Green]=$RST " ;#stick to basic default colours for wider terminal support + set sep_mismatch " [punk::ansi::a+ Brightred undercurly underline undt-white]mismatch$RST " } package require punk ;#we need pipeline pattern matching features package require textblock @@ -836,7 +849,7 @@ namespace eval punk::lib { lappend keyset_structure dict } @* { - puts ---->HERE<---- + #puts "showdict ---->@*<----" dict set pattern_this_structure $p list set keys [punk::lib::range 0 [llength $dval]-1] lappend keyset {*}$keys @@ -1405,16 +1418,29 @@ namespace eval punk::lib { } proc is_list_all_in_list {small large} { - package require struct::list - package require struct::set set small_in_large [lsort [struct::set intersect [lsort -unique $small] $large ]] return [struct::list equal [lsort $small] $small_in_large] } + if {!$has_struct_list || !$has_struct_set} { + set body { + package require struct::list + package require struct::set + } + append body [info body is_list_all_in_list] + proc is_list_all_in_list {small large} $body + } + proc is_list_all_ni_list {a b} { - package require struct::set set i [struct::set intersect $a $b] return [expr {[llength $i] == 0}] } + if {!$has_struct_set} { + set body { + package require struct::list + } + append body [info body is_list_all_ni_list] + proc is_list_all_ni_list {a b} $body + } #somewhat like struct::set difference - but order preserving, and doesn't treat as a 'set' so preserves dupes in fromlist #struct::set difference may happen to preserve ordering when items are integers, but order can't be relied on, @@ -1465,18 +1491,22 @@ namespace eval punk::lib { return [array names tmp] } - package require struct::set - if {[struct::set equal [struct::set union {a a} {}] {a}]} { - proc lunique_unordered {list} { - struct::set union $list {} - } - } else { - puts stderr "WARNING: struct::set union no longer dedupes!" - #we could also test a sequence of: struct::set add - proc lunique_unordered {list} { - tailcall lunique $list + #default/fallback implementation + proc lunique_unordered {list} { + lunique $list + } + if {$has_struct_set} { + if {[struct::set equal [struct::set union {a a} {}] {a}]} { + proc lunique_unordered {list} { + struct::set union $list {} + } + } else { + puts stderr "WARNING: struct::set union no longer dedupes!" + #we could also test a sequence of: struct::set add } } + + #order-preserving proc lunique {list} { set new {} @@ -1863,14 +1893,14 @@ namespace eval punk::lib { set opt_empty [tcl::dict::get $opts -empty_as_hex] # -- --- --- --- - set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map [list _ ""] [string trim $h]}] + set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map {_ ""} [string trim $h]}] if {$opt_validate} { #Note appended F so that we accept list of empty strings as per the documentation if {![string is xdigit -strict [join $list_largeHex ""]F ]} { error "[namespace current]::hex2dec error: non-hex digits encountered after stripping underscores and leading/trailing whitespace for each element\n $list_largeHex" } } - if {![string is xdigit -strict [string map [list _ ""] $opt_empty]]} { + if {![string is xdigit -strict [string map {_ ""} $opt_empty]]} { #mapping empty string to a value destroys any advantage of -scanonly #todo - document that -scanonly has 2 restrictions - each element must be valid hex and less than 7 chars long #set list_largeHex [lmap v $list_largeHex[set list_largeHex {}] {expr {$v eq ""} ? {0} : {[set v]}}] @@ -1878,7 +1908,7 @@ namespace eval punk::lib { error "[namespace current]::hex2dec error: empty values in list cannot be mapped to non-hex $opt_empty" } } else { - set opt_empty [string trim [string map [list _ ""] $opt_empty]] + set opt_empty [string trim [string map {_ ""} $opt_empty]] if {[set first_empty [lsearch $list_largeHex ""]] >= 0} { #set list_largeHex [lmap v $list_largeHex[set list_largeHex {}] {expr {$v eq ""} ? {$opt_empty} : {$v}}] set nonempty_head [lrange $list_largeHex 0 $first_empty-1] @@ -1931,13 +1961,13 @@ namespace eval punk::lib { } set fmt "%${opt_width}.${opt_width}ll${spec}" - set list_decimals [lmap d $list_decimals[unset list_decimals] {string map [list _ ""] [string trim $d]}] - if {![string is digit -strict [string map [list _ ""] $opt_empty]]} { + set list_decimals [lmap d $list_decimals[unset list_decimals] {string map {_ ""} [string trim $d]}] + if {![string is digit -strict [string map {_ ""} $opt_empty]]} { if {[lsearch $list_decimals ""] >=0} { error "[namespace current]::dec2hex error: empty values in list cannot be mapped to non-decimal $opt_empty" } } else { - set opt_empty [string map [list _ ""] $opt_empty] + set opt_empty [string map {_ ""} $opt_empty] if {[set first_empty [lsearch $list_decimals ""]] >= 0} { set nonempty_head [lrange $list_decimals 0 $first_empty-1] set list_decimals [concat $nonempty_head [lmap v [lrange $list_decimals $first_empty end] {expr {$v eq ""} ? {$opt_empty} : {$v}}]] @@ -2402,13 +2432,14 @@ namespace eval punk::lib { # important for pipeline & match_assign # -line trimline|trimleft|trimright -block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty -commandprefix {string length} ? # -block trimming only trims completely empty lines. use -line trimming to remove whitespace e.g -line trimright will clear empty lines without affecting leading whitespace on other lines that aren't pure whitespace - proc linelist {args} { + + set linelist_body { set usage "linelist ?-line trimline|trimleft|trimright? ?-block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty? -commandprefix text" if {[llength $args] == 0} { error "linelist missing textchunk argument usage:$usage" } set text [lindex $args end] - set text [string map [list \r\n \n] $text] ;#review - option? + set text [string map {\r\n \n} $text] ;#review - option? set arglist [lrange $args 0 end-1] set opts [tcl::dict::create\ @@ -2441,10 +2472,10 @@ namespace eval punk::lib { } } #normalize certain combos - if {[set posn [lsearch $opt_block trimhead1]] >=0 && "trimhead" in $opt_block} { + if {"trimhead" in $opt_block && [set posn [lsearch $opt_block trimhead1]] >=0} { set opt_block [lreplace $opt_block $posn $posn] } - if {[set posn [lsearch $opt_block trimtail1]] >=0 && "trimtail" in $opt_block} { + if {"trimtail" in $opt_block && [set posn [lsearch $opt_block trimtail1]] >=0} { set opt_block [lreplace $opt_block $posn $posn] } if {"trimall" in $opt_block} { @@ -2594,9 +2625,10 @@ namespace eval punk::lib { #Each resulting line should have a reset of some type at start and a pure-reset at end to stop #see if we can find an ST sequence that most terminals will not display for marking sections? if {$opt_ansireplays} { - package require punk::ansi + #package require punk::ansi + if {$opt_ansiresets} { - set RST [punk::ansi::a] + set RST "\x1b\[0m" } else { set RST "" } @@ -2721,6 +2753,15 @@ namespace eval punk::lib { return $linelist } + if {$has_punk_ansi} { + #optimise linelist as much as possible + set linelist_body [string map { ""} $linelist_body] + } else { + #punk ansi not avail at time of package load. + #by putting in calls to punk::ansi the user will get appropriate error messages + set linelist_body [string map { "package require punk::ansi"} $linelist_body] + } + proc linelist {args} $linelist_body interp alias {} errortime {} punk::lib::errortime @@ -2846,6 +2887,133 @@ namespace eval punk::lib { proc temperature_c_to_f {deg_celsius} { return [expr {($deg_celsius * (9/5.0)) + 32}] } + + proc interp_sync_package_paths {interp} { + if {![interp exists $interp]} { + error "interp_sync_package_paths error. interp '$interp' not found. Create it first with \[interp create $interp\]" + } + interp eval $interp [list set ::auto_path $::auto_path] + interp eval $interp {tcl::tm::remove {*}[tcl::tm::list]} + interp eval $interp [list tcl::tm::add {*}[lreverse [tcl::tm::list]]] + } + + proc objclone {obj} { + append obj2 $obj {} + } + + + + proc format_number {numbers_or_commaformattednumbers {delim ""} {groupsize ""}} { + variable has_twapi + if {$has_twapi} { + if {$delim eq "" && $groupsize eq ""} { + set localeid [twapi::get_system_default_lcid] + } + } + + set results [list] + set nums [objclone $numbers_or_commaformattednumbers] ;#stops single num from getting internal rep of list + foreach inputnum $nums { + set number [objclone $inputnum] + #also handle tcl 8.7+ underscores in numbers + set number [string map [list _ "" , ""] $number] + #normalize e.g 2e4 -> 20000.0 + set number [expr {$number}] + + if {$has_twapi} { + if {$delim eq "" && $groupsize eq ""} { + lappend results [twapi::format_number $number $localeid -idigits -1] + continue + } else { + if {$delim eq ""} {set delim ","} + if {$groupsize eq ""} {set groupsize 3} + lappend results [twapi::format_number $number 0 -idigits -1 -sthousand $delim -sgrouping $groupsize] + continue + } + } + #todo - get configured user defaults + set delim "," + set groupsize 3 + + lappend results [delimit_number $number $delim $groupsize] + } + + if {[llength $results] == 1} { + #keep intrep as string rather than list + return [lindex $results 0] + } + return $results + } + + + #from wiki https://wiki.tcl-lang.org/page/Delimiting+Numberse + # Given a number represented as a string, insert delimiters to break it up for + # readability. Normally, the delimiter will be a comma which will be inserted every + # three digits. However, the delimiter and groupsize are optional arguments, + # permitting use in other locales. + # + # The string is assumed to consist of digits, possibly preceded by spaces, + # and possibly containing a decimal point, i.e.: [:space:]*[:digit:]*\.[:digit:]* + + proc delimit_number {unformattednumber {delim ","} {GroupSize 3}} { + set number [punk::objclone $unformattednumber] + set number [string map {_ ""} $number] + #normalize using expr - e.g 2e4 -> 20000.0 + set number [expr {$number}] + # First, extract right hand part of number, up to and including decimal point + set point [string last "." $number]; + if {$point >= 0} { + set PostDecimal [string range $number [expr $point + 1] end]; + set PostDecimalP 1; + } else { + set point [expr [string length $number] + 1] + set PostDecimal ""; + set PostDecimalP 0; + } + + # Now extract any leading spaces. review - regex for whitespace instead of just ascii space? + set ind 0; + while {[string equal [string index $number $ind] \u0020]} { + incr ind; + } + set FirstNonSpace $ind; + set LastSpace [expr $FirstNonSpace - 1]; + set LeadingSpaces [string range $number 0 $LastSpace]; + + # Now extract the non-fractional part of the number, omitting leading spaces. + set MainNumber [string range $number $FirstNonSpace [expr $point -1]]; + + # Insert commas into the non-fractional part. + set Length [string length $MainNumber]; + set Phase [expr $Length % $GroupSize] + set PhaseMinusOne [expr $Phase -1]; + set DelimitedMain ""; + + #First we deal with the extra stuff. + if {$Phase > 0} { + append DelimitedMain [string range $MainNumber 0 $PhaseMinusOne]; + } + set FirstInGroup $Phase; + set LastInGroup [expr $FirstInGroup + $GroupSize -1]; + while {$LastInGroup < $Length} { + if {$FirstInGroup > 0} { + append DelimitedMain $delim; + } + append DelimitedMain [string range $MainNumber $FirstInGroup $LastInGroup]; + incr FirstInGroup $GroupSize + incr LastInGroup $GroupSize + } + + # Reassemble the number. + if {$PostDecimalP} { + return [format "%s%s.%s" $LeadingSpaces $DelimitedMain $PostDecimal]; + } else { + return [format "%s%s" $LeadingSpaces $DelimitedMain]; + } + } + + + #*** !doctools #[list_end] [comment {--- end definitions namespace punk::lib ---}] } @@ -2998,7 +3166,9 @@ tcl::namespace::eval punk::lib::system { return [concat $smallfactors [lreverse $largefactors] $x] } - # incomplte - report which is the innermost bracket/quote etc awaiting completion for a Tcl command + + + # incomplete - report which is the innermost bracket/quote etc awaiting completion for a Tcl command #important - used by punk::repl proc incomplete {partial} { #we can apparently get away without concatenating current innerpartial to previous in list - REVIEW. diff --git a/src/bootsupport/modules/punk/mix/base-0.1.tm b/src/bootsupport/modules/punk/mix/base-0.1.tm index 1e90b5ca..932c1db6 100644 --- a/src/bootsupport/modules/punk/mix/base-0.1.tm +++ b/src/bootsupport/modules/punk/mix/base-0.1.tm @@ -35,12 +35,14 @@ namespace eval punk::mix::base { } #puts stderr "punk::mix::base extension: [string trimleft $extension :]" if {![string length $extension]} { - #if still no extension - must have been called dirctly as punk::mix::base::_cli + #if still no extension - must have been called directly as punk::mix::base::_cli if {![llength $args]} { set args "help" } set extension [namespace current] } + #init usually used to load commandsets (and export their names) into the extension namespace/ensemble + ${extension}::_init if {![llength $args]} { if {[info exists ${extension}::default_command]} { tailcall $extension [set ${extension}::default_command] diff --git a/src/bootsupport/modules/punk/mix/cli-0.3.1.tm b/src/bootsupport/modules/punk/mix/cli-0.3.1.tm index 5b1ec6da..cd6f3025 100644 --- a/src/bootsupport/modules/punk/mix/cli-0.3.1.tm +++ b/src/bootsupport/modules/punk/mix/cli-0.3.1.tm @@ -31,47 +31,58 @@ namespace eval punk::mix::cli { namespace eval temp_import { } namespace ensemble create + variable initialised 0 - package require punk::overlay - catch { - punk::overlay::import_commandset module . ::punk::mix::commandset::module - } - punk::overlay::import_commandset debug . ::punk::mix::commandset::debug - punk::overlay::import_commandset repo . ::punk::mix::commandset::repo - punk::overlay::import_commandset lib . ::punk::mix::commandset::loadedlib - - catch { - package require punk::mix::commandset::project - punk::overlay::import_commandset project . ::punk::mix::commandset::project - punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection - } - if {[catch { - package require punk::mix::commandset::layout - punk::overlay::import_commandset project.layout . ::punk::mix::commandset::layout - punk::overlay::import_commandset project.layouts . ::punk::mix::commandset::layout::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::layout" - puts stderr $errM - } - if {[catch { - package require punk::mix::commandset::buildsuite - punk::overlay::import_commandset buildsuite . ::punk::mix::commandset::buildsuite - punk::overlay::import_commandset buildsuites . ::punk::mix::commandset::buildsuite::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::buildsuite" - puts stderr $errM - } - punk::overlay::import_commandset scriptwrap . ::punk::mix::commandset::scriptwrap - if {[catch { - package require punk::mix::commandset::doc - punk::overlay::import_commandset doc . ::punk::mix::commandset::doc - punk::overlay::import_commandset "" "" ::punk::mix::commandset::doc::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::doc" - puts stderr $errM + #lazy _init - called by punk::mix::base::_cli when ensemble used + proc _init {args} { + variable initialised + if {$initialised} { + return + } + puts stderr "punk::mix::cli::init $args" + package require punk::overlay + namespace eval ::punk::mix::cli { + catch { + punk::overlay::import_commandset module . ::punk::mix::commandset::module + } + punk::overlay::import_commandset debug . ::punk::mix::commandset::debug + punk::overlay::import_commandset repo . ::punk::mix::commandset::repo + punk::overlay::import_commandset lib . ::punk::mix::commandset::loadedlib + + catch { + package require punk::mix::commandset::project + punk::overlay::import_commandset project . ::punk::mix::commandset::project + punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection + } + if {[catch { + package require punk::mix::commandset::layout + punk::overlay::import_commandset project.layout . ::punk::mix::commandset::layout + punk::overlay::import_commandset project.layouts . ::punk::mix::commandset::layout::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::layout" + puts stderr $errM + } + if {[catch { + package require punk::mix::commandset::buildsuite + punk::overlay::import_commandset buildsuite . ::punk::mix::commandset::buildsuite + punk::overlay::import_commandset buildsuites . ::punk::mix::commandset::buildsuite::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::buildsuite" + puts stderr $errM + } + punk::overlay::import_commandset scriptwrap . ::punk::mix::commandset::scriptwrap + if {[catch { + package require punk::mix::commandset::doc + punk::overlay::import_commandset doc . ::punk::mix::commandset::doc + punk::overlay::import_commandset "" "" ::punk::mix::commandset::doc::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::doc" + puts stderr $errM + } + } + set initialised 1 } - proc help {args} { #set basehelp [punk::mix::base::help -extension [namespace current] {*}$args] set basehelp [punk::mix::base help {*}$args] @@ -210,11 +221,12 @@ namespace eval punk::mix::cli { proc validate_modulename {modulename args} { set opts [list\ -errorprefix validate_modulename\ + -strict 0\ ] if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} foreach {k v} $args { switch -- $k { - -errorprefix { + -errorprefix - -strict { dict set opts $k $v } default { @@ -223,8 +235,14 @@ namespace eval punk::mix::cli { } } # -- --- --- --- --- --- --- --- --- --- --- --- --- --- - set opt_errorprefix [dict get $opts -errorprefix] + set opt_errorprefix [dict get $opts -errorprefix] + set opt_strict [dict get $opts -strict] # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + if {$opt_strict} { + if {[regexp {[A-Z]} $modulename]} { + error "$opt_errorprefix '$modulename' contains uppercase which is not recommended as per tip 590, and option -strict is set to 1" + } + } validate_name_not_empty_or_spaced $modulename -errorprefix $opt_errorprefix set testname [string map {:: {}} $modulename] @@ -239,6 +257,56 @@ namespace eval punk::mix::cli { } return $modulename } + proc confirm_modulename {modulename} { + set finalised 0 + set aborted 0 + while {!$finalised && !$aborted} { + #first validate with -strict 0 to confirm acceptable while ignoring case issues. + #uppercase is generally valid but not recommended - so has separate prompting. + if {[catch {validate_modulename $modulename -strict 0} errM]} { + set msg "Chosen name didn't pass validation\n" + append msg "reason: $errM\n" + append msg "Please retype the modulename. You will be given a further prompt to confirm or abort." + set modulename [util::askuser $msg] + } elseif {[regexp {[A-Z]} $modulename]} { + set msg "module names containing uppercase are not recommended (see tip 590).\n" + append msg "Please retype the module name '$modulename' to proceed.\n" + append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" + append msg "Retype it all in lowercase to use recommended naming" + set answer [util::askuser $msg] + if {[regexp {[A-Z]} $answer]} { + if {$answer eq $modulename} { + #ok - user insists + set finalised 1 + } else { + #user supplied a different uppercase name - don't set finalised so we bug them again to type it two times the same way to proceed + puts stdout "A different uppercase name was supplied - reconfirmation required." + } + set modulename $answer + } else { + #user has resupplied modulename all as lowercase + if {$answer eq [string tolower $modulename]} { + set finalised 1 + } else { + #.. but it doesn't match original - require rerun + } + set modulename $answer + } + } else { + set answer [util::askuser "Proceed with the module name '$modulename'? Y to continue N to abort"] + if {[string tolower $answer] eq "y"} { + set finalised 1 + } else { + set aborted 1 + } + } + } + if {$aborted} { + return [dict create status error reason errmsg] + } else { + return [dict create status ok modulename $modulename] + } + } proc validate_projectname {projectname args} { set defaults [list\ diff --git a/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm b/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm index fafc3cec..856c9340 100644 --- a/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm +++ b/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm @@ -165,7 +165,17 @@ namespace eval punk::mix::commandset::doc { cd $original_wd } - proc validate {} { + proc validate {args} { + set argd [punk::args::get_dict { + -- -type none -optional 1 -help "end of options marker --" + -individual -type boolean -default 1 + *values -min 0 -max -1 + patterns -default {*} -type any -multiple 1 + } $args] + set opt_individual [tcl::dict::get $argd opts -individual] + set patterns [tcl::dict::get $argd values patterns] + + #todo - run and validate punk::docgen output set projectdir [punk::repo::find_project] if {$projectdir eq ""} { @@ -180,7 +190,23 @@ namespace eval punk::mix::commandset::doc { set docroot $projectdir/src/doc cd $docroot - dtplite validate $docroot + if {!$opt_individual && "*" in $patterns} { + if {[catch { + dtplite validate $docroot + } errM]} { + puts stderr "commandset::doc::validate failed for projectdir '$projectdir'" + puts stderr "docroot '$docroot'" + puts stderr "dtplite error was: $errM" + } + } else { + foreach p $patterns { + set treefiles [punk::path::treefilenames $p] + foreach path $treefiles { + puts stdout "dtplite validate $path" + dtplite validate $path + } + } + } #punk::mix::cli::lib::kettle_call lib validate-doc diff --git a/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm b/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm index bd0b5358..08d103ee 100644 --- a/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm +++ b/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm @@ -179,7 +179,16 @@ namespace eval punk::mix::commandset::loadedlib { return [join $loaded_libs \n] } - proc info {libname} { + proc info {args} { + set argspecs { + *values -min 1 + libname -help "library/package name" + } + set argd [punk::args::get_dict $argspecs $args] + set libname [dict get $argd values libname] + + + if {[catch {package require natsort}]} { set has_natsort 0 } else { diff --git a/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm b/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm index 9955c53b..029be3ce 100644 --- a/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm +++ b/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm @@ -204,6 +204,30 @@ namespace eval punk::mix::commandset::module { set modulename $module } punk::mix::cli::lib::validate_modulename $modulename -errorprefix "punk::mix::commandset::module::new" + + if {[regexp {[A-Z]} $module]} { + set msg "module names containing uppercase are not recommended (see tip 590).\n" + append msg "Please retype the module name '$module' to proceed.\n" + append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" + append msg "Retype it all in lowercase to use recommended naming" + set answer [util::askuser $msg] + if {[regexp {[A-Z]} $answer]} { + if {$answer eq $module} { + #ok - user insists + } else { + + } + } else { + #user has resupplied modulename all as lowercase + if {$answer eq [string tolower $module]} { + set module $answer + } else { + #.. but it doesn't match original - require rerun + } + } + } + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #options # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- diff --git a/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm b/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm index aa630d36..9afc685c 100644 --- a/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm +++ b/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm @@ -165,7 +165,7 @@ namespace eval punk::mix::commandset::project { #user can use dev module.new manually or supply module name in -modules set opt_modules [list] } else { - set opt_modules [list $projectname] + set opt_modules [list [string tolower $projectname]] ;#default modules to lowercase as is the modern (tip 590) recommendation for Tcl } } # -- --- --- --- --- --- --- --- --- --- --- --- --- @@ -919,10 +919,18 @@ namespace eval punk::mix::commandset::project { if {[llength $col_states]} { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes s $col_states { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode] [overtype::left $col6 $s]" \n } } else { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode]" \n } } diff --git a/src/bootsupport/modules/punk/overlay-0.1.tm b/src/bootsupport/modules/punk/overlay-0.1.tm index 5534dad3..73b8ef39 100644 --- a/src/bootsupport/modules/punk/overlay-0.1.tm +++ b/src/bootsupport/modules/punk/overlay-0.1.tm @@ -130,6 +130,7 @@ tcl::namespace::eval ::punk::overlay { }] set imported_commands [list] + set imported_tails [list] set nscaller [uplevel 1 [list tcl::namespace::current]] if {[catch { #review - noclobber? @@ -143,7 +144,10 @@ tcl::namespace::eval ::punk::overlay { } rename $cmd $import_as lappend imported_commands $import_as + lappend imported_tails [namespace tail $import_as] } + #make imported commands exported so they are available to the ensemble + tcl::namespace::eval ${nscaller} [list namespace export {*}$imported_tails] } errM]} { puts stderr "Error loading commandset $prefix $separator $cmdnamespace" puts stderr "err: $errM" diff --git a/src/bootsupport/modules/punk/path-0.1.0.tm b/src/bootsupport/modules/punk/path-0.1.0.tm index 933ef860..2165c0fd 100644 --- a/src/bootsupport/modules/punk/path-0.1.0.tm +++ b/src/bootsupport/modules/punk/path-0.1.0.tm @@ -63,11 +63,11 @@ package require Tcl 8.6- # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # oo::class namespace # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ -namespace eval punk::path::class { +#namespace eval punk::path::class { #*** !doctools #[subsection {Namespace punk::path::class}] #[para] class definitions - if {[info commands [namespace current]::interface_sample1] eq ""} { + #if {[info commands [namespace current]::interface_sample1] eq ""} { #*** !doctools #[list_begin enumerated] @@ -89,8 +89,8 @@ namespace eval punk::path::class { #*** !doctools #[list_end] [comment {--- end class enumeration ---}] - } -} + #} +#} # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ @@ -105,6 +105,448 @@ namespace eval punk::path { #[para] Core API functions for punk::path #[list_begin definitions] + # -- --- + #punk::path::normjoin + # - simplify . and .. segments as far as possible whilst respecting specific types of root. + # -- --- + #a form of file normalize that supports //xxx to be treated as server path names + #(ie regardless of unices ignoring (generally) leading double slashes, and regardless of windows volumerelative path syntax) + #(sometimes //server.com used as a short form for urls - which doesn't seem too incompatible with this anyway) + # -- --- + #This is intended to be purely a string analysis - without reference to filesystem volumes or vfs or zipfs mountpoints etc + # + #TODO - option for caller to provide a -base below which we can't backtrack. + #This is preferable to setting policy here for example regarding forcing no trackback below //servername/share + #Our default is to allow trackback to: + # :// + # :/ + # //./ (dos device volume) + # //server (while normalizing //./UNC/server to same) + # / (ordinary unix root) + # ./../ - (track back indefinitely on relpath as we are not resolving to anything physical and can't fully simplify the leading backtracks) + # + #The caller should do the file/vfs operations to determine this - not us. + # -- --- + #simplify path with respect to /./ & /../ elements - independent of platform + #NOTE: "anomalies" in standard tcl processing on windows: + #e.g file normalize {//host} -> c:/host (or e.g d:/host if we happen to be on another volume) + #file normalize {//host/share} -> //host/share + #This is because //host is treated as volume-relative in cmd/powershell and Tcl quite reasonably follows suit. + #This prevents cwd and windows commandlines from pointing to the server (above the share) + #Explorer however does allow pointing to the //server level and seeing shares as if they are directory entries. + #we are more interested in supporting the explorer-like behaviour - as while volumerelative paths are also useful on windows - they are lesser known. + #REVIEW. + #To get back to some consistent cross platform behaviour - we will treat //something as a root/volume i.e we can't backtrack above it with ".." + #note too that file split on UNC paths doesn't give a clear indication of the root + # file split //./UNC/server/share/subpath -> //./UNC server share subpath + # file split //server/share/subpath -> //server/share subpath + #TODO - disallow all change of root or change from relative path to absolute result. + #e.g normjoin relpath/../d:/secret should not return d:/secret - but ./d:/secret + # ================ + #known issues: + #1) + # normjoin d://a//b//c -> d://a/b/c + # This is because we don't detect specific schemes. ie it's treated the same as https://a/b/c -> https://a/b/c + # Not considered a problem - just potentially surprising. + # To avoid it we would have to enumerate possible schemes. + # As it stands a unix system could define a 'scheme' that happens to match windows style driveletters. Consider a 'feature' ? review. + # won't fix? + #2) + # normjoin https:///real.com/../fake.com -> https:///fake.com + # The extra slash means effectively our servername is empty - this is potentially confusing but probably the right thing to do here. + # It's a concern only if upstream treats the tripple slash in this case as valid and maps it to https:// - which would probably be bad anyway. + # won't fix (review) + #3) + #similarly + # normjoin //./UNC//server/share/subpath -> ///server/share/subpath (when 2 or more slashes directly after UNC) + # normjoin ///server/share -> ///server/share + #This is effectively an empty servername in the input with 'server' being pushed one level down - and the output is consistent + # possibly won't fix - review + #4) inconsistency + # we return normalized //server/share for //./UNC/server share + # but other dos device paths are maintained + # e.g //./c:/etc + # This is because such paths could contain alternate segment names (windows shortnames) which we aren't in a position to resolve. + # caller should + # #as with 'case' below - caller will need to run a post 'file normalize' + #5) we don't normalize case like file normalize does on windows platform. + # This is intentional. It could only be done with reference to underlying filesystem which we don't want here. + # + # ================ + # + #relpaths all end up with leading . - while not always the simplest form, this is ok. (helps stop inadvertent conversions to absolutes) + # Tests - TODO + # normjoin /d:/..//vfs:/test -> /vfs:/test (good - not converted to //vfs:/test) + proc normjoin {args} { + set args [lmap a $args {string map "\\\\ /" $a}] + set path [plainjoin {*}$args] + switch -exact $path { + "" { + return "" + } + / - // { + #treated in unixlike manner - (but leading doubleslashes with subsequent data are server indication) + #// not considered a servername indicator - but /// (for consistency) is. (empty servername?) + return / + } + /// { + #if this is effectively //$emptyservername/ + #then for consistency we should trail //=3 + #todo - shortcircuit that here? + } + } + # /// + set doubleslash1_posn [string first // $path] + + # -- --- --- temp warning on windows only - no x-platform difference in result + #on windows //host is of type volumerelative + # whereas //host/share is of type absolute + if {"windows" eq $::tcl_platform(platform) && [file pathtype $path] eq "volumerelative"} { + #volumerelative probably only occurs on windows anyway + if {$doubleslash1_posn == 0} { + #e.g //something where no further slashes + #review - eventually get rid of this warning and require upstream to know the appropriate usecase + puts stderr "Warning - ambiguous path $path - treating as server path - not 'volumerelative'" + } else { + # /something/etc + # /mnt/c/stuff + #output will retain leading / as if on unix. + #on windows - the result would still be interpreted as volumerelative if the caller normalizes it + } + } + # -- --- --- + + set is_relpath 0 + + #set path [string map [list \\ /] $path] + set finalparts [list] + set is_nonunc_dosdevice 0 + if {[punk::winpath::is_dos_device_path $path]} { + #review + if {[string range $path 4 6] eq "UNC"} { + #convert to 'standard' //server/... path for processing + set path "/[string range $path 7 end]" ;# //server/... + } else { + #error "normjoin non-UNC dos device path '$path' not supported" + #first segment after //./ or //?/ represents the volume or drive. + #not applicable to unix - but unlikely to conflict with a genuine usecase there (review) + #we should pass through and stop navigation below //./vol + #!!! + #not anomaly in tcl (continues in tcl9) + #file exists //./c:/test -> 0 + #file exists //?/c:/test -> 1 + #file exists //./BootPartition/Windows -> 1 + #file exists //?/BootPartition/Windows -> 0 + set is_nonunc_dosdevice 1 + } + } + + if {$is_nonunc_dosdevice} { + #dosdevice prefix //./ or //?/ - preserve it (without trailing slash which will be put back in with join) + set prefix [string range $path 0 2] + set tail [string range $path 4 end] + set tailparts [split $tail /] + set parts [concat [list $prefix] $tailparts] + set rootindex 1 ;#disallow backtrack below //./ + } else { + #note use of ordinary ::split vs file split is deliberate. + if {$doubleslash1_posn == 0} { + #this is handled differently on different platforms as far as 'file split' is concerned. + #e.g for file split //sharehost/share/path/etc + #e.g on windows: -> //sharehost/share path + #e.g on freebsd: -> / sharehost share path etc + #however..also on windows: file split //sharehost -> / sharehost + #normalize by dropping leading slash before split - and then treating first 2 segments as a root + #set parts [file split [string range $path 1 end]] + set parts [split $path /] + #assert parts here has {} {} as first 2 entries + set rootindex 2 + #currently prefer can backtrack to the //zipfs:/ scheme (below the mountpoint - to browse other mounts) + #alternative handling for //zipfs:/path - don't go below mountpoint + #but we can't determine just from string if mountpoint is direct subpath or a lower one e.g //zipfs:/arbitraryname/actualmountpoint + #review - more generally //:/path ? + #todo - make an option for zipfs and others to determine the 'base' + #if {"zipfs:" eq [lindex $parts 2]} { + # set rootindex 3 + #} + } else { + #path may or may not begin with a single slash here. + #treat same on unix and windows + set rootindex 0 + #set parts [file split $path] + set parts [::split $path /] + #e.g /a/b/c -> {} a b c + #or relative path a/b/c -> a b c + #or c:/a/b/c -> c: a b c + if {[string match *: [lindex $parts 0]]} { + if {[lindex $parts 1] eq ""} { + #scheme://x splits to scheme: {} x + set parts [concat [list [lindex $parts 0]/] [lrange $parts 2 end]] + #e.g {scheme:/ x} + set rootindex 1 ;#disallow below first element of scheme + } else { + set rootindex 0 + } + } elseif {[lindex $parts 0] ne ""} { + #relpath a/b/c + set parts [linsert $parts 0 .] + set rootindex 0 + #allow backtracking arbitrarily for leading .. entries - simplify where possible + #also need to stop possible conversion to absolute path + set is_relpath 1 + } + } + } + set baseparts [lrange $parts 0 $rootindex] ;#base below which we can't retreat via ".." + #puts stderr "-->baseparts:$baseparts" + #ensure that if our rootindex already spans a dotted segment (after the first one) we remove it + #must maintain initial . for relpaths to stop them converting to absolute via backtrack + # + set finalparts [list [lindex $baseparts 0]] + foreach b [lrange $baseparts 1 end] { + if {$b ni {. ..}} { + lappend finalparts $b + } + } + set baselen [expr {$rootindex + 1}] + if {$is_relpath} { + set i [expr {$rootindex+1}] + foreach p [lrange $parts $i end] { + switch -exact -- $p { + . - "" {} + .. { + switch -exact -- [lindex $finalparts end] { + . - .. { + lappend finalparts .. + } + default { + lpop finalparts + } + } + } + default { + lappend finalparts $p + } + } + incr i + } + } else { + foreach p [lrange $parts $rootindex+1 end] { + if {[llength $finalparts] <= $baselen} { + if {$p ni {. .. ""}} { + lappend finalparts $p + } + } else { + switch -exact -- $p { + . - "" {} + .. { + lpop finalparts ;#uses punk::lib::compat::lpop if on < 8.7 + } + default { + lappend finalparts $p + } + } + } + } + } + puts "==>finalparts: '$finalparts'" + # using join - {"" "" server share} -> //server/share and {a b} -> a/b + if {[llength $finalparts] == 1 && [lindex $finalparts 0] eq ""} { + #backtracking on unix-style path can end up with empty string as only member of finalparts + #e.g /x/.. + return / + } + set result [::join $finalparts /] + #normalize volumes and mountschemes to have trailing slash if no subpath + #e.g c: -> c:/ + #//zipfs: -> //zipfs:/ + if {[set lastchar [string index $result end]] eq ":"} { + if {$result eq "//zipfs:"} { + set result "//zipfs:/" + } else { + if {[string first / $result] < 0} { + set result $result/ + } + } + } elseif {[string match //* $result]} { + if {![punk::winpath::is_dos_device_path $result]} { + #server + set tail [string range $result 2 end] + set tailparts [split $tail /] + if {[llength $tailparts] <=1} { + #empty // or //servername + append result / + } + } + } elseif {[llength $finalparts] == 2} { + if {[string range [lindex $finalparts 0] end-1 end] eq ":/"} { + #e.g https://server/ -> finalparts {https:/ server} + #e.g https:/// -> finalparts {https:/ ""} + #scheme based path should always return trailing slash after server component - even if server component empty. + lappend finalparts "" ;#force trailing / + return [join $finalparts /] + } + } + return $result + } + + proc trim_final_slash {str} { + if {[string index $str end] eq "/"} { + return [string range $str 0 end-1] + } + return $str + } + + + #x-platform - punk::path::pathtype - can be used in safe interps - different concept of pathtypes to 'file pathtype' + # - no volumerelative + # - no lookup of file volumes (volume is a windows concept - but with //zipfs:/ somewhat applicable to other platforms) + # - /* as absolute (covers also //zipfs:/ (volume), //server , //./etc , //./UNC) + # - xxx:// as absolute (scheme) + # - xxx:/ or x:/ as absolute + # - x: xxx: -> as absolute (volume-basic or volume-extended) + + #note also on windows - legacy name for COM devices + # COM1 = COM1: + # //./COM1 ?? review + + proc pathtype {str} { + set str [string map "\\\\ /" $str] + if {[string index $str 0] eq "/"} { + #todo - look for //xxx:/ prefix (generalisation of //zipfs:/) as a 'volume' specifically {volume mount} ?? - review + # look for //server prefix as {absolute server} + # look for //./UNC/server or //?/UNC/server as {absolute server UNC} ? + # look for //./ as {absolute dosdevice} + return absolute + } + + #only firstsegment with single colon at last position (after some non empty string) counts as volume or scheme - review + #e.g a:b:/.. or a::/.. or :/.. is not treated as volume/scheme whereas ab:/ is. + set firstslash [string first / $str] + if {$firstslash == -1} { + set firstsegment $str + } else { + set firstsegment [string range $str 0 $firstslash-1] + } + if {[set firstc [string first : $firstsegment]] > 0} { + set lhs_firstsegment [string range $firstsegment 0 $firstc-1] + set rhs_firstsegment [string range $firstsegment $firstc+1 end] ;#exclude a:b/ etc + if {$rhs_firstsegment eq ""} { + set rhs_entire_path [string range $str $firstc+1 end] + #assert lhs_firstsegment not empty since firstc > 0 + #count following / sequence + set i 0 + set slashes_after_firstsegment "" ;#run of slashes *directly* following first segment + while {$i < [string length $rhs_entire_path]} { + if {[string index $rhs_entire_path $i] eq "/"} { + append slashes_after_firstsegment / + } else { + break + } + incr i + } + switch -exact -- $slashes_after_firstsegment { + "" - / { + if {[string length $lhs_firstsegment] == 1} { + return {absolute volume basic} + } else { + return {absolute volume extended} + } + } + default { + #2 or more / + #this will return 'scheme' even for c:// - even though that may look like a windows volume - review + return {absolute scheme} + } + } + } + } + #assert first element of any return has been absolute or relative + return relative + } + + + proc plain {str} { + set str [string map "\\\\ /" $str] + set pathinfo [punk::path::pathtype $str] + if {[lindex $pathinfo 0] eq "relative" && ![string match ./* $str]} { + set str ./$str + } + if {[string index $str end] eq "/"} { + if {[string map {/ ""} $str] eq ""} { + #all slash segment + return $str + } else { + if {[lindex $pathinfo 1] ni {volume scheme}} { + return [string range $str 0 end-1] + } + } + } + return $str + } + #purely string based - no reference to filesystem knowledge + #unix-style forward slash only + proc plainjoin {args} { + set args [lmap a $args {string map "\\\\ /" $a}] + #if {[llength $args] == 1} { + # return [lindex $args 0] + #} + set out "" + foreach a $args { + if {![string length $out]} { + append out [plain $a] + } else { + set a [plain $a] + if {[string map {/ ""} $out] eq ""} { + set out [string range $out 0 end-1] + } + + if {[string map {/ ""} $a] eq ""} { + #all / segment + append out [string range $a 0 end-1] + } else { + if {[string length $a] > 2 && [string match "./*" $a]} { + set a [string range $a 2 end] + } + if {[string index $out end] eq "/"} { + append out $a + } else { + append out / $a + } + } + } + } + return $out + } + proc plainjoin1 {args} { + if {[llength $args] == 1} { + return [lindex $args 0] + } + set out [trim_final_slash [lindex $args 0]] + foreach a [lrange $args 1 end] { + set a [trim_final_slash $a] + append out / $a + } + return $out + } + + #intention? + #proc filepath_dotted_dirname {path} { + #} + + proc strip_prefixdepth {path prefix} { + if {$prefix eq ""} { + return [norm $path] + } + return [file join \ + {*}[lrange \ + [file split [norm $path]] \ + [llength [file split [norm $prefix]]] \ + end]] + } proc pathglob_as_re {pathglob} { #*** !doctools diff --git a/src/bootsupport/modules/punk/repo-0.1.1.tm b/src/bootsupport/modules/punk/repo-0.1.1.tm index ee2384b4..2cb5fd1d 100644 --- a/src/bootsupport/modules/punk/repo-0.1.1.tm +++ b/src/bootsupport/modules/punk/repo-0.1.1.tm @@ -134,13 +134,30 @@ namespace eval punk::repo { } interp alias "" fossil "" punk::repo::fossil_proxy + # --- + # Calling auto_execok on an external tool can be too slow to do during package load (e.g could be 150ms) + #safe interps can't call auto_execok #At least let them load the package even though much of it may be unusable depending on the safe configuration - catch { - if {[auto_execok fossil] ne ""} { - interp alias "" FOSSIL "" {*}[auto_execok fossil] - } + #catch { + # if {[auto_execok fossil] ne ""} { + # interp alias "" FOSSIL "" {*}[auto_execok fossil] + # } + #} + # --- + # ---------- + # + + #uppercase FOSSIL to bypass fossil as alias to fossil_proxy + proc establish_FOSSIL {args} { + if {![info exists ::auto_execs(FOSSIL)]} { + set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp + } + interp alias "" FOSSIL "" ;#delete establishment alias + FOSSIL {*}$args } + interp alias "" FOSSIL "" punk::repo::establish_FOSSIL + # ---------- proc askuser {question} { if {![catch {package require punk::lib}]} { @@ -370,7 +387,16 @@ namespace eval punk::repo { } if {$repodir eq ""} { - error "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "args: $args" + dict set resultdict revision {} + dict set resultdict revision_iso8601 {} + dict set resultdict paths {} + dict set resultdict ahead "" + dict set resultdict behind "" + dict set resultdict error {reason "no_repo_found"} + dict set resultdict repotype none + return $resultdict } set subpath [punk::path::relative $repodir $abspath] if {$subpath eq "."} { @@ -644,6 +670,16 @@ namespace eval punk::repo { set path_count_fields [list unchanged changed new missing extra] set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601] set dresult [dict create] + if {[dict exists $repostate error]} { + foreach f $state_fields { + dict set dresult $f "" + } + foreach f $path_count_fields { + dict set dresult $f "" + } + #todo? + return $dresult + } foreach f $state_fields { dict set dresult $f [dict get $repostate $f] } diff --git a/src/bootsupport/modules/punk/winpath-0.1.0.tm b/src/bootsupport/modules/punk/winpath-0.1.0.tm index b30133ba..6de745a8 100644 --- a/src/bootsupport/modules/punk/winpath-0.1.0.tm +++ b/src/bootsupport/modules/punk/winpath-0.1.0.tm @@ -30,7 +30,7 @@ namespace eval punk::winpath { #\\servername\share etc or \\?\UNC\servername\share etc. proc is_unc_path {path} { - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway) if {[string first "//" $strcopy_path] == 0} { #check for "Dos device path" syntax @@ -77,7 +77,7 @@ namespace eval punk::winpath { #dos device path syntax allows windows api to acces extended-length paths and filenames with illegal path characters such as trailing dots or whitespace #(can exist on server shares and on NTFS - but standard apps can't access without dos device syntax) proc is_dos_device_path {path} { - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway) if {[string range $strcopy_path 0 3] in {//?/ //./}} { return 1 @@ -87,7 +87,7 @@ namespace eval punk::winpath { } proc strip_dos_device_prefix {path} { #it's unlikely to be valid to strip only //?/ from a //?/UNC path so check for it here and diver to strip that. - #(review.. or raise error because a //?/UNC path isn't *strictly* a UNC path? ) + #(review.. or raise error because a //?/UNC path isn't an ordinary dos device path? ) if {[is_unc_path $path]} { return [strip_unc_path_prefix $path] } @@ -98,18 +98,18 @@ namespace eval punk::winpath { } } proc strip_unc_path_prefix {path} { - if {[is_unc_path $path]} { - #//?/UNC/server/etc - set strcopy_path [punk::objclone $path] - set trimmedpath [string range $strcopy_path 7 end] - file pathtype $trimmedpath ;#shimmer it to path rep - return $trimmedpath - } elseif {is_unc_path_plain $path} { + if {[is_unc_path_plain $path]} { #plain unc //server - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set trimmedpath [string range $strcopy_path 2 end] file pathtype $trimmedpath return $trimmedpath + } elseif {is_unc_path $path} { + #//?/UNC/server/subpath or //./UNC/server/subpath + set strcopy_path [punk::winpath::system::objclone $path] + set trimmedpath [string range $strcopy_path 7 end] + file pathtype $trimmedpath ;#shimmer it to path rep + return $trimmedpath } else { return $path } @@ -153,7 +153,7 @@ namespace eval punk::winpath { error $err } - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] #Note: path could still have leading double slash if it is a Dos device path: e.g. //?/c:/etc @@ -225,27 +225,124 @@ namespace eval punk::winpath { return 0 } - proc test_ntfs_tunneling {f1 f2 args} { - file mkdir $f1 - puts stderr "waiting 15secs..." - after 5000 {puts -nonewline stderr .} - after 5000 {puts -nonewline stderr .} - after 5000 {puts -nonewline stderr .} - after 500 {puts stderr \n} - file mkdir $f2 - puts stdout "$f1 [file stat $f1]" - puts stdout "$f2 [file stat $f2]" - file delete $f1 - puts stdout "renaming $f2 to $f1" - file rename $f2 $f1 - puts stdout "$f1 [file stat $f1]" - + proc shortname {path} { + set shortname "NA" + if {[catch { + set shortname [dict get [file attributes $path] -shortname] + } errM]} { + puts stderr "Failed to get shortname for '$path'" + } + return $shortname + } + proc test_ntfs_tunneling {prefix args} { + puts stderr "We are looking for whether any of the final $prefix files or dirs took over the ctime attribute of the original $prefix files or dirs" + puts stderr "We expect the ino values to get potentially reassigned depending on order of deletion/creation so matches are coincidental and not material" + puts stderr "The shortnames are similarly allocated as they come - so presumably match by coincidence" + puts stderr "However - if we record a file's shortname, then delete it. Recreating it by shortname within the tunneling timeframe will magically reassociate the longname" + puts stderr "use test_ntfs_tunneling2 to test shortname tunneling" + file mkdir $prefix-dir-rename + file mkdir $prefix-dir-recreate + set fd [open $prefix-file-recreate.txt w] + puts $fd "original for recreate" + close $fd + set fd [open $prefix-file-rename.txt w] + puts $fd "original for rename" + close $fd + puts stdout "ORIGINAL files/dirs" + puts stdout "$prefix-dir-rename [file stat $prefix-dir-rename] " + puts stdout "$prefix-dir-recreate [file stat $prefix-dir-recreate]" + puts stdout "$prefix-file-recreate.txt [file stat $prefix-file-recreate.txt] short:[shortname $prefix-file-recreate.txt]" + puts stdout "$prefix-file-rename.txt [file stat $prefix-file-rename.txt] short:[shortname $prefix-file-rename.txt]" + puts stderr "waiting 10secs (to have discernable ctime differences)" + after 5000 + puts -nonewline stderr . + after 5000 + puts -nonewline stderr . + after 500 + + #-- + #seems to make no diff whether created or copied - no tunneling seen with dirs + #file mkdir $prefix-dir-rename-temp + file copy $prefix-dir-rename $prefix-dir-rename-temp + #-- + puts stderr \n + puts stdout "$prefix-dir-rename-temp [file stat $prefix-dir-rename-temp] (temp to rename into place)" + puts stderr "deleting $prefix-dir-rename" + file delete $prefix-dir-rename + puts stdout "renaming $prefix-dir-rename-temp to $prefix-dir-rename" + file rename $prefix-dir-rename-temp $prefix-dir-rename + + puts stderr "deleting $prefix-dir-recreate" + file delete $prefix-dir-recreate + puts stdout "re-creating $prefix-dir-recreate" + file mkdir $prefix-dir-recreate + + puts stderr "deleting $prefix-file-recreate.txt" + file delete $prefix-file-recreate.txt + puts stderr "Recreating $prefix-file-recreate.txt" + set fd [open $prefix-file-recreate.txt w] + puts $fd "replacement" + close $fd + + puts stderr "copying $prefix-file-rename.txt to $prefix-file-rename-temp.txt" + file copy $prefix-file-rename.txt $prefix-file-rename-temp.txt + puts stdout "$prefix-file-rename-temp.txt [file stat $prefix-file-rename-temp.txt] short:[shortname $prefix-file-rename-temp.txt] (status of initial temp copy)" + puts stderr "modifying temp copy before deletion of original.. (append)" + set fd [open $prefix-file-rename-temp.txt a] + puts $fd "added to file" + close $fd + puts stdout "$prefix-file-rename-temp.txt [file stat $prefix-file-rename-temp.txt] short:[shortname $prefix-file-rename-temp.txt] (status of appended temp copy)" + puts stderr "deleting $prefix-file-rename.txt" + file delete $prefix-file-rename.txt + puts stderr "renaming temp file $prefix-file-rename-temp.txt to original $prefix-file-rename.txt" + file rename $prefix-file-rename-temp.txt $prefix-file-rename.txt + + puts stdout "Final files/dirs" + puts stdout "$prefix-dir-rename [file stat $prefix-dir-rename]" + puts stdout "$prefix-dir-recreate [file stat $prefix-dir-recreate]" + puts stdout "$prefix-file-recreate.txt [file stat $prefix-file-recreate.txt] short:[shortname $prefix-file-recreate.txt]" + puts stdout "$prefix-file-rename.txt [file stat $prefix-file-rename.txt] short:[shortname $prefix-file-rename.txt]" + } + proc test_ntfs_tunneling2 {prefix {waitms 15000}} { + #shortname -> longname tunneling + puts stderr "Tunneling only happens if we delete via shortname? review" + set f1 $prefix-longname-file1.txt + set f2 $prefix-longname-file2.txt + + set fd [open $f1 w];close $fd + set shortname1 [shortname $f1] + puts stderr "longname:$f1 has shortname:$shortname1" + set fd [open $f2 w];close $fd + set shortname2 [shortname $f2] + puts stderr "longname:$f2 has shortname:$shortname2" + + puts stderr "deleting $f1 via name $shortname1" + file delete $shortname1 + puts stdout "immediately recreating $shortname1 - should retain longname $f1 via tunneling" + set fd [open $shortname1 w];close $fd + set f1_exists [file exists $f1] + puts stdout "file exists $f1 = $f1_exists" + + puts stderr "deleting $f2 via name $shortname2" + file delete $shortname2 + puts stderr "Waiting [expr {$waitms / 1000}] seconds.. (standard tunneling timeframe is 15 seconds if registry hasn't been tweaked)" + after $waitms + puts stdout "recreating $shortname2 after wait of $waitms ms - longname lost?" + set fd [open $shortname2 w];close $fd + set f2_exists [file exists $f2] + puts stdout "file exists $f2 = $f2_exists" + + puts stdout -done- } - } - +namespace eval punk::winpath::system { + #get a copy of the item without affecting internal rep + proc objclone {obj} { + append obj2 $obj {} + } +} diff --git a/src/bootsupport/modules/textblock-0.1.1.tm b/src/bootsupport/modules/textblock-0.1.1.tm index 94af61ba..5d127a38 100644 --- a/src/bootsupport/modules/textblock-0.1.1.tm +++ b/src/bootsupport/modules/textblock-0.1.1.tm @@ -12,25 +12,97 @@ # Meta license # @@ Meta End +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_textblock 0 0.1.1] +#[copyright "2024"] +#[titledesc {punk textblock functions}] [comment {-- Name section and table of contents description --}] +#[moddesc {punk textblock}] [comment {-- Description at end of page heading --}] +#[require textblock] +#[keywords module utility lib] +#[description] +#[para] Ansi-aware terminal textblock manipulation + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[section Overview] +#[para] overview of textblock +#[subsection Concepts] +#[para] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements -##e.g package require frobz +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by textblock +#[list_begin itemized] + +#*** !doctools +#[item] [package {Tcl 8.6-}] +#[item] [package {punk::args}] +#[item] [package {punk::char}] +#[item] [package {punk::ansi}] +#[item] [package {punk::lib}] +#[item] [package {overtype}] +#[item] [package {term::ansi::code::macros}] +#[item] [package {textutil}] + +## Requirements +package require Tcl 8.6- package require punk::args package require punk::char package require punk::ansi package require punk::lib catch {package require patternpunk} package require overtype + +#safebase interps as at 2024-08 can't access deeper paths - even though they are below the supposed safe list. package require term::ansi::code::macros ;#required for frame if old ansi g0 used - review - make package optional? package require textutil + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + tcl::namespace::eval textblock { #review - what about ansi off in punk::console? tcl::namespace::import ::punk::ansi::a ::punk::ansi::a+ tcl::namespace::export block frame frame_cache framedef frametypes gcross height width widthtopline join join_basic list_as_table pad testblock - + variable use_md5 ;#framecache + set use_md5 1 + if {[catch {package require md5}]} { + set use_md5 0 + } + proc use_md5 {{yes_no ""}} { + variable use_md5 + if {$yes_no eq ""} { + return $use_md5 + } + if {![string is boolean -strict $yes_no]} { + error "textblock::use_md5 requires a boolean (or empty string to query)" + } + if {$yes_no} { + package require md5 + set use_md5 1 + } else { + set use_md5 0 + } + return $use_md5 + } tcl::namespace::eval class { variable opts_table_defaults set opts_table_defaults [tcl::dict::create\ @@ -228,6 +300,7 @@ tcl::namespace::eval textblock { } return $map } + if {[tcl::info::commands [tcl::namespace::current]::table] eq ""} { #*** !doctools #[subsection {Namespace textblock::class}] @@ -249,7 +322,7 @@ tcl::namespace::eval textblock { oo::class create [tcl::namespace::current]::table [tcl::string::map [list %topt_keys% $topt_keys %topt_switchkeys% $switch_keys_valid_topts %copt_keys% $copt_keys %copt_switchkeys% $switch_keys_valid_copts] { #*** !doctools - #[enum] CLASS [class interface_caphandler.registry] + #[enum] CLASS [class textblock::class::table] #[list_begin definitions] # [para] [emph METHODS] variable o_opts_table ;#options as configured by user (with exception of -ansireset) @@ -3986,7 +4059,7 @@ tcl::namespace::eval textblock { if append is chosen the new values will always start at the first column" -columns -default "" -type integer -help "Number of table columns Will default to 2 if not using an existing -table object" - *values + *values -min 0 -max 1 datalist -default {} -help "flat list of table cell values which will be wrapped based on -columns value" }] $args] set opts [dict get $argd opts] @@ -4337,6 +4410,14 @@ tcl::namespace::eval textblock { return [tcl::dict::create width $width height $height] ;#maintain order in 'image processing' standard width then height - caller may use lassign [tcl::dict::values [blocksize ]] width height } + proc size_as_opts {textblock} { + set sz [size $textblock] + return [dict create -width [dict get $sz width] -height [dict get $sz height]] + } + proc size_as_list {textblock} { + set sz [size $textblock] + return [list [dict get $sz width] [dict get $sz height]] + } #must be able to handle block as string with or without newlines #if no newlines - attempt to treat as a list #must handle whitespace-only string,list elements, and/or lines. @@ -5061,6 +5142,7 @@ tcl::namespace::eval textblock { [punk::lib::list_as_lines -- [lrepeat 8 " | "]] } proc table {args} { + #todo - use punk::args upvar ::textblock::class::opts_table_defaults toptdefaults set defaults [tcl::dict::create\ -rows [list]\ @@ -5112,7 +5194,7 @@ tcl::namespace::eval textblock { } variable frametypes - set frametypes [list light heavy arc double block block1 block2 ascii altg] + set frametypes [list light heavy arc double block block1 block2 block2hack ascii altg] #class::table needs to be able to determine valid frametypes proc frametypes {} { variable frametypes @@ -5121,7 +5203,7 @@ tcl::namespace::eval textblock { proc frametype {f} { #set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] switch -- $f { - light - heavy - arc - double - block - block1 - block2 - ascii - altg { + light - heavy - arc - double - block - block1 - block2 - block2hack - ascii - altg { return [tcl::dict::create category predefined type $f] } default { @@ -5142,7 +5224,7 @@ tcl::namespace::eval textblock { set is_custom_dict_ok 0 } if {!$is_custom_dict_ok} { - error "frame option -type must be one of known types: $textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" + error "frame option -type must be one of known types: $::textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" } set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] set custom_frame [tcl::dict::merge $default_custom $f] @@ -6252,9 +6334,12 @@ tcl::namespace::eval textblock { set vlr \u2595 ;# right one eighth block set vll \u258f ;# left one eighth block + #some terminals (on windows as at 2024) miscount width of these single-width blocks internally + #resulting in extra spacing that is sometimes well removed from the character itself (e.g at next ansi reset) + #This was fixed in windows-terminal based systems (2021) but persists in others. + #https://github.com/microsoft/terminal/issues/11694 set tlc \U1fb7d ;#legacy block set trc \U1fb7e ;#legacy block - set blc \U1fb7c ;#legacy block set brc \U1fb7f ;#legacy block @@ -6265,6 +6350,42 @@ tcl::namespace::eval textblock { set vlrj $vlr } + block2hack { + #the resultant table will have text appear towards top of each box + #with 'legacy' computing unicode block - hopefully these become more widely supported - as they are useful and fill in some gaps + set hlt \u2594 ;# upper one eighth block + set hlb \u2581 ;# lower one eighth block + set vlr \u2595 ;# right one eighth block + set vll \u258f ;# left one eighth block + + #see comments in block2 regarding the problems in some terminals that this *may* hack around to some extent. + #the caller probably only needs block2hack if block2 doesn't work + + #1) + #review - this hack looks sort of promising - but overtype::renderline needs fixing ? + #set tlc \U1fb7d\b ;#legacy block + #set trc \U1fb7e\b ;#legacy block + #set blc \U1fb7c\b ;#legacy block + #set brc \U1fb7f\b ;#legacy block + + #2) - works on cmd.exe and some others + # a 'privacy message' is 'probably' also not supported on the old terminal but is on newer ones + #known exception - conemu on windows - displays junk for various ansi codes - (and slow terminal anyway) + #this hack has a reasonable chance of working + #except that the punk overtype library does recognise PMs + #A single backspace however is an unlikely and generally unuseful PM - so there is a corresponding hack in the renderline system to pass this PM through! + #ugly - in that we don't know the application specifics of what the PM data contains and where it's going. + set tlc \U1fb7d\x1b^\b\x1b\\ ;#legacy block + set trc \U1fb7e\x1b^\b\x1b\\ ;#legacy block + set blc \U1fb7c\x1b^\b\x1b\\ ;#legacy block + set brc \U1fb7f\x1b^\b\x1b\\ ;#legacy block + + #horizontal and vertical bar joins + set hltj $hlt + set hlbj $hlb + set vllj $vll + set vlrj $vlr + } block { set hlt \u2580 ;#upper half set hlb \u2584 ;#lower half @@ -6286,7 +6407,7 @@ tcl::namespace::eval textblock { set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] ;#only default the general types - these form defaults for more specific types if they're missing if {[llength $f] % 2 != 0} { #todo - retrieve usage from punk::args - error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $textblock::frametypes and does not appear to be a dictionary for a custom frametype" + error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $::textblock::frametypes and does not appear to be a dictionary for a custom frametype" } #unknown order of keys specified by user - validate before creating vars as we need more general elements to be available as defaults dict for {k v} $f { @@ -6388,7 +6509,7 @@ tcl::namespace::eval textblock { #options before content argument - which is allowed to be absent - #frame performance (noticeable with complex tables even of modest size) is improved significantly by frame_cache - but is still (2024) a fairly expensive operation. + #frame performance (noticeable with complex tables even of modest size) is improved somewhat by frame_cache - but is still (2024) a fairly expensive operation. # #consider if we can use -sticky nsew instead of -blockalign (as per Tk grid -sticky option) # This would require some sort of expand equivalent e.g for -sticky ew or -sticky ns - for which we have to decide a meaning for text.. e.g ansi padding? @@ -6397,6 +6518,7 @@ tcl::namespace::eval textblock { # - but we would need to maintain support for the rendered-string based operations too. proc frame {args} { variable frametypes + variable use_md5 #counterintuitively - in-proc dict create each time is generally slightly faster than linked namespace var set opts [tcl::dict::create\ @@ -6416,7 +6538,11 @@ tcl::namespace::eval textblock { -ellipsis 1\ -usecache 1\ -buildcache 1\ + -pad 1\ + -crm_mode 0\ ] + #-pad 1 is default so that simple 'textblock::frame "[a+ Red]a \nbbb[a]" extends the bg colour on the short ragged lines (and empty lines) + # for ansi art - -pad 0 is likely to be preferable set expect_optval 0 set argposn 0 @@ -6455,7 +6581,12 @@ tcl::namespace::eval textblock { #use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache foreach {k v} $arglist { switch -- $k { - -etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache { + -etabs - -type - -boxlimits - -boxmap - -joins + - -title - -subtitle - -width - -height + - -ansiborder - -ansibase + - -blockalign - -textalign - -ellipsis + - -crm_mode + - -usecache - -buildcache - -pad { tcl::dict::set opts $k $v } default { @@ -6471,11 +6602,13 @@ tcl::namespace::eval textblock { set opt_boxmap [tcl::dict::get $opts -boxmap] set opt_usecache [tcl::dict::get $opts -usecache] set opt_buildcache [tcl::dict::get $opts -buildcache] + set opt_pad [tcl::dict::get $opts -pad] + set opt_crm_mode [tcl::dict::get $opts -crm_mode] set usecache $opt_usecache ;#may need to override set buildcache $opt_buildcache set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] - set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable + set known_frametypes $frametypes ;# light, heavey etc as defined in the ::textblock::frametypes variable set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] lassign [textblock::frametype $opt_type] _cat category _type ftype @@ -6614,6 +6747,19 @@ tcl::namespace::eval textblock { } } set contents [tcl::string::map [list \r\n \n] $contents] + if {$opt_crm_mode} { + if {$opt_height eq ""} { + set h [textblock::height $contents] + } else { + set h [expr {$opt_height -2}] + } + if {$opt_width eq ""} { + set w [textblock::width $contents] + } else { + set w [expr {$opt_width -2}] + } + set contents [overtype::renderspace -crm_mode 1 -wrap 1 -width $w -height $h "" $contents] + } set actual_contentwidth [textblock::width $contents] ;#length of longest line in contents (contents can be ragged) set actual_contentheight [textblock::height $contents] } else { @@ -6652,9 +6798,14 @@ tcl::namespace::eval textblock { #review - custom frame affects frame_inner_width - exclude from caching? #set cache_key [concat $arglist $frame_inner_width $frame_inner_height] set hashables [concat $arglist $frame_inner_width $frame_inner_height] - package require md5 - #set hash $hashables - set hash [md5::md5 -hex [encoding convertto utf-8 $hashables]] ;#need fast and unique to content - not cryptographic - review + + if {$use_md5} { + #package require md5 ;#already required at package load + set hash [md5::md5 -hex [encoding convertto utf-8 $hashables]] ;#need fast and unique to content - not cryptographic - review + } else { + set hash $hashables + } + set cache_key "$hash-$frame_inner_width-$frame_inner_height-actualcontentwidth:$actual_contentwidth" #should be in a unicode private range different to that used in table construction #e.g BMP PUA U+E000 -> U+F8FF - although this is commonly used for example by nerdfonts @@ -7057,15 +7208,22 @@ tcl::namespace::eval textblock { append contents [::join [lrepeat $diff \n] ""] } - set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) - set paddedwidth [textblock::widthtopline $paddedcontents] - - #review - horizontal truncation - if {$paddedwidth > $cache_patternwidth} { - set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + if {$opt_pad} { + set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) + set paddedwidth [textblock::widthtopline $paddedcontents] + #review - horizontal truncation + if {$paddedwidth > $cache_patternwidth} { + set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + } + #important to supply end of opts -- to textblock::join - particularly here with arbitrary data + set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays + } else { + set cwidth [textblock::width $contents] + if {$cwidth > $cache_patternwidth} { + set contents [overtype::renderspace -width $cache_patternwidth "" $contents] + } + set contentblock [textblock::join -- $contents] } - #important to supply end of opts -- to textblock::join - particularly here with arbitrary data - set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays set tlines [split $template \n] @@ -7183,7 +7341,6 @@ tcl::namespace::eval textblock { #fastest to do row first then columns - because textblock::join must do line by line if {$crosscount > 1} { - package require textblock set row [textblock::join -- {*}[lrepeat $crosscount $onecross]] set rows [lrepeat $crosscount $row] set out [::join $rows \n] @@ -7223,4 +7380,8 @@ package provide textblock [tcl::namespace::eval textblock { variable version set version 0.1.1 }] -return \ No newline at end of file +return + +#*** !doctools +#[manpage_end] + diff --git a/src/make.tcl b/src/make.tcl index 1cf07c5b..9edd90b0 100644 --- a/src/make.tcl +++ b/src/make.tcl @@ -1212,8 +1212,9 @@ foreach vfstail $vfs_tails { set rtmountpoint //zipfs:/rtmounts/$runtime_fullname set changed_unchanged [$vfs_event targetset_source_changes] + set vfs_or_runtime_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]}] - if {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]} { + if {$vfs_or_runtime_changed} { #source .vfs folder has changes $vfs_event targetset_started # -- --- --- --- --- --- @@ -1283,6 +1284,7 @@ foreach vfstail $vfs_tails { puts stderr "RUNTIME capabilities unknown. Unsure if zip supported. trying anyway.." } } + #note - as at 2024-08 - there is some discussion about the interface to mkimg - it is considered unstable (may change to -option value syntax) puts stderr "calling: tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs \"\" $buildfolder/build_$runtime_fullname" tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs "" $buildfolder/build_$runtime_fullname } result ]} { @@ -1352,9 +1354,10 @@ foreach vfstail $vfs_tails { if {![catch { exec $pscmd | grep $targetkit } still_running]} { - - puts stdout "found $targetkit instances still running\n" + set still_running_lines [split [string trim $still_running] \n] + puts stdout "found ([llength $still_running_lines]) $targetkit instances still running\n" set count_killed 0 + set num_to_kill [llength $still_running_lines] foreach ln [split $still_running \n] { puts stdout " $ln" @@ -1387,9 +1390,6 @@ foreach vfstail $vfs_tails { #review - *no running instance* works with windows taskkill - "*No such process*" works with kill -9 on FreeBSD and linux - other platforms? if {![string match "*no running instance*" $errMsg] && ![string match "*No such process*" $errMsg]} { lappend failed_kits [list kit $targetkit reason "could not kill running process for $targetkit (using '$killcmd')"] - $vfs_event targetset_end FAILED - $vfs_event destroy - $vfs_installer destroy continue } } else { @@ -1397,10 +1397,15 @@ foreach vfstail $vfs_tails { incr count_killed } } - if {$count_killed > 0} { - puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" - after 1000 + if {$count_killed < $num_to_kill} { + $vfs_event targetset_end FAILED + $vfs_event destroy + $vfs_installer destroy + continue } + + puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" + after 1000 } else { puts stderr "Ok.. no running '$targetkit' processes found" } @@ -1426,22 +1431,35 @@ foreach vfstail $vfs_tails { # -- --- --- --- --- --- $vfs_event targetset_end OK + } else { + set skipped_vfs_build 1 + puts stderr "." + puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" + $vfs_event targetset_end SKIPPED + } + $vfs_event destroy + $vfs_installer destroy - after 200 - set deployment_folder [file dirname $sourcefolder]/bin - file mkdir $deployment_folder + after 200 + set deployment_folder [file dirname $sourcefolder]/bin + file mkdir $deployment_folder - # -- ---------- - set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] - $bin_installer set_source_target $buildfolder $deployment_folder - set bin_event [$bin_installer start_event {-make-step final_kit_install}] - $bin_event targetset_init INSTALL $deployment_folder/$targetkit - #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) - #set last_completion [$bin_event targetset_last_complete] - - $bin_event targetset_addsource $buildfolder/$targetkit - $bin_event targetset_started - # -- ---------- + # -- ---------- + set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] + $bin_installer set_source_target $buildfolder $deployment_folder + set bin_event [$bin_installer start_event {-make-step final_kit_install}] + $bin_event targetset_init INSTALL $deployment_folder/$targetkit + #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) + #set last_completion [$bin_event targetset_last_complete] + + $bin_event targetset_addsource $deployment_folder/$targetkit ;#add target as a source of metadata for change detection + $bin_event targetset_addsource $buildfolder/$targetkit + $bin_event targetset_started + # -- ---------- + + set changed_unchanged [$bin_event targetset_source_changes] + set built_or_installed_kit_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$bin_event get_targets_exist]] < [llength [$bin_event get_targets]]}] + if {$built_or_installed_kit_changed} { if {[file exists $deployment_folder/$targetkit]} { puts stderr "deleting existing deployed at $deployment_folder/$targetkit" @@ -1467,19 +1485,16 @@ foreach vfstail $vfs_tails { # -- ---------- $bin_event targetset_end OK # -- ---------- - $bin_event destroy - $bin_installer destroy - } else { - set skipped_vfs_build 1 + set skipped_kit_install 1 puts stderr "." - puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" - $vfs_event targetset_end SKIPPED + puts stdout "Skipping kit install for $targetkit with vfs $vfstail runtime $rtname - no change detected" + $bin_event targetset_end SKIPPED } + $bin_event destroy + $bin_installer destroy - $vfs_event destroy - $vfs_installer destroy } ;#end foreach targetkit } ;#end foreach rtname in runtimes diff --git a/src/modules/punk/ansi-999999.0a1.0.tm b/src/modules/punk/ansi-999999.0a1.0.tm index 747364c1..6ef15c9e 100644 --- a/src/modules/punk/ansi-999999.0a1.0.tm +++ b/src/modules/punk/ansi-999999.0a1.0.tm @@ -106,7 +106,7 @@ tcl::namespace::eval punk::ansi::class { #overflow is a different concept - perhaps not particularly congruent with the idea of the textblock as a mini terminal emulator. #overflow effectively auto-expands the block(terminal?) width #overflow and wrap both being true won't make sense unless we implement a max_overflow concept - set o_rendered [overtype::renderspace -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] + set o_rendered [overtype::renderspace -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] if {$cksum eq "not-done"} { #if dimensions changed - the checksum won't have been done set o_rendered_what [$o_ansistringobj checksum] @@ -129,7 +129,7 @@ tcl::namespace::eval punk::ansi::class { set o_dimensions $dimensions - set rendered [overtype::renderspace -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] + set rendered [overtype::renderspace -cp437 1 -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] return $rendered } method render_to_input_line {args} { @@ -176,7 +176,7 @@ tcl::namespace::eval punk::ansi::class { if {$opt_minus ne "0"} { set chunk [tcl::string::range $chunk 0 end-$opt_minus] } - set rendered [overtype::renderspace -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk] + set rendered [overtype::renderspace -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk] set marker "" for {set i 1} {$i <= $w} {incr i} { if {$i % 10 == 0} { @@ -514,11 +514,8 @@ tcl::namespace::eval punk::ansi { set encnames [encoding names] set encoding "" set dimensions "" - set test_mode 0 foreach a $args { - if {$a eq "test_mode"} { - set test_mode 1 - } elseif {$a in $encnames} { + if {$a in $encnames} { set encoding $a } else { if {[regexp {[0-9]+(?:x|X)[0-9]+} $a]} { @@ -553,28 +550,51 @@ tcl::namespace::eval punk::ansi { $obj destroy return $result } - proc example {} { + proc example {args} { + set base [punk::repo::find_project] + set default_ansibase [file join $base src/testansi] + + set argd [punk::args::get_dict [tstr -return string { + *proc -name punk::ansi::example -help "Display .ans image files in a grid that will fit in console + " + -colwidth -default 82 -help "Width of each column - default of 82 will fit a standard 80wide ansi image (when framed) + You can specify a narrower width to truncate images on the right side" + -folder -default "${$default_ansibase}" -help "Base folder for files if relative paths are used. + Defaults to /src/testansi - where projectbase is determined from current directory. + " + *values -min 0 -max -1 + files -default {belinda.ans bot.ans flower.ans fish.ans} -multiple true -help "List of filenames - leave empty to display 4 defaults" + }] $args] + set colwidth [dict get $argd opts -colwidth] + set ansibase [file normalize [dict get $argd opts -folder]] + set fnames [dict get $argd values files] + + #assumes fixed column widths e.g 80col images will fit in 82-width frames (common standard for old ansi art) (of arbitrary height) #todo - review dependency on punk::repo ? package require textblock package require punk::repo package require punk::console - set fnames [list belinda.ans bot.ans flower.ans fish.ans] - set base [punk::repo::find_project] - set ansibase [file join $base src/testansi] if {![file exists $ansibase]} { - puts stderr "Missing testansi folder at $base/src/testansi" + puts stderr "Missing folder at $ansibase" puts stderr "Ensure ansi test files exist: $fnames" #error "punk::ansi::example Cannot find example files" } - set missingbase [a+ yellow][textblock::block 80 23 ?][a] + set missingbase [a+ yellow][textblock::block [expr {$colwidth-2}] 23 ?][a] ;#assuming standard frame - subtract 2 for left/right borders set pics [list] foreach f $fnames { - if {![file exists $ansibase/$f]} { - set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$ansibase/$f[a]"] + if {[file pathtype $f] ne "absolute"} { + set filepath [file normalize $ansibase/$f] + } else { + set filepath [file normalize $f] + } + if {![file exists $filepath]} { + set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$f[a]"] lappend pics [tcl::dict::create filename $f pic $p status missing] } else { - set img [join [lines_as_list -line trimline -block trimtail [ansicat $ansibase/$f]] \n] + #set img [join [lines_as_list -line trimline -block trimtail [ansicat $filepath]] \n] + #-line trimline will wreck some images + set img [join [lines_as_list -block trimtail [ansicat $filepath]] \n] lappend pics [tcl::dict::create filename $f pic $img status ok] } } @@ -582,30 +602,73 @@ tcl::namespace::eval punk::ansi { set termsize [punk::console:::get_size] set margin 4 set freewidth [expr {[tcl::dict::get $termsize columns]-$margin}] - set per_row [expr {$freewidth / 80}] - - set rowlist [list] - set row [list] - set i 1 + set per_row [expr {$freewidth / $colwidth}] + + set rowlist [list] ;# { { } { } } + set heightlist [list] ;# { { } { } } + set maxheights [list] ;# { } + set row [list] ;#wip row + set rowh [list] ;#wip row img heights + set i 1 ;#track image index of whole pics list + set rowindex 0 foreach picinfo $pics { set subtitle "" if {[tcl::dict::get $picinfo status] ne "ok"} { set subtitle [tcl::dict::get $picinfo status] } set title [tcl::dict::get $picinfo filename] - lappend row [textblock::frame -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + set fr [textblock::frame -width $colwidth -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + # -- --- --- --- + #we need the max height of a row element to use join_basic instead of join below + # -- --- --- --- + set fr_height [textblock::height $fr] + lappend row $fr + lappend rowh $fr_height + + set rowmax [lindex $maxheights $rowindex] + if {$rowmax eq ""} { + #empty result means no maxheights entry for this row yet + set rowmax $fr_height + lappend maxheights $rowmax + } else { + if {$fr_height > $rowmax} { + set rowmax $fr_height + lset maxheights end $rowmax + } + } + # -- --- --- --- + if {$i % $per_row == 0} { lappend rowlist $row + lappend heightlist $rowh + incr rowindex set row [list] + set rowh [list] } elseif {$i == [llength $pics]} { lappend rowlist $row + lappend heightlist $rowh } incr i } - + #puts "--> maxheights: $maxheights" + #puts "--> heightlist: $heightlist" set result "" - foreach r $rowlist { - append result [textblock::join_basic -- {*}$r] \n + set rowindex 0 + set blankline [string repeat " " $colwidth] + foreach imgs $rowlist heights $heightlist { + set maxheight [lindex $maxheights $rowindex] + set adjusted_row [list] + foreach i $imgs h $heights { + if {$h < $maxheight} { + #add blank lines to bottom of shorter images so join_basic can be used. + #textblock::join of ragged-height images would work and remove the need for all the height calculation + #.. but it requires much more processing + append i [string repeat \n$blankline [expr {$maxheight - $h}]] + } + lappend adjusted_row $i + } + append result [textblock::join_basic -- {*}$adjusted_row] \n + incr rowindex } @@ -3199,6 +3262,28 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu return \x1b8 } # -- --- --- --- --- + #CRM Show Control Character Mode + proc enable_crm {} { + return \x1b\[3h + } + proc disable_crm {} { + return \x1b\[3l + } + + #DECSNM + #Note this can invert the enclosed section including any already reversed by SGR 7 - depending on terminal support. + #e.g + #set test [a+ reverse]aaa[a+ noreverse]bbb + # - $test above can't just be reversed by putting another [a+ reverse] in front of it. + # - but the following will work (even if underlying terminal doesn't support ?5 sequences) + #overtype::renderspace -width 20 [enable_inverse]$test + proc enable_inverse {} { + return \x1b\[?5h + } + proc disable_inverse {} { + return \x1b\[?5l + } + #DECAWM - automatic line wrapping proc enable_line_wrap {} { @@ -3399,6 +3484,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu #the purpose of backspace (or line cr) in embedded text is unclear. Should it allow some sort of character combining/overstrike as it has sometimes done historically (nroff/less)? e.g a\b` as an alternative combiner or bolding if same char #This should presumably only be done if the over_strike (os) capability is enabled in the terminal. Either way - it presumably won't affect printing width? set line [punk::ansi::ansistrip $line] + #ANSI (e.g PM/SOS) can contain \b or \n or \t but won't contribute to length + #ansistrip must come before any other processing of these chars. + #we can't use simple \b processing if we get ansi codes and aren't actually processing them (e.g moves) set line [punk::char::strip_nonprinting_ascii $line] ;#only strip nonprinting after ansistrip - some like BEL are part of ansi @@ -3748,6 +3836,7 @@ tcl::namespace::eval punk::ansi { -filter_fg 0\ -filter_bg 0\ -filter_reset 0\ + -info 0\ ] #codes *must* already have been split so that one esc per element in codelist @@ -3760,7 +3849,8 @@ tcl::namespace::eval punk::ansi { set opts $defaultopts_sgr_merge_singles foreach {k v} $args { switch -- $k { - -filter_fg - -filter_bg - -filter_reset { + -filter_fg - -filter_bg - -filter_reset - + -info { tcl::dict::set opts $k $v } default { @@ -4139,19 +4229,24 @@ tcl::namespace::eval punk::ansi { set codemerge [tcl::string::trimright $codemerge {;}] if {$unmergeable ne ""} { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" } else { - return "\x1b\[${codemerge}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m[join $othercodes ""]" } } else { if {$unmergeable eq ""} { #there were no SGR codes - not even resets - return [join $othercodes ""] + set mergeresult [join $othercodes ""] } else { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${unmergeable}m[join $othercodes ""]" } } + if {[tcl::dict::get $opts -info]} { + return [dict create sgr $codemerge unmergeable $unmergeable othercodes $othercodes mergeresult $mergeresult codestate $codestate] + } else { + return $mergeresult + } } #has_sgr_reset - rather than support this function - create an sgr normalize function that removes dead params and brings reset to front of param list? @@ -4240,7 +4335,7 @@ tcl::namespace::eval punk::ansi::ta { #we also need to track the start of ST terminated code and not add it for replay (in the ansistring functions) #variable re_ST {(?:\x1bX|\u0098|\x1b\^|\u009E|\x1b_|\u009F)(?:[^\x1b\007\u009c]*)(?:\x1b\\|\007|\u009c)} ;#downsides: early terminating with nests, mixes 7bit 8bit start/ends (does that exist in the wild?) #keep our 8bit/7bit start-end codes separate - variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} + variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} @@ -4252,7 +4347,7 @@ tcl::namespace::eval punk::ansi::ta { # -- --- --- --- #handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regext TRIE generator that works with Tcl regexes #This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone. - variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} + variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} # -- --- --- --- @@ -5674,7 +5769,12 @@ tcl::namespace::eval punk::ansi::ansistring { ENQ [list \x05 \u2405]\ ACK [list \x06 \u2406]\ BEL [list \x07 \u2407]\ + BS [list \x08 \u2408]\ + HT [list \x09 \u2409]\ + LF [list \x0a \u240a]\ + VT [list \x0b \u240b]\ FF [list \x0c \u240c]\ + CR [list \x0d \u240d]\ SO [list \x0e \u240e]\ SF [list \x0f \u240f]\ DLE [list \x10 \u2410]\ @@ -5688,12 +5788,15 @@ tcl::namespace::eval punk::ansi::ansistring { CAN [list \x18 \u2418]\ EM [list \x19 \u2419]\ SUB [list \x1a \u241a]\ + ESC [list \x1b \u241b]\ FS [list \x1c \u241c]\ GS [list \x1d \u241d]\ RS [list \x1e \u241e]\ US [list \x1f \u241f]\ + SP [list \x20 \u2420]\ DEL [list \x7f \u2421]\ ] + #alternate symbols for space # \u2422 Blank Symbol (b with forwardslash overly) # \u2423 Open Box (square bracket facing up like a tray/box) @@ -5836,6 +5939,7 @@ tcl::namespace::eval punk::ansi::ansistring { -cr 1\ -lf 0\ -vt 0\ + -ff 1\ -ht 1\ -bs 1\ -sp 1\ @@ -5850,16 +5954,22 @@ tcl::namespace::eval punk::ansi::ansistring { set opt_cr [tcl::dict::get $opts -cr] set opt_lf [tcl::dict::get $opts -lf] set opt_vt [tcl::dict::get $opts -vt] + set opt_ff [tcl::dict::get $opts -ff] set opt_ht [tcl::dict::get $opts -ht] set opt_bs [tcl::dict::get $opts -bs] set opt_sp [tcl::dict::get $opts -sp] # -- --- --- --- --- + # -lf 2, -vt 2 and -ff 2 are useful for CRM mode (Show Control Character Mode) in the terminal - where a newline is expected to display after the character. set visuals_opt $debug_visuals + set visuals_opt [dict remove $visuals_opt CR ESC LF VT FF HT BS SP] + if {$opt_esc} { tcl::dict::set visuals_opt ESC [list \x1b \u241b] + } else { + tcl::dict::unset visuals_opt ESC } if {$opt_cr} { tcl::dict::set visuals_opt CR [list \x0d \u240d] @@ -5870,9 +5980,20 @@ tcl::namespace::eval punk::ansi::ansistring { if {$opt_lf == 2} { tcl::dict::set visuals_opt LF [list \x0a \u240a\n] } - if {$opt_vt} { + if {$opt_vt == 1} { tcl::dict::set visuals_opt VT [list \x0b \u240b] } + if {$opt_vt == 2} { + tcl::dict::set visuals_opt VT [list \x0b \u240b\n] + } + switch -exact -- $opt_ff { + 1 { + tcl::dict::set visuals_opt FF [list \x0c \u240c] + } + 2 { + tcl::dict::set visuals_opt FF [list \x0c \u240c\n] + } + } if {$opt_ht} { tcl::dict::set visuals_opt HT [list \x09 \u2409] } diff --git a/src/modules/punk/basictelnet-999999.0a1.0.tm b/src/modules/punk/basictelnet-999999.0a1.0.tm index 36c1131b..d4be99f6 100644 --- a/src/modules/punk/basictelnet-999999.0a1.0.tm +++ b/src/modules/punk/basictelnet-999999.0a1.0.tm @@ -531,7 +531,7 @@ namespace eval punk::basictelnet { # -- --- --- --- set tailinfo "" if {[string length $nextwaiting]} { - set waitingdisplay [overtype::renderspace -wrap 1 -width 77 -height 1 "" [ansistring VIEW -lf 1 -vt 1 $nextwaiting]] + set waitingdisplay [overtype::renderspace -cp437 1 -wrap 1 -width 77 -height 1 "" [ansistring VIEW -lf 1 -vt 1 $nextwaiting]] set tailinfo "[a+ red]from waiting:\n $waitingdisplay[a]" } ::punk::basictelnet::add_debug "[a+ Yellow black]from stdin sending: [ansistring VIEW -lf 1 -vt 1 $chunk][a]\n$tailinfo\n" stdin $sock @@ -629,7 +629,7 @@ namespace eval punk::basictelnet { #set rawview [ansistring VIEW -lf 1 -vt 1 [encoding convertfrom $encoding_guess $data]] set rawview [ansistring VIEW -lf 1 -vt 1 $data] #set viewblock [overtype::left -wrap 1 -width 78 -height 4 "" $rawview] - set viewblock [overtype::renderspace -experimental test_mode -wrap 1 -width 78 -height 4 "" $rawview] + set viewblock [overtype::renderspace -cp437 1 -wrap 1 -width 78 -height 4 "" $rawview] set lines [split $viewblock \n] if {[llength $lines] > 4} { append debug_info [join [list {*}[lrange $lines 0 1] "...<[expr {[llength $lines] -4}] lines undisplayed>..." {*}[lrange $lines end-1 end]] \n] diff --git a/src/modules/punk/blockletter-999999.0a1.0.tm b/src/modules/punk/blockletter-999999.0a1.0.tm new file mode 100644 index 00000000..70e74271 --- /dev/null +++ b/src/modules/punk/blockletter-999999.0a1.0.tm @@ -0,0 +1,358 @@ +# -*- tcl -*- +# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'pmix make' or bin/punkmake to update from -buildversion.txt +# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.3.tm +# +# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. +# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# (C) 2024 +# +# @@ Meta Begin +# Application punk::blockletter 999999.0a1.0 +# Meta platform tcl +# Meta license +# @@ Meta End + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin shellspy_module_punk::blockletter 0 999999.0a1.0] +#[copyright "2024"] +#[titledesc {Module API}] [comment {-- Name section and table of contents description --}] +#[moddesc {-}] [comment {-- Description at end of page heading --}] +#[require punk::blockletter] +#[keywords module] +#[description] +#[para] - + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section Overview] +#[para] overview of punk::blockletter +#[subsection Concepts] +#[para] - + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +## Requirements +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by punk::blockletter +#[list_begin itemized] + +package require Tcl 8.6- +package require textblock +#*** !doctools +#[item] [package {Tcl 8.6}] +#[item] [package {textblock}] + +# #package require frobz +# #*** !doctools +# #[item] [package {frobz}] + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# oo::class namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#tcl::namespace::eval punk::blockletter::class { + #*** !doctools + #[subsection {Namespace punk::blockletter::class}] + #[para] class definitions + #if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} { + #*** !doctools + #[list_begin enumerated] + + # oo::class create interface_sample1 { + # #*** !doctools + # #[enum] CLASS [class interface_sample1] + # #[list_begin definitions] + + # method test {arg1} { + # #*** !doctools + # #[call class::interface_sample1 [method test] [arg arg1]] + # #[para] test method + # puts "test: $arg1" + # } + + # #*** !doctools + # #[list_end] [comment {-- end definitions interface_sample1}] + # } + + #*** !doctools + #[list_end] [comment {--- end class enumeration ---}] + #} +#} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# Base namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +tcl::namespace::eval punk::blockletter { + tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase + #variable xyz + + #*** !doctools + #[subsection {Namespace punk::blockletter}] + #[para] Core API functions for punk::blockletter + #[list_begin definitions] + + #A 3x4 block font + + variable default_frametype + set default_frametype {vl \u00a0 hl \u00a0 tlc \u00a0 trc \u00a0 blc \u00a0 brc \u00a0} + + # colours in order for T c l T k + set logo_letter_colours [list Web-red Web-green Web-royalblue Web-purple Web-orange] + set logo_letter_colours [list Red Green Blue Purple Yellow] + + + proc logo {args} { + variable logo_letter_colours + variable default_frametype + set argd [punk::args::get_dict [tstr -return string { + -frametype -default {${$default_frametype}} + -outlinecolour -default "web-white" + -backgroundcolour -default {} -help "e.g Web-white + This argument is the name as accepted by punk::ansi::a+" + *values -min 0 -max 0 + }] $args] + set f [dict get $argd opts -frametype] + set bd [dict get $argd opts -outlinecolour] + set bgansi [dict get $argd opts -backgroundcolour] ;#we use ta::detect to see if already ansi and apply as necessary + + #standard red green blue purple yellow + lassign $logo_letter_colours c_0 c_1 c_2 c_3 c_4 + + set tc [merge_left_block [T -bg $c_0 -border $bd -frametype $f] [c -bg $c_1 -border $bd -frametype $f]] + set tk [merge_left_block [T -bg $c_3 -border $bd -frametype $f] [k_short -bg $c_4 -border $bd -frametype $f]] + set logo [textblock::join_basic -- $tc [l -bg $c_2 -border $bd -frametype $f] [textblock::block 2 8 " "] $tk] + if {$bgansi ne ""} { + lassign [textblock::size_as_list $logo] lwidth lheight + set w [expr {$lwidth + 2}] + set h [expr {$lheight + 2}] + if {![punk::ansi::ta::detect $bgansi]} { + set bgansi [punk::ansi::a+ $bgansi] + } + set logobg $bgansi[textblock::block $w $h " "][punk::ansi::a] + set topmargin [string repeat " " $w] + set lmargin [textblock::block 1 [expr {$h + 1}] " "] + set logo [overtype::left -transparent " " $logobg [textblock::join_basic -- $lmargin $topmargin\n$logo]] + } + return $logo + } + + #for characters where it makes sense - offset left by 4 (1 'block' width) + proc merge_left {charleft textright} { + if {[string length $charleft] != 1} { + error "merge_left requires a single character as the charleft argument" + } + if {[textblock::height $charleft$textright] > 1} { + error "merge_left only operates on a plain char and a plain string with no newlines" + } + set rhs [textblock::join_basic -- [textblock::block 8 8 " "] [text $textright]] + #important to explicitly use -transparent " " (ordinary space) rather than -transparent 1 (any space?) + #This is because our frames have NBSP as filler to be non-transparent + return [overtype::left -transparent " " -overflow 1 [text $charleft] $rhs] + } + proc merge_left_block {blockleft blockright} { + set rhs [textblock::join_basic -- [textblock::block 8 8 " "] $blockright] + return [overtype::left -transparent " " -overflow 1 $blockleft $rhs] + } + + proc T {args} { + set args [dict remove $args -width -height] + append out [lib::hbar {*}$args]\n + append out [textblock::join -- " " [lib::vbar {*}$args] " "] + } + proc c {args} { + set args [dict remove $args -width -height] + append out [textblock::block 12 2 " "]\n + append out [lib::hbar {*}$args]\n + append out [textblock::join -- [lib::block {*}$args] " "]\n + append out [lib::hbar {*}$args] + } + proc l {args} { + set args [dict remove $args -width -height] + append out [lib::vbar {*}[dict merge {-height 8} $args]] + } + + #full height lower k + proc k {args} { + set args [dict remove $args -width -height] + set left [lib::vbar {*}[dict merge {-height 8} $args]] + set centre [textblock::block 4 4 " "]\n + append centre [lib::block {*}$args]\n + append centre [textblock::block 4 2 " "] + set right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args]\n + append right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args] + append out [textblock::join_basic -- $left $centre $right] + } + proc k_short {args} { + set args [dict remove $args -width -height] + append left [textblock::block 4 2 " "]\n + append left [lib::vbar {*}[dict merge {-height 6} $args]] + append centre [textblock::block 4 4 " "]\n + append centre [lib::block {*}$args]\n + append centre [textblock::block 4 2 " "] + append right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args]\n + append right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args] + append out [textblock::join_basic -- $left $centre $right] + } + + proc text {args} { + variable default_frametype + set argd [punk::args::get_dict [tstr -return string { + -bgcolour -default "Web-red" + -bordercolour -default "web-white" + -frametype -default {${$default_frametype}} + *values -min 1 -max 1 + str -help "Text to convert to blockletters + Requires terminal font to support relevant block characters" + " + }] $args] + set opts [dict get $argd opts] + set str [dict get $argd values str] + set str [string map {\r\n \n} $str] + set outblocks [list] + set literals [list \n] + foreach char [split $str ""] { + if {$char in $literals} { + lappend outblocks $char + continue + } + if {$char in [list \t \r]} { + lappend outblocks [textblock::block 1 8 $char] + continue + } + if {[info commands ::punk::blockletter::$char] ne ""} { + lappend outblocks [::punk::blockletter::$char {*}$opts] + } else { + lappend outblocks [textblock::block 12 8 $char] + } + } + return [textblock::join_basic -- {*}$outblocks] + } + + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::blockletter ---}] +} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# Secondary API namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +tcl::namespace::eval punk::blockletter::lib { + + tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase + tcl::namespace::path [tcl::namespace::parent] + #*** !doctools + #[subsection {Namespace punk::blockletter::lib}] + #[para] Secondary functions that are part of the API + #[list_begin definitions] + + #proc utility1 {p1 args} { + # #*** !doctools + # #[call lib::[fun utility1] [arg p1] [opt {?option value...?}]] + # #[para]Description of utility1 + # return 1 + #} + + proc block {args} { + upvar ::punk::blockletter::default_frametype ft + set argd [punk::args::get_dict [tstr -return string { + -height -default 2 + -width -default 4 + -frametype -default {${$ft}} + -bgcolour -default "Web-red" + -bordercolour -default "web-white" + *values -min 0 -max 0 + }] $args] + set bg [dict get $argd opts -bgcolour] + set bd [dict get $argd opts -bordercolour] + set h [dict get $argd opts -height] + set w [dict get $argd opts -width] + set f [dict get $argd opts -frametype] + + #a frame will usually be filled with empty spaces if content not specified + #fill the frame with a non-space so we can do transparent overtypes using ordinary space as the transparency character + set w_in [expr {$w -2}] + set h_in [expr {$h -2}] + if {$w_in > 0 && $h_in > 0} { + set inner [textblock::block $w_in $h_in \u00a0] ;#NBSP + textblock::frame -type $f -height $h -width $w -ansiborder [a+ $bd $bg] -ansibase [a+ $bg] $inner + } else { + #important to use no content arg - as empty string has 'height' of 1 in the textblock context (min height of any string is 1 row in the console) + textblock::frame -type $f -height $h -width $w -ansiborder [a+ $bd $bg] -ansibase [a+ $bg] + } + + } + proc hbar {args} { + upvar ::punk::blockletter::default_frametype ft + set defaults [dict create\ + -height 2\ + -width 12\ + -frametype $ft\ + ] + set opts [dict merge $defaults $args] + block {*}$opts + } + proc vbar {args} { + upvar ::punk::blockletter::default_frametype ft + #default height a multiple of default hbar/block height + set defaults [dict create\ + -height 6\ + -width 4\ + -frametype $ft\ + ] + set opts [dict merge $defaults $args] + [namespace current]::block {*}$opts + } + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::blockletter::lib ---}] +} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[section Internal] +#tcl::namespace::eval punk::blockletter::system { + #*** !doctools + #[subsection {Namespace punk::blockletter::system}] + #[para] Internal functions that are not part of the API + + + +#} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +## Ready +package provide punk::blockletter [tcl::namespace::eval punk::blockletter { + variable pkg punk::blockletter + variable version + set version 999999.0a1.0 +}] +return + +#*** !doctools +#[manpage_end] + diff --git a/src/modules/punk/blockletter-buildversion.txt b/src/modules/punk/blockletter-buildversion.txt new file mode 100644 index 00000000..f47d01c8 --- /dev/null +++ b/src/modules/punk/blockletter-buildversion.txt @@ -0,0 +1,3 @@ +0.1.0 +#First line must be a semantic version number +#all other lines are ignored. diff --git a/src/modules/punk/console-999999.0a1.0.tm b/src/modules/punk/console-999999.0a1.0.tm index ed3c40b1..273d444b 100644 --- a/src/modules/punk/console-999999.0a1.0.tm +++ b/src/modules/punk/console-999999.0a1.0.tm @@ -1021,8 +1021,8 @@ namespace eval punk::console { #It's known this isn't always the case - but things like textutil::untabify2 take only a single value #on some systems test_char_width is a similar speed to get_tabstop_apparent_width - but on some test_char_width is much slower #we will use test_char_width as a fallback - proc get_tabstop_apparent_width {} { - set tslist [get_tabstops] + proc get_tabstop_apparent_width {{inoutchannels {stdin stdout}}} { + set tslist [get_tabstops $inoutchannels] if {![llength $tslist]} { #either terminal failed to report - or none set. set testw [test_char_width \t] @@ -1075,23 +1075,37 @@ namespace eval punk::console { return [split [get_cursor_pos $inoutchannels] ";"] } - #todo - determine cursor on/off state before the call to restore properly. May only be possible + #todo - determine cursor on/off state before the call to restore properly. proc get_size {{inoutchannels {stdin stdout}}} { lassign $inoutchannels in out #we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810 #chan eof is faster whether chan exists or not than - if {[catch {chan eof $in} is_eof]} { - error "punk::console::get_size input channel $in seems to be closed ([info level 1])" + if {[catch {chan eof $out} is_eof]} { + error "punk::console::get_size output channel $out seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on input channel $in ([info level 1])" + error "punk::console::get_size eof on output channel $out ([info level 1])" } } - if {[catch {chan eof $out} is_eof]} { - error "punk::console::get_size output channel $out seems to be closed ([info level 1])" + #we don't need to care about the input channel if chan configure on the output can give us the info. + #short circuit ansi cursor movement method if chan configure supports the -winsize value + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + #this mechanism is much faster than ansi cursor movements + #REVIEW check if any x-platform anomalies with this method? + #can -winsize key exist but contain erroneous info? We will check that we get 2 ints at least + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + #continue on to ansi mechanism if we didn't get 2 ints + } + + if {[catch {chan eof $in} is_eof]} { + error "punk::console::get_size input channel $in seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on output channel $out ([info level 1])" + error "punk::console::get_size eof on input channel $in ([info level 1])" } } @@ -1114,18 +1128,28 @@ namespace eval punk::console { } } - #faster - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore - proc get_size_cursorrestore {} { + #faster than get_size when it is using ansi mechanism - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore + proc get_size_cursorrestore {{inoutchannels {stdin stdout}}} { + lassign $inoutchannels in out + #we use the same shortcircuit mechanism as get_size to avoid ansi at all if the output channel will give us the info directly + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + } + if {[catch { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. - puts -nonewline [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] - lassign [get_cursor_pos_list] lines cols - puts -nonewline [punk::ansi::cursor_restore][punk::console::cursor_on];flush stdout + puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] + lassign [get_cursor_pos_list $inoutchannels] lines cols + puts -nonewline $out [punk::ansi::cursor_restore][punk::console::cursor_on];flush $out set result [list columns $cols rows $lines] } errM]} { - puts -nonewline [punk::ansi::cursor_restore_dec] - puts -nonewline [punk::ansi::cursor_on] + puts -nonewline $out [punk::ansi::cursor_restore_dec] + puts -nonewline $out [punk::ansi::cursor_on] error "$errM" } else { return $result @@ -1175,7 +1199,7 @@ namespace eval punk::console { } if {!$emit} { - puts -nonewline stdout \033\[2K\033\[1G ;#2K erase line 1G cursor at col1 + puts -nonewline stdout \033\[2K\033\[1G ;#2K erase line, 1G cursor at col1 } set response "" if {[catch { @@ -1405,12 +1429,12 @@ namespace eval punk::console { proc cursor_save {} { #*** !doctools #[call [fun cursor_save]] - puts -nonewline \x1b\[s + puts -nonewline stdout \x1b\[s } proc cursor_restore {} { #*** !doctools #[call [fun cursor_restore]] - puts -nonewline \x1b\[u + puts -nonewline stdout \x1b\[u } #DEC equivalents of cursor_save/cursor_restore - perhaps more widely supported? proc cursor_save_dec {} { diff --git a/src/modules/punk/experiment-999999.0a1.0.tm b/src/modules/punk/experiment-999999.0a1.0.tm index 95436bb5..8b7287db 100644 --- a/src/modules/punk/experiment-999999.0a1.0.tm +++ b/src/modules/punk/experiment-999999.0a1.0.tm @@ -474,12 +474,12 @@ namespace eval punk::experiment { proc render1 {} { variable b1 variable b2 - overtype::renderspace -overflow 1 -startcolumn 7 $b1 $b2 + overtype::renderspace -expand_right 1 -startcolumn 7 $b1 $b2 } proc render2 {} { variable b1 variable b3 - overtype::renderspace -overflow 1 -transparent @ $b1 $b3 + overtype::renderspace -expand_right 1 -transparent @ $b1 $b3 } oo::class create c1 { diff --git a/src/modules/punk/mix/commandset/project-999999.0a1.0.tm b/src/modules/punk/mix/commandset/project-999999.0a1.0.tm index ab79b480..24a2be2d 100644 --- a/src/modules/punk/mix/commandset/project-999999.0a1.0.tm +++ b/src/modules/punk/mix/commandset/project-999999.0a1.0.tm @@ -919,10 +919,18 @@ namespace eval punk::mix::commandset::project { if {[llength $col_states]} { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes s $col_states { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode] [overtype::left $col6 $s]" \n } } else { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode]" \n } } diff --git a/src/modules/punk/repl-0.1.tm b/src/modules/punk/repl-0.1.tm index 0d3f6115..864c4030 100644 --- a/src/modules/punk/repl-0.1.tm +++ b/src/modules/punk/repl-0.1.tm @@ -431,7 +431,7 @@ proc repl::post_operations {} { uplevel #0 {eval $::repl::running_script} } #todo - tidyup so repl could be restarted - set repl::post_operations_done 0 + set ::repl::post_operations_done 0 } @@ -860,7 +860,7 @@ namespace eval punk::repl::class { set o_cursor_col $line_nextchar_col } - set mergedinfo [overtype::renderline -info 1 -overflow 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $new0] + set mergedinfo [overtype::renderline -info 1 -expand_right 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $new0] set result [dict get $mergedinfo result] set o_insert_mode [dict get $mergedinfo insert_mode] @@ -934,13 +934,13 @@ namespace eval punk::repl::class { break } } - #puts stderr "overtype::renderline -info 1 -overflow 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $activeline '$p'" + #puts stderr "overtype::renderline -info 1 -expand_right 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $activeline '$p'" set underlay $activeline set line_nextchar_col [expr {[punk::char::string_width $underlay] + 1}] if {$o_cursor_col > $line_nextchar_col} { set o_cursor_col $line_nextchar_col } - set mergedinfo [overtype::renderline -info 1 -overflow 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $p] + set mergedinfo [overtype::renderline -info 1 -expand_right 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $p] set debug "add_chunk$i" append debug \n $mergedinfo append debug \n "input:[ansistring VIEW -lf 1 -vt 1 $p]" @@ -1120,7 +1120,7 @@ namespace eval punk::repl::class { } else { set charhighlight [punk::ansi::a+ reverse]$char_at_cursor[a] } - set cursorline [overtype::renderline -transparent 1 -insert_mode 0 -overflow 0 $cursorline $prefix$charhighlight$suffix] + set cursorline [overtype::renderline -transparent 1 -insert_mode 0 -expand_right 0 $cursorline $prefix$charhighlight$suffix] lset lines $o_cursor_row-1 $cursorline } @@ -1921,7 +1921,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config if {[info complete $commandstr] && [string index $commandstr end] ne "\\"} { - #set commandstr [overtype::renderline -overflow 1 "" $commandstr] + #set commandstr [overtype::renderline -expand_right 1 "" $commandstr] set ::repl::output_stdout "" diff --git a/src/modules/punk/repo-999999.0a1.0.tm b/src/modules/punk/repo-999999.0a1.0.tm index 436dcdc4..d9f968ed 100644 --- a/src/modules/punk/repo-999999.0a1.0.tm +++ b/src/modules/punk/repo-999999.0a1.0.tm @@ -134,13 +134,30 @@ namespace eval punk::repo { } interp alias "" fossil "" punk::repo::fossil_proxy + # --- + # Calling auto_execok on an external tool can be too slow to do during package load (e.g could be 150ms) + #safe interps can't call auto_execok #At least let them load the package even though much of it may be unusable depending on the safe configuration - catch { - if {[auto_execok fossil] ne ""} { - interp alias "" FOSSIL "" {*}[auto_execok fossil] - } + #catch { + # if {[auto_execok fossil] ne ""} { + # interp alias "" FOSSIL "" {*}[auto_execok fossil] + # } + #} + # --- + # ---------- + # + + #uppercase FOSSIL to bypass fossil as alias to fossil_proxy + proc establish_FOSSIL {args} { + if {![info exists ::auto_execs(FOSSIL)]} { + set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp + } + interp alias "" FOSSIL "" ;#delete establishment alias + FOSSIL {*}$args } + interp alias "" FOSSIL "" punk::repo::establish_FOSSIL + # ---------- proc askuser {question} { if {![catch {package require punk::lib}]} { @@ -370,7 +387,16 @@ namespace eval punk::repo { } if {$repodir eq ""} { - error "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "args: $args" + dict set resultdict revision {} + dict set resultdict revision_iso8601 {} + dict set resultdict paths {} + dict set resultdict ahead "" + dict set resultdict behind "" + dict set resultdict error {reason "no_repo_found"} + dict set resultdict repotype none + return $resultdict } set subpath [punk::path::relative $repodir $abspath] if {$subpath eq "."} { @@ -644,6 +670,16 @@ namespace eval punk::repo { set path_count_fields [list unchanged changed new missing extra] set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601] set dresult [dict create] + if {[dict exists $repostate error]} { + foreach f $state_fields { + dict set dresult $f "" + } + foreach f $path_count_fields { + dict set dresult $f "" + } + #todo? + return $dresult + } foreach f $state_fields { dict set dresult $f [dict get $repostate $f] } diff --git a/src/modules/textblock-999999.0a1.0.tm b/src/modules/textblock-999999.0a1.0.tm index 0502cc4b..45890bee 100644 --- a/src/modules/textblock-999999.0a1.0.tm +++ b/src/modules/textblock-999999.0a1.0.tm @@ -60,6 +60,8 @@ package require punk::ansi package require punk::lib catch {package require patternpunk} package require overtype + +#safebase interps as at 2024-08 can't access deeper paths - even though they are below the supposed safe list. package require term::ansi::code::macros ;#required for frame if old ansi g0 used - review - make package optional? package require textutil @@ -1931,13 +1933,6 @@ tcl::namespace::eval textblock { set hval $ansibase_header$header ;#no reset set rowh [my header_height $hrow] - #set h_lines [lrepeat $rowh $hcell_line_blank] - #set hcell_blank [join $h_lines \n] - #set hval_lines [split $hval \n] - #set hval_lines [lrange $hval_lines 0 $rowh-1] - #set hval_block [join $hval_lines \n] - #set headercell [overtype::left -experimental test_mode $ansibase_header$hcell_blank$RST $hval_block] - if {$hrow == 0} { set hlims $header_boxlimits_toprow set rowpos "top" @@ -2144,7 +2139,7 @@ tcl::namespace::eval textblock { #puts $hblock #puts "==>hval:'$hval'[a]" #puts "==>hval:'[ansistring VIEW $hval]'" - #set spanned_frame [overtype::renderspace -experimental test_mode -transparent 1 $spanned_frame $hblock] + #set spanned_frame [overtype::renderspace -transparent 1 $spanned_frame $hblock] #spanned values default left - todo make configurable @@ -3502,11 +3497,11 @@ tcl::namespace::eval textblock { set height [textblock::height $table] ;#only need to get height once at start } else { set nextcol [textblock::join -- [textblock::block $padwidth $height $TSUB] $nextcol] - set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent $TSUB $table[unset table] $nextcol] + set table [overtype::renderspace -expand_right 1 -transparent $TSUB $table[unset table] $nextcol] #JMN #set nextcol [textblock::join -- [textblock::block $padwidth $height "\uFFFF"] $nextcol] - #set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol] + #set table [overtype::renderspace -expand_right 1 -transparent \uFFFF $table $nextcol] } incr padwidth $bodywidth incr colposn @@ -3607,14 +3602,7 @@ tcl::namespace::eval textblock { set table $nextcol set height [textblock::height $table] ;#only need to get height once at start } else { - set table [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -overflow 1 -experimental test_mode -transparent $TSUB $table $nextcol] - - #set nextcol [textblock::join -- [textblock::block $padwidth $height $TSUB] $nextcol] - #set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent $TSUB $table[unset table] $nextcol] - #JMN - - #set nextcol [textblock::join -- [textblock::block $padwidth $height "\uFFFF"] $nextcol] - #set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol] + set table [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -expand_right 1 -transparent $TSUB $table $nextcol] } incr padwidth $bodywidth incr colposn @@ -3724,7 +3712,7 @@ tcl::namespace::eval textblock { lappend body_blocks $nextcol_body } else { if {$headerheight > 0} { - set header_build [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -overflow 1 -experimental test_mode -transparent $TSUB $header_build[unset header_build] $nextcol_header[unset nextcol_header]] + set header_build [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -expand_right 1 -transparent $TSUB $header_build[unset header_build] $nextcol_header[unset nextcol_header]] } lappend body_blocks $nextcol_body #set body_build [textblock::join -- $body_build[unset body_build] $nextcol_body] @@ -4057,7 +4045,7 @@ tcl::namespace::eval textblock { if append is chosen the new values will always start at the first column" -columns -default "" -type integer -help "Number of table columns Will default to 2 if not using an existing -table object" - *values + *values -min 0 -max 1 datalist -default {} -help "flat list of table cell values which will be wrapped based on -columns value" }] $args] set opts [dict get $argd opts] @@ -4408,6 +4396,14 @@ tcl::namespace::eval textblock { return [tcl::dict::create width $width height $height] ;#maintain order in 'image processing' standard width then height - caller may use lassign [tcl::dict::values [blocksize ]] width height } + proc size_as_opts {textblock} { + set sz [size $textblock] + return [dict create -width [dict get $sz width] -height [dict get $sz height]] + } + proc size_as_list {textblock} { + set sz [size $textblock] + return [list [dict get $sz width] [dict get $sz height]] + } #must be able to handle block as string with or without newlines #if no newlines - attempt to treat as a list #must handle whitespace-only string,list elements, and/or lines. @@ -5132,6 +5128,7 @@ tcl::namespace::eval textblock { [punk::lib::list_as_lines -- [lrepeat 8 " | "]] } proc table {args} { + #todo - use punk::args upvar ::textblock::class::opts_table_defaults toptdefaults set defaults [tcl::dict::create\ -rows [list]\ @@ -5183,7 +5180,7 @@ tcl::namespace::eval textblock { } variable frametypes - set frametypes [list light heavy arc double block block1 block2 ascii altg] + set frametypes [list light heavy arc double block block1 block2 block2hack ascii altg] #class::table needs to be able to determine valid frametypes proc frametypes {} { variable frametypes @@ -5192,7 +5189,7 @@ tcl::namespace::eval textblock { proc frametype {f} { #set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] switch -- $f { - light - heavy - arc - double - block - block1 - block2 - ascii - altg { + light - heavy - arc - double - block - block1 - block2 - block2hack - ascii - altg { return [tcl::dict::create category predefined type $f] } default { @@ -5213,7 +5210,7 @@ tcl::namespace::eval textblock { set is_custom_dict_ok 0 } if {!$is_custom_dict_ok} { - error "frame option -type must be one of known types: $textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" + error "frame option -type must be one of known types: $::textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" } set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] set custom_frame [tcl::dict::merge $default_custom $f] @@ -6323,9 +6320,12 @@ tcl::namespace::eval textblock { set vlr \u2595 ;# right one eighth block set vll \u258f ;# left one eighth block + #some terminals (on windows as at 2024) miscount width of these single-width blocks internally + #resulting in extra spacing that is sometimes well removed from the character itself (e.g at next ansi reset) + #This was fixed in windows-terminal based systems (2021) but persists in others. + #https://github.com/microsoft/terminal/issues/11694 set tlc \U1fb7d ;#legacy block set trc \U1fb7e ;#legacy block - set blc \U1fb7c ;#legacy block set brc \U1fb7f ;#legacy block @@ -6336,6 +6336,42 @@ tcl::namespace::eval textblock { set vlrj $vlr } + block2hack { + #the resultant table will have text appear towards top of each box + #with 'legacy' computing unicode block - hopefully these become more widely supported - as they are useful and fill in some gaps + set hlt \u2594 ;# upper one eighth block + set hlb \u2581 ;# lower one eighth block + set vlr \u2595 ;# right one eighth block + set vll \u258f ;# left one eighth block + + #see comments in block2 regarding the problems in some terminals that this *may* hack around to some extent. + #the caller probably only needs block2hack if block2 doesn't work + + #1) + #review - this hack looks sort of promising - but overtype::renderline needs fixing ? + #set tlc \U1fb7d\b ;#legacy block + #set trc \U1fb7e\b ;#legacy block + #set blc \U1fb7c\b ;#legacy block + #set brc \U1fb7f\b ;#legacy block + + #2) - works on cmd.exe and some others + # a 'privacy message' is 'probably' also not supported on the old terminal but is on newer ones + #known exception - conemu on windows - displays junk for various ansi codes - (and slow terminal anyway) + #this hack has a reasonable chance of working + #except that the punk overtype library does recognise PMs + #A single backspace however is an unlikely and generally unuseful PM - so there is a corresponding hack in the renderline system to pass this PM through! + #ugly - in that we don't know the application specifics of what the PM data contains and where it's going. + set tlc \U1fb7d\x1b^\b\x1b\\ ;#legacy block + set trc \U1fb7e\x1b^\b\x1b\\ ;#legacy block + set blc \U1fb7c\x1b^\b\x1b\\ ;#legacy block + set brc \U1fb7f\x1b^\b\x1b\\ ;#legacy block + + #horizontal and vertical bar joins + set hltj $hlt + set hlbj $hlb + set vllj $vll + set vlrj $vlr + } block { set hlt \u2580 ;#upper half set hlb \u2584 ;#lower half @@ -6357,7 +6393,7 @@ tcl::namespace::eval textblock { set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] ;#only default the general types - these form defaults for more specific types if they're missing if {[llength $f] % 2 != 0} { #todo - retrieve usage from punk::args - error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $textblock::frametypes and does not appear to be a dictionary for a custom frametype" + error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $::textblock::frametypes and does not appear to be a dictionary for a custom frametype" } #unknown order of keys specified by user - validate before creating vars as we need more general elements to be available as defaults dict for {k v} $f { @@ -6488,7 +6524,11 @@ tcl::namespace::eval textblock { -ellipsis 1\ -usecache 1\ -buildcache 1\ + -pad 1\ + -crm_mode 0\ ] + #-pad 1 is default so that simple 'textblock::frame "[a+ Red]a \nbbb[a]" extends the bg colour on the short ragged lines (and empty lines) + # for ansi art - -pad 0 is likely to be preferable set expect_optval 0 set argposn 0 @@ -6527,7 +6567,12 @@ tcl::namespace::eval textblock { #use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache foreach {k v} $arglist { switch -- $k { - -etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache { + -etabs - -type - -boxlimits - -boxmap - -joins + - -title - -subtitle - -width - -height + - -ansiborder - -ansibase + - -blockalign - -textalign - -ellipsis + - -crm_mode + - -usecache - -buildcache - -pad { tcl::dict::set opts $k $v } default { @@ -6543,11 +6588,13 @@ tcl::namespace::eval textblock { set opt_boxmap [tcl::dict::get $opts -boxmap] set opt_usecache [tcl::dict::get $opts -usecache] set opt_buildcache [tcl::dict::get $opts -buildcache] + set opt_pad [tcl::dict::get $opts -pad] + set opt_crm_mode [tcl::dict::get $opts -crm_mode] set usecache $opt_usecache ;#may need to override set buildcache $opt_buildcache set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] - set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable + set known_frametypes $frametypes ;# light, heavey etc as defined in the ::textblock::frametypes variable set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] lassign [textblock::frametype $opt_type] _cat category _type ftype @@ -6686,6 +6733,19 @@ tcl::namespace::eval textblock { } } set contents [tcl::string::map [list \r\n \n] $contents] + if {$opt_crm_mode} { + if {$opt_height eq ""} { + set h [textblock::height $contents] + } else { + set h [expr {$opt_height -2}] + } + if {$opt_width eq ""} { + set w [textblock::width $contents] + } else { + set w [expr {$opt_width -2}] + } + set contents [overtype::renderspace -crm_mode 1 -wrap 1 -width $w -height $h "" $contents] + } set actual_contentwidth [textblock::width $contents] ;#length of longest line in contents (contents can be ragged) set actual_contentheight [textblock::height $contents] } else { @@ -7134,15 +7194,22 @@ tcl::namespace::eval textblock { append contents [::join [lrepeat $diff \n] ""] } - set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) - set paddedwidth [textblock::widthtopline $paddedcontents] - - #review - horizontal truncation - if {$paddedwidth > $cache_patternwidth} { - set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + if {$opt_pad} { + set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) + set paddedwidth [textblock::widthtopline $paddedcontents] + #review - horizontal truncation + if {$paddedwidth > $cache_patternwidth} { + set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + } + #important to supply end of opts -- to textblock::join - particularly here with arbitrary data + set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays + } else { + set cwidth [textblock::width $contents] + if {$cwidth > $cache_patternwidth} { + set contents [overtype::renderspace -width $cache_patternwidth "" $contents] + } + set contentblock [textblock::join -- $contents] } - #important to supply end of opts -- to textblock::join - particularly here with arbitrary data - set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays set tlines [split $template \n] diff --git a/src/project_layouts/custom/_project/punk.basic/src/make.tcl b/src/project_layouts/custom/_project/punk.basic/src/make.tcl index 1cf07c5b..9edd90b0 100644 --- a/src/project_layouts/custom/_project/punk.basic/src/make.tcl +++ b/src/project_layouts/custom/_project/punk.basic/src/make.tcl @@ -1212,8 +1212,9 @@ foreach vfstail $vfs_tails { set rtmountpoint //zipfs:/rtmounts/$runtime_fullname set changed_unchanged [$vfs_event targetset_source_changes] + set vfs_or_runtime_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]}] - if {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]} { + if {$vfs_or_runtime_changed} { #source .vfs folder has changes $vfs_event targetset_started # -- --- --- --- --- --- @@ -1283,6 +1284,7 @@ foreach vfstail $vfs_tails { puts stderr "RUNTIME capabilities unknown. Unsure if zip supported. trying anyway.." } } + #note - as at 2024-08 - there is some discussion about the interface to mkimg - it is considered unstable (may change to -option value syntax) puts stderr "calling: tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs \"\" $buildfolder/build_$runtime_fullname" tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs "" $buildfolder/build_$runtime_fullname } result ]} { @@ -1352,9 +1354,10 @@ foreach vfstail $vfs_tails { if {![catch { exec $pscmd | grep $targetkit } still_running]} { - - puts stdout "found $targetkit instances still running\n" + set still_running_lines [split [string trim $still_running] \n] + puts stdout "found ([llength $still_running_lines]) $targetkit instances still running\n" set count_killed 0 + set num_to_kill [llength $still_running_lines] foreach ln [split $still_running \n] { puts stdout " $ln" @@ -1387,9 +1390,6 @@ foreach vfstail $vfs_tails { #review - *no running instance* works with windows taskkill - "*No such process*" works with kill -9 on FreeBSD and linux - other platforms? if {![string match "*no running instance*" $errMsg] && ![string match "*No such process*" $errMsg]} { lappend failed_kits [list kit $targetkit reason "could not kill running process for $targetkit (using '$killcmd')"] - $vfs_event targetset_end FAILED - $vfs_event destroy - $vfs_installer destroy continue } } else { @@ -1397,10 +1397,15 @@ foreach vfstail $vfs_tails { incr count_killed } } - if {$count_killed > 0} { - puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" - after 1000 + if {$count_killed < $num_to_kill} { + $vfs_event targetset_end FAILED + $vfs_event destroy + $vfs_installer destroy + continue } + + puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" + after 1000 } else { puts stderr "Ok.. no running '$targetkit' processes found" } @@ -1426,22 +1431,35 @@ foreach vfstail $vfs_tails { # -- --- --- --- --- --- $vfs_event targetset_end OK + } else { + set skipped_vfs_build 1 + puts stderr "." + puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" + $vfs_event targetset_end SKIPPED + } + $vfs_event destroy + $vfs_installer destroy - after 200 - set deployment_folder [file dirname $sourcefolder]/bin - file mkdir $deployment_folder + after 200 + set deployment_folder [file dirname $sourcefolder]/bin + file mkdir $deployment_folder - # -- ---------- - set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] - $bin_installer set_source_target $buildfolder $deployment_folder - set bin_event [$bin_installer start_event {-make-step final_kit_install}] - $bin_event targetset_init INSTALL $deployment_folder/$targetkit - #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) - #set last_completion [$bin_event targetset_last_complete] - - $bin_event targetset_addsource $buildfolder/$targetkit - $bin_event targetset_started - # -- ---------- + # -- ---------- + set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] + $bin_installer set_source_target $buildfolder $deployment_folder + set bin_event [$bin_installer start_event {-make-step final_kit_install}] + $bin_event targetset_init INSTALL $deployment_folder/$targetkit + #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) + #set last_completion [$bin_event targetset_last_complete] + + $bin_event targetset_addsource $deployment_folder/$targetkit ;#add target as a source of metadata for change detection + $bin_event targetset_addsource $buildfolder/$targetkit + $bin_event targetset_started + # -- ---------- + + set changed_unchanged [$bin_event targetset_source_changes] + set built_or_installed_kit_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$bin_event get_targets_exist]] < [llength [$bin_event get_targets]]}] + if {$built_or_installed_kit_changed} { if {[file exists $deployment_folder/$targetkit]} { puts stderr "deleting existing deployed at $deployment_folder/$targetkit" @@ -1467,19 +1485,16 @@ foreach vfstail $vfs_tails { # -- ---------- $bin_event targetset_end OK # -- ---------- - $bin_event destroy - $bin_installer destroy - } else { - set skipped_vfs_build 1 + set skipped_kit_install 1 puts stderr "." - puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" - $vfs_event targetset_end SKIPPED + puts stdout "Skipping kit install for $targetkit with vfs $vfstail runtime $rtname - no change detected" + $bin_event targetset_end SKIPPED } + $bin_event destroy + $bin_installer destroy - $vfs_event destroy - $vfs_installer destroy } ;#end foreach targetkit } ;#end foreach rtname in runtimes diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/fileutil/paths-1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/fileutil/paths-1.tm new file mode 100644 index 00000000..e387acf7 --- /dev/null +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/fileutil/paths-1.tm @@ -0,0 +1,74 @@ +# paths.tcl -- +# +# Manage lists of search paths. +# +# Copyright (c) 2009-2019 Andreas Kupries +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +# Each object instance manages a list of paths. + +# ### ### ### ######### ######### ######### +## Requisites + +package require Tcl 8.4 +package require snit + +# ### ### ### ######### ######### ######### +## API + +snit::type ::fileutil::paths { + + # ### ### ### ######### ######### ######### + ## Options :: None + + # ### ### ### ######### ######### ######### + ## Creation, destruction + + # Default constructor. + # Default destructor. + + # ### ### ### ######### ######### ######### + ## Methods :: Querying and manipulating the list of paths. + + method paths {} { + return $mypaths + } + + method add {path} { + set pos [lsearch $mypaths $path] + if {$pos >= 0 } return + lappend mypaths $path + return + } + + method remove {path} { + set pos [lsearch $mypaths $path] + if {$pos < 0} return + set mypaths [lreplace $mypaths $pos $pos] + return + } + + method clear {} { + set mypaths {} + return + } + + # ### ### ### ######### ######### ######### + ## Internal methods :: None + + # ### ### ### ######### ######### ######### + ## State :: List of paths. + + variable mypaths {} + + ## + # ### ### ### ######### ######### ######### +} + +# ### ### ### ######### ######### ######### +## Ready + +package provide fileutil::paths 1 +return diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/fileutil/traverse-0.6.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/fileutil/traverse-0.6.tm new file mode 100644 index 00000000..2f36d109 --- /dev/null +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/fileutil/traverse-0.6.tm @@ -0,0 +1,504 @@ +# traverse.tcl -- +# +# Directory traversal. +# +# Copyright (c) 2006-2015 by Andreas Kupries +# +# 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.3 + +# OO core +if {[package vsatisfies [package present Tcl] 8.5]} { + # Use new Tcl 8.5a6+ features to specify the allowed packages. + # We can use anything above 1.3. This means v2 as well. + package require snit 1.3- +} else { + # For Tcl 8.{3,4} only snit1 of a suitable patchlevel is possible. + package require snit 1.3 +} +package require control ; # Helpers for control structures +package require fileutil ; # -> fullnormalize + +snit::type ::fileutil::traverse { + + # Incremental directory traversal. + + # API + # create %AUTO% basedirectory options... -> object + # next filevar -> boolean + # foreach filevar script + # files -> list (path ...) + + # Options + # -prefilter command-prefix + # -filter command-prefix + # -errorcmd command-prefix + + # Use cases + # + # (a) Basic incremental + # - Create and configure a traversal object. + # - Execute 'next' to retrieve one path at a time, + # until the command returns False, signaling that + # the iterator has exhausted the supply of paths. + # (The path is stored in the named variable). + # + # The execution of 'next' can be done in a loop, or via event + # processing. + + # (b) Basic loop + # - Create and configure a traversal object. + # - Run a script for each path, using 'foreach'. + # This is a convenient standard wrapper around 'next'. + # + # The loop properly handles all possible Tcl result codes. + + # (c) Non-incremental, non-looping. + # - Create and configure a traversal object. + # - Retrieve a list of all paths via 'files'. + + # The -prefilter callback is executed for directories. Its result + # determines if the traverser recurses into the directory or not. + # The default is to always recurse into all directories. The call- + # back is invoked with a single argument, the path of the + # directory. + # + # The -filter callback is executed for all paths. Its result + # determines if the current path is a valid result, and returned + # by 'next'. The default is to accept all paths as valid. The + # callback is invoked with a single argument, the path to check. + + # The -errorcmd callback is executed for all paths the traverser + # has trouble with. Like being unable to cd into them, get their + # status, etc. The default is to ignore any such problems. The + # callback is invoked with a two arguments, the path for which the + # error occured, and the error message. Errors thrown by the + # filter callbacks are handled through this callback too. Errors + # thrown by the error callback itself are not caught and ignored, + # but allowed to pass to the caller, usually of 'next'. + + # Note: Low-level functionality, version and platform dependent is + # implemented in procedures, and conditioally defined for optimal + # use of features, etc. ... + + # Note: Traversal is done in depth-first pre-order. + + # Note: The options are handled only during + # construction. Afterward they are read-only and attempts to + # modify them will cause the system to throw errors. + + # ### ### ### ######### ######### ######### + ## Implementation + + option -filter -default {} -readonly 1 + option -prefilter -default {} -readonly 1 + option -errorcmd -default {} -readonly 1 + + constructor {basedir args} { + set _base $basedir + $self configurelist $args + return + } + + method files {} { + set files {} + $self foreach f {lappend files $f} + return $files + } + + method foreach {fvar body} { + upvar 1 $fvar currentfile + + # (Re-)initialize the traversal state on every call. + $self Init + + while {[$self next currentfile]} { + set code [catch {uplevel 1 $body} result] + + # decide what to do upon the return code: + # + # 0 - the body executed successfully + # 1 - the body raised an error + # 2 - the body invoked [return] + # 3 - the body invoked [break] + # 4 - the body invoked [continue] + # everything else - return and pass on the results + # + switch -exact -- $code { + 0 {} + 1 { + return -errorinfo [::control::ErrorInfoAsCaller uplevel foreach] \ + -errorcode $::errorCode -code error $result + } + 3 { + # FRINK: nocheck + return + } + 4 {} + default { + return -code $code $result + } + } + } + return + } + + method next {fvar} { + upvar 1 $fvar currentfile + + # Initialize on first call. + if {!$_init} { + $self Init + } + + # We (still) have valid paths in the result stack, return the + # next one. + + if {[llength $_results]} { + set top [lindex $_results end] + set _results [lreplace $_results end end] + set currentfile $top + return 1 + } + + # Take the next directory waiting in the processing stack and + # fill the result stack with all valid files and sub- + # directories contained in it. Extend the processing queue + # with all sub-directories not yet seen already (!circular + # symlinks) and accepted by the prefilter. We stop iterating + # when we either have no directories to process anymore, or + # the result stack contains at least one path we can return. + + while {[llength $_pending]} { + set top [lindex $_pending end] + set _pending [lreplace $_pending end end] + + # Directory accessible? Skip if not. + if {![ACCESS $top]} { + Error $top "Inacessible directory" + continue + } + + # Expand the result stack with all files in the directory, + # modulo filtering. + + foreach f [GLOBF $top] { + if {![Valid $f]} continue + lappend _results $f + } + + # Expand the result stack with all sub-directories in the + # directory, modulo filtering. Further expand the + # processing stack with the same directories, if not seen + # yet and modulo pre-filtering. + + foreach f [GLOBD $top] { + if { + [string equal [file tail $f] "."] || + [string equal [file tail $f] ".."] + } continue + + if {[Valid $f]} { + lappend _results $f + } + + Enter $top $f + if {[Cycle $f]} continue + + if {[Recurse $f]} { + lappend _pending $f + } + } + + # Stop expanding if we have paths to return. + + if {[llength $_results]} { + set top [lindex $_results end] + set _results [lreplace $_results end end] + set currentfile $top + return 1 + } + } + + # Allow re-initialization with next call. + + set _init 0 + return 0 + } + + # ### ### ### ######### ######### ######### + ## Traversal state + + # * Initialization flag. Checked in 'next', reset by next when no + # more files are available. Set in 'Init'. + # * Base directory (or file) to start the traversal from. + # * Stack of prefiltered unknown directories waiting for + # processing, i.e. expansion (TOP at end). + # * Stack of valid paths waiting to be returned as results. + # * Set of directories already visited (normalized paths), for + # detection of circular symbolic links. + + variable _init 0 ; # Initialization flag. + variable _base {} ; # Base directory. + variable _pending {} ; # Processing stack. + variable _results {} ; # Result stack. + + # sym link handling (to break cycles, while allowing the following of non-cycle links). + # Notes + # - path parent tracking is lexical. + # - path identity tracking is based on the normalized path, i.e. the path with all + # symlinks resolved. + # Maps + # - path -> parent (easier to follow the list than doing dirname's) + # - path -> normalized (cache to avoid redundant calls of fullnormalize) + # cycle <=> A parent's normalized form (NF) is identical to the current path's NF + + variable _parent -array {} + variable _norm -array {} + + # ### ### ### ######### ######### ######### + ## Internal helpers. + + proc Enter {parent path} { + #puts ___E|$path + upvar 1 _parent _parent _norm _norm + set _parent($path) $parent + set _norm($path) [fileutil::fullnormalize $path] + } + + proc Cycle {path} { + upvar 1 _parent _parent _norm _norm + set nform $_norm($path) + set paren $_parent($path) + while {$paren ne {}} { + if {$_norm($paren) eq $nform} { return yes } + set paren $_parent($paren) + } + return no + } + + method Init {} { + array unset _parent * + array unset _norm * + + # Path ok as result? + if {[Valid $_base]} { + lappend _results $_base + } + + # Expansion allowed by prefilter? + if {[file isdirectory $_base] && [Recurse $_base]} { + Enter {} $_base + lappend _pending $_base + } + + # System is set up now. + set _init 1 + return + } + + proc Valid {path} { + #puts ___V|$path + upvar 1 options options + if {![llength $options(-filter)]} {return 1} + set path [file normalize $path] + set code [catch {uplevel \#0 [linsert $options(-filter) end $path]} valid] + if {!$code} {return $valid} + Error $path $valid + return 0 + } + + proc Recurse {path} { + #puts ___X|$path + upvar 1 options options _norm _norm + if {![llength $options(-prefilter)]} {return 1} + set path [file normalize $path] + set code [catch {uplevel \#0 [linsert $options(-prefilter) end $path]} valid] + if {!$code} {return $valid} + Error $path $valid + return 0 + } + + proc Error {path msg} { + upvar 1 options options + if {![llength $options(-errorcmd)]} return + set path [file normalize $path] + uplevel \#0 [linsert $options(-errorcmd) end $path $msg] + return + } + + ## + # ### ### ### ######### ######### ######### +} + +# ### ### ### ######### ######### ######### +## + +# The next three helper commands for the traverser depend strongly on +# the version of Tcl, and partially on the platform. + +# 1. In Tcl 8.3 using -types f will return only true files, but not +# links to files. This changed in 8.4+ where links to files are +# returned as well. So for 8.3 we have to handle the links +# separately (-types l) and also filter on our own. +# Note that Windows file links are hard links which are reported by +# -types f, but not -types l, so we can optimize that for the two +# platforms. +# +# 2. In Tcl 8.3 we also have a crashing bug in glob (SIGABRT, "stat on +# a known file") when trying to perform 'glob -types {hidden f}' on +# a directory without e'x'ecute permissions. We code around by +# testing if we can cd into the directory (stat might return enough +# information too (mode), but possibly also not portable). +# +# For Tcl 8.2 and 8.4+ glob simply delivers an empty result +# (-nocomplain), without crashing. For them this command is defined +# so that the bytecode compiler removes it from the bytecode. +# +# This bug made the ACCESS helper necessary. +# We code around the problem by testing if we can cd into the +# directory (stat might return enough information too (mode), but +# possibly also not portable). + +if {[package vsatisfies [package present Tcl] 8.5]} { + # Tcl 8.5+. + # We have to check readability of "current" on our own, glob + # changed to error out instead of returning nothing. + + proc ::fileutil::traverse::ACCESS {args} {return 1} + + proc ::fileutil::traverse::GLOBF {current} { + if {![file readable $current] || + [BadLink $current]} { + return {} + } + + set res [lsort -unique [concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]]] + + # Look for broken links (They are reported as neither file nor directory). + foreach l [lsort -unique [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *]]] { + if {[file isfile $l]} continue + if {[file isdirectory $l]} continue + lappend res $l + } + return [lsort -unique $res] + } + + proc ::fileutil::traverse::GLOBD {current} { + if {![file readable $current] || + [BadLink $current]} { + return {} + } + + lsort -unique [concat \ + [glob -nocomplain -directory $current -types d -- *] \ + [glob -nocomplain -directory $current -types {hidden d} -- *]] + } + + proc ::fileutil::traverse::BadLink {current} { + if {[file type $current] ne "link"} { return no } + + set dst [file join [file dirname $current] [file readlink $current]] + + if {![file exists $dst] || + ![file readable $dst]} { + return yes + } + + return no + } + +} elseif {[package vsatisfies [package present Tcl] 8.4]} { + # Tcl 8.4+. + # (Ad 1) We have -directory, and -types, + # (Ad 2) Links are returned for -types f/d if they refer to files/dirs. + # (Ad 3) No bug to code around + + proc ::fileutil::traverse::ACCESS {args} {return 1} + + proc ::fileutil::traverse::GLOBF {current} { + set res [concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]] + + # Look for broken links (They are reported as neither file nor directory). + foreach l [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *] ] { + if {[file isfile $l]} continue + if {[file isdirectory $l]} continue + lappend res $l + } + return $res + } + + proc ::fileutil::traverse::GLOBD {current} { + concat \ + [glob -nocomplain -directory $current -types d -- *] \ + [glob -nocomplain -directory $current -types {hidden d} -- *] + } + +} else { + # 8.3. + # (Ad 1) We have -directory, and -types, + # (Ad 2) Links are NOT returned for -types f/d, collect separately. + # No symbolic file links on Windows. + # (Ad 3) Bug to code around. + + proc ::fileutil::traverse::ACCESS {current} { + if {[catch { + set h [pwd] ; cd $current ; cd $h + }]} {return 0} + return 1 + } + + if {[string equal $::tcl_platform(platform) windows]} { + proc ::fileutil::traverse::GLOBF {current} { + concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]] + } + } else { + proc ::fileutil::traverse::GLOBF {current} { + set l [concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]] + + foreach x [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *]] { + if {[file isdirectory $x]} continue + # We have now accepted files, links to files, and broken links. + lappend l $x + } + + return $l + } + } + + proc ::fileutil::traverse::GLOBD {current} { + set l [concat \ + [glob -nocomplain -directory $current -types d -- *] \ + [glob -nocomplain -directory $current -types {hidden d} -- *]] + + foreach x [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *]] { + if {![file isdirectory $x]} continue + lappend l $x + } + + return $l + } +} + +# ### ### ### ######### ######### ######### +## Ready + +package provide fileutil::traverse 0.6 diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm index 1d91b53f..7f7c33cd 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm @@ -5,8 +5,9 @@ package require flagfilter namespace import ::flagfilter::check_flags namespace eval natsort { + #REVIEW - determine and document the purpose of scriptdir being added to tm path proc scriptdir {} { - set possibly_linked_script [file dirname [file normalize [file join [info script] ...]]] + set possibly_linked_script [file dirname [file normalize [file join [info script] __dummy__]]] if {[file isdirectory $possibly_linked_script]} { return $possibly_linked_script } else { @@ -14,7 +15,11 @@ namespace eval natsort { } } if {![interp issafe]} { - tcl::tm::add [scriptdir] + set sdir [scriptdir] + #puts stderr "natsort tcl::tm::add $sdir" + if {$sdir ni [tcl::tm::list]} { + catch {tcl::tm::add $sdir} + } } } @@ -36,6 +41,7 @@ namespace eval natsort { } else { puts stderr "|>natsort_call_err> unable to interpret 2nd argument to do_error: '$then' should be one of '$levels' or 'exit '" } + flush stderr if {$::tcl_interactive} { #may not always be desirable - but assumed to be more useful not to exit despite request, to aid in debugging if {[string tolower $type] eq "exit"} { @@ -43,6 +49,7 @@ namespace eval natsort { if {![string is digit -strict $code]} { puts stderr "|>natsort_call_err> unable to interpret 2nd argument to do_error: '$then' should be: 'exit '" } + flush stderr } return -code error $msg } else { @@ -1422,6 +1429,9 @@ namespace eval natsort { proc called_directly_namematch {} { global argv0 + if {[info script] eq ""} { + return 0 + } #see https://wiki.tcl-lang.org/page/main+script #trailing ... let's us resolve symlinks in last component of the path (could be something else like ___ but ... seems unlikely to collide with anything in the filesystem) if {[info exists argv0] @@ -1440,12 +1450,18 @@ namespace eval natsort { #Review issues around comparing names vs using inodes (esp with respect to samba shares) proc called_directly_inodematch {} { global argv0 + if {[info exists argv0] - && [file exists [info script]] && [file exists $argv0]} { + && [file exists [info script]] && [file exists $argv0]} { file stat $argv0 argv0Info file stat [info script] scriptInfo - expr {$argv0Info(dev) == $scriptInfo(dev) - && $argv0Info(ino) == $scriptInfo(ino)} + if {$argv0Info(ino) == 0 || $scriptInfo(ino) == 0 || $argv0Info(dev) == 0 || $scriptInfo(dev) == 0} { + #vfs? + #e.g //zipfs:/ + return 0 + } + return [expr {$argv0Info(dev) == $scriptInfo(dev) + && $argv0Info(ino) == $scriptInfo(ino)}] } else { return 0 } @@ -1460,6 +1476,11 @@ namespace eval natsort { #-- choose a policy and leave the others commented. #set is_called_directly $is_namematch #set is_called_directly $is_inodematch + + #puts "NATSORT: called_directly_namematch - $is_namematch" + #puts "NATSORT: called_directly_inodematch - $is_inodematch" + #flush stdout + set is_called_directly [expr {$is_namematch || $is_inodematch}] #set is_called_directly [expr {$is_namematch && $is_inodematch}] ### @@ -1921,6 +1942,8 @@ namespace eval natsort { #set args [check_flags -caller test1 -defaults [list -collate nocase -algorithm sort -topchars "\uFFFF" -winlike 0 -debug 0 -stacktrace 0 -showsplits 0] -required {all} -extras {none} -commandprocessors {{-cmd -default help} {-cmd -cmdarg1 -default "."} {-cmd -cmdarg2 -default j}} -values $::argv ] #set args [check_flags -caller test1 -defaults [list -collate nocase -algorithm sort -topchars "\uFFFF" -winlike 0 -debug 0 -stacktrace 0 -showsplits 0] -required {all} -extras {none} -commandprocessors {ls {ls lsdir -default "\uFFFF"}} -values $::argv ] + puts stderr "natsort directcall exit" + flush stderr exit 0 if {$::argc} { diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.6.5.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.6.5.tm index 143794fb..f7e4c1a5 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.6.5.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.6.5.tm @@ -163,7 +163,7 @@ proc overtype::string_columns {text} { tcl::namespace::eval overtype::priv { } -#could return larger than colwidth +#could return larger than renderwidth proc _get_row_append_column {row} { upvar outputlines outputlines set idx [expr {$row -1}] @@ -171,14 +171,14 @@ proc _get_row_append_column {row} { return 1 } else { upvar opt_overflow opt_overflow - upvar colwidth colwidth + upvar renderwidth renderwidth set existinglen [punk::ansi::printing_length [lindex $outputlines $idx]] set endpos [expr {$existinglen +1}] if {$opt_overflow} { return $endpos } else { - if {$endpos > $colwidth} { - return $colwidth + 1 + if {$endpos > $renderwidth} { + return $renderwidth + 1 } else { return $endpos } @@ -213,7 +213,20 @@ tcl::namespace::eval overtype { if {[llength $args] < 2} { error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} } - lassign [lrange $args end-1 end] underblock overblock + set optargs [lrange $args 0 end-2] + if {[llength $optargs] % 2 == 0} { + lassign [lrange $args end-1 end] underblock overblock + set argsflags [lrange $args 0 end-2] + } else { + set optargs [lrange $args 0 end-1] + if {[llength $optargs] %2 == 0} { + set overblock [lindex $args end] + set underblock "" + set argsflags [lrange $args 0 end-1] + } else { + error "renderspace expects opt-val pairs followed by: or just " + } + } set opts [tcl::dict::create\ -bias ignored\ -width \uFFEF\ @@ -230,12 +243,15 @@ tcl::namespace::eval overtype { -exposed2 \uFFFD\ -experimental 0\ -looplimit \uFFEF\ + -crm_mode 0\ + -reverse_mode 0\ ] #-ellipsis args not used if -wrap is true - set argsflags [lrange $args 0 end-2] foreach {k v} $argsflags { switch -- $k { - -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental { + -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines + - -transparent - -exposed1 - -exposed2 - -experimental + - -reverse_mode - -crm_mode { tcl::dict::set opts $k $v } default { @@ -261,6 +277,8 @@ tcl::namespace::eval overtype { set opt_exposed1 [tcl::dict::get $opts -exposed1] ;#widechar_exposed_left - todo set opt_exposed2 [tcl::dict::get $opts -exposed2] ;#widechar_exposed_right - todo # -- --- --- --- --- --- + set opt_crm_mode [tcl::dict::get $opts -crm_mode] + set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] # ---------------------------- # -experimental dev flag to set flags etc @@ -295,9 +313,10 @@ tcl::namespace::eval overtype { # ---------------------------- #modes - set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l - set autowrap_mode $opt_wrap - set reverse_mode 0 + set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l + set autowrap_mode $opt_wrap + set reverse_mode $opt_reverse_mode + set crm_mode $opt_crm_mode set underblock [tcl::string::map {\r\n \n} $underblock] @@ -307,33 +326,35 @@ tcl::namespace::eval overtype { #set underlines [split $underblock \n] #underblock is a 'rendered' block - so width height make sense - #colwidth & colheight were originally named with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. - #The naming is now confusing. It should be something like renderwidth renderheight ?? review + #only non-cursor affecting and non-width occupying ANSI codes should be present. + #ie SGR codes and perhaps things such as PM - although generally those should have been pushed to the application already + #renderwidth & renderheight were originally used with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. if {$opt_width eq "\uFFEF" || $opt_height eq "\uFFEF"} { - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } if {$opt_height ne "\uFFEF"} { - set colheight $opt_height + set renderheight $opt_height } } else { - set colwidth $opt_width - set colheight $opt_height + set renderwidth $opt_width + set renderheight $opt_height } # -- --- --- --- #REVIEW - do we need ansi resets in the underblock? if {$underblock eq ""} { - set underlines [lrepeat $colheight ""] + set underlines [lrepeat $renderheight ""] } else { + set underblock [textblock::join_basic -- $underblock] ;#ensure properly rendered - ansi per-line resets & replays set underlines [split $underblock \n] } #if {$underblock eq ""} { # set blank "\x1b\[0m\x1b\[0m" # #set underlines [list "\x1b\[0m\x1b\[0m"] - # set underlines [lrepeat $colheight $blank] + # set underlines [lrepeat $renderheight $blank] #} else { # #lines_as_list -ansiresets 1 will do nothing if -ansiresets 1 isn't specified - REVIEW # set underlines [lines_as_list -ansiresets 1 $underblock] @@ -341,7 +362,7 @@ tcl::namespace::eval overtype { # -- --- --- --- #todo - reconsider the 'line' as the natural chunking mechanism for the overlay. - #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth + #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output renderwidth #In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time. #(in cases where there are interline moves or cursor jumps anyway) #This works - but doesn't seem efficient. @@ -409,7 +430,7 @@ tcl::namespace::eval overtype { set replay_codes_underlay [tcl::dict::create 1 ""] #lappend replay_codes_overlay "" - set replay_codes_overlay "" + set replay_codes_overlay "[punk::ansi::a]" set unapplied "" set cursor_saved_position [tcl::dict::create] set cursor_saved_attributes "" @@ -452,14 +473,25 @@ tcl::namespace::eval overtype { } #review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary - #but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l - set LASTCALL [list -info 1 -insert_mode $insert_mode -autowrap_mode $autowrap_mode -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] + set LASTCALL [list -info 1\ + -insert_mode $insert_mode\ + -crm_mode $crm_mode\ + -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -transparent $opt_transparent\ + -width $renderwidth\ + -exposed1 $opt_exposed1\ + -exposed2 $opt_exposed2\ + -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] set rinfo [renderline -experimental $opt_experimental\ -info 1\ + -crm_mode $crm_mode\ -insert_mode $insert_mode\ - -cursor_restore_attributes $cursor_saved_attributes\ -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -cursor_restore_attributes $cursor_saved_attributes\ -transparent $opt_transparent\ - -width $colwidth\ + -width $renderwidth\ -exposed1 $opt_exposed1\ -exposed2 $opt_exposed2\ -overflow $opt_overflow\ @@ -471,7 +503,10 @@ tcl::namespace::eval overtype { set instruction [tcl::dict::get $rinfo instruction] set insert_mode [tcl::dict::get $rinfo insert_mode] set autowrap_mode [tcl::dict::get $rinfo autowrap_mode] ;# - #set reverse_mode [tcl::dict::get $rinfo reverse_mode];#how to support in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + set reverse_mode [tcl::dict::get $rinfo reverse_mode] + #how to support reverse_mode in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + # - review - the answer is probably that we don't need to - it is set/reset only during application of overtext + set crm_mode [tcl::dict::get $rinfo crm_mode] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] set overflow_right_column [tcl::dict::get $rinfo overflow_right_column] @@ -486,7 +521,36 @@ tcl::namespace::eval overtype { set insert_lines_below [tcl::dict::get $rinfo insert_lines_below] tcl::dict::set replay_codes_underlay [expr {$renderedrow+1}] [tcl::dict::get $rinfo replay_codes_underlay] #lset replay_codes_overlay [expr $overidx+1] [tcl::dict::get $rinfo replay_codes_overlay] - set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + if {0 && $reverse_mode} { + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + #review + #JMN3 + set existing_reverse_state 0 + #split_codes_single is single esc sequence - but could have multiple sgr codes within one esc sequence + #e.g \x1b\[0;31;7m has a reset,colour red and reverse + set codeinfo [punk::ansi::codetype::sgr_merge [list $replay_codes_overlay] -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + } @@ -520,7 +584,7 @@ tcl::namespace::eval overtype { incr row if {$data_mode} { set col [_get_row_append_column $row] - if {$col > $colwidth} { + if {$col > $renderwidth} { } } else { @@ -563,10 +627,10 @@ tcl::namespace::eval overtype { #we need renderline to return the number of the maximum column filled (or min if we ever do r-to-l) set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -601,10 +665,10 @@ tcl::namespace::eval overtype { } set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -640,9 +704,9 @@ tcl::namespace::eval overtype { puts stdout ">>>[a+ red bold]overflow_right during restore_cursor[a]" - set sub_info [overtype::renderline -info 1 -width $colwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] + set sub_info [overtype::renderline -info 1 -width $renderwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] set foldline [tcl::dict::get $sub_info result] - set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed.. + set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed..? set autowrap_mode [tcl::dict::get $sub_info autowrap_mode] ;#nor this.. linsert outputlines $renderedrow $foldline #review - row & col set by restore - but not if there was no save.. @@ -740,7 +804,7 @@ tcl::namespace::eval overtype { } } lf_overflow { - #linefeed after colwidth e.g at column 81 for an 80 col width + #linefeed after renderwidth e.g at column 81 for an 80 col width #we may also have other control sequences that came after col 80 e.g cursor save if 0 { @@ -833,10 +897,10 @@ tcl::namespace::eval overtype { } else { set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } } @@ -845,12 +909,12 @@ tcl::namespace::eval overtype { #doesn't seem to be used by fruit.ans testfile #used by dzds.ans #note that cursor_forward may move deep into the next line - or even span multiple lines !TODO - set c $colwidth + set c $renderwidth set r $post_render_row - if {$post_render_col > $colwidth} { + if {$post_render_col > $renderwidth} { set i $c while {$i <= $post_render_col} { - if {$c == $colwidth+1} { + if {$c == $renderwidth+1} { incr r if {$opt_appendlines} { if {$r < [llength $outputlines]} { @@ -874,7 +938,7 @@ tcl::namespace::eval overtype { set col $c } wrapmovebackward { - set c $colwidth + set c $renderwidth set r $post_render_row if {$post_render_col < 1} { set c 1 @@ -883,7 +947,7 @@ tcl::namespace::eval overtype { if {$c == 0} { if {$r > 1} { incr r -1 - set c $colwidth + set c $renderwidth } else { #leave r at 1 set c 1 #testfile besthpav.ans first line top left border alignment @@ -941,7 +1005,7 @@ tcl::namespace::eval overtype { #2nd half of grapheme would overflow - treggering grapheme is returned in unapplied. There may also be overflow_right from earlier inserts #todo - consider various options .. re-render a single trailing space or placeholder on same output line, etc if {$autowrap_mode} { - if {$colwidth < 2} { + if {$renderwidth < 2} { #edge case of rendering to a single column output - any 2w char will just cause a loop if we don't substitute with something, or drop the character set idx 0 set triggering_grapheme_index -1 @@ -960,7 +1024,7 @@ tcl::namespace::eval overtype { } else { set overflow_handled 1 #handled by dropping entire overflow if any - if {$colwidth < 2} { + if {$renderwidth < 2} { set idx 0 set triggering_grapheme_index -1 foreach u $unapplied_list { @@ -1141,12 +1205,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + #set renderwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] - #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {$colwidth - $overblock_width}] + set under_exposed_max [expr {$renderwidth - $overblock_width}] if {$under_exposed_max > 0} { #background block is wider if {$under_exposed_max % 2 == 0} { @@ -1176,14 +1239,14 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] set undertext "$undertext[string repeat { } $udiff]" } set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] #review - right-to-left langs should elide on left! - extra option required if {$overflowlength > 0} { @@ -1196,8 +1259,8 @@ tcl::namespace::eval overtype { #overlay line data is wider - trim if overflow not specified in opts - and overtype an ellipsis at right if it was specified if {![tcl::dict::get $opts -overflow]} { - #lappend outputlines [tcl::string::range $overtext 0 [expr {$colwidth - 1}]] - #set overtext [tcl::string::range $overtext 0 $colwidth-1 ] + #lappend outputlines [tcl::string::range $overtext 0 [expr {$renderwidth - 1}]] + #set overtext [tcl::string::range $overtext 0 $renderwidth-1 ] if {$opt_ellipsis} { set show_ellipsis 1 if {!$opt_ellipsiswhitespace} { @@ -1286,12 +1349,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] set left_exposed $under_exposed_max @@ -1307,8 +1369,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1336,10 +1398,17 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline\ + -info 1\ + -insert_mode 0\ + -transparent $opt_transparent\ + -exposed1 $opt_exposed1 -exposed2 $opt_exposed2\ + -overflow $opt_overflow\ + -startcolumn [expr {1 + $startoffset}]\ + $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] if {!$opt_overflow} { @@ -1433,12 +1502,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] switch -- $opt_blockalign { left { @@ -1484,8 +1552,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1513,7 +1581,7 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] @@ -1566,6 +1634,7 @@ tcl::namespace::eval overtype { #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #puts stderr "--> [ansistring VIEW -lf 1 -nul 1 $rinfo] <--" set overflow_right [tcl::dict::get $rinfo overflow_right] set unapplied [tcl::dict::get $rinfo unapplied] lappend outputlines [tcl::dict::get $rinfo result] @@ -1629,6 +1698,7 @@ tcl::namespace::eval overtype { -cursor_column 1\ -cursor_row ""\ -insert_mode 1\ + -crm_mode 0\ -autowrap_mode 1\ -reverse_mode 0\ -info 0\ @@ -1649,7 +1719,9 @@ tcl::namespace::eval overtype { set argsflags [lrange $args 0 end-2] tcl::dict::for {k v} $argsflags { switch -- $k { - -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -autowrap_mode - -reverse_mode - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { + -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row + - -crm_mode - -insert_mode - -autowrap_mode - -reverse_mode + - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { tcl::dict::set opts $k $v } default { @@ -1676,6 +1748,7 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_autowrap_mode [tcl::dict::get $opts -autowrap_mode] ;#DECAWM - char or movement can go beyond leftmost/rightmost col to prev/next line set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] ;#DECSNM + set opt_crm_mode [tcl::dict::get $opts -crm_mode];# CRM - show control character mode # -- --- --- --- --- --- --- --- --- --- --- --- set temp_cursor_saved [tcl::dict::get $opts -cursor_restore_attributes] @@ -1721,6 +1794,10 @@ tcl::namespace::eval overtype { set cursor_row $opt_row_context } + set insert_mode $opt_insert_mode ;#default 1 + set autowrap_mode $opt_autowrap_mode ;#default 1 + set crm_mode $opt_crm_mode ;#default 0 (Show Control Character mode) + set reverse_mode $opt_reverse_mode #----- # @@ -1768,6 +1845,7 @@ tcl::namespace::eval overtype { } set understacks [list] set understacks_gx [list] + set pm_list [list] set i_u -1 ;#underlay may legitimately be empty set undercols [list] @@ -1834,6 +1912,7 @@ tcl::namespace::eval overtype { #underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc + #keep any remaining PMs in place if {$code ne ""} { set c1c2 [tcl::string::range $code 0 1] @@ -1841,6 +1920,8 @@ tcl::namespace::eval overtype { \x1b\[ 7CSI\ \x9b 8CSI\ \x1b\( 7GFX\ + \x1b^ 7PMX\ + \x1bX 7SOS\ ] $c1c2] 0 3];# leadernorm is 1st 2 chars mapped to normalised indicator - or is original 2 chars switch -- $leadernorm { @@ -1875,6 +1956,26 @@ tcl::namespace::eval overtype { } } } + 7PMX - 7SOS { + #we can have PMs or SOS (start of string) in the underlay - though mostly the PMs should have been processed.. + #attach the PM/SOS (entire ANSI sequence) to the previous grapheme! + #It should not affect the size - but terminal display may get thrown out if terminal doesn't support them. + + #note that there may in theory already be ANSI stored - we don't assume it was a pure grapheme string + set graphemeplus [lindex $undercols end] + if {$graphemeplus ne "\0"} { + append graphemeplus $code + } else { + set graphemeplus $code + } + lset undercols end $graphemeplus + #The grapheme_width_cached function will be called on this later - and doesn't account for ansi. + #we need to manually cache the item with it's proper width + variable grapheme_widths + #stripped and plus version keys pointing to same length + dict set grapheme_widths $graphemeplus [grapheme_width_cached [::punk::ansi::ansistrip $graphemeplus]] + + } default { } @@ -1937,9 +2038,9 @@ tcl::namespace::eval overtype { } if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } else { - set colwidth [llength $undercols] + set renderwidth [llength $undercols] } @@ -2017,12 +2118,30 @@ tcl::namespace::eval overtype { } append pt_overchars $pt #will get empty pt between adjacent codes - foreach grapheme [punk::char::grapheme_split $pt] { - lappend overstacks $o_codestack - lappend overstacks_gx $o_gxstack - incr i_o - lappend overlay_grapheme_control_list [list g $grapheme] - lappend overlay_grapheme_control_stacks $o_codestack + if {!$crm_mode} { + foreach grapheme [punk::char::grapheme_split $pt] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } else { + foreach grapheme_original [punk::char::grapheme_split $pt] { + set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original] + foreach grapheme [punk::char::grapheme_split $pt_crm] { + if {$grapheme eq "\n"} { + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"] + } else { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + } } #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc @@ -2030,40 +2149,91 @@ tcl::namespace::eval overtype { # that pure resets are fairly common - more so than leading resets with other info # that non-sgr codes are not that common, so ok to check for resets before verifying it is actually SGR at all. if {$code ne ""} { - lappend overlay_grapheme_control_stacks $o_codestack - #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) - if {[punk::ansi::codetype::is_sgr_reset $code]} { - set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set o_codestack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #basic simplification first - remove straight dupes - set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars - set o_codestack [lremove $o_codestack {*}$dup_posns] - lappend o_codestack $code - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[regexp {\x1b7|\x1b\[s} $code]} { - #experiment - #cursor_save - for the replays review. - #jmn - #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] - lappend overlay_grapheme_control_list [list other $code] - } elseif {[regexp {\x1b8|\x1b\[u} $code]} { - #experiment - #cursor_restore - for the replays - set o_codestack [list $temp_cursor_saved] - lappend overlay_grapheme_control_list [list other $code] + #we need to immediately set crm_mode here if \x1b\[3h received + if {$code eq "\x1b\[3h"} { + set crm_mode 1 + } elseif {$code eq "\x1b\[3l"} { + set crm_mode 0 + } + #else crm_mode could be set either way from options + if {$crm_mode && $code ne "\x1b\[00001E"} { + #treat the code as type 'g' like above - only allow through codes to reset mode REVIEW for now just \x1b\[3l ? + #we need to somehow convert further \n in the graphical rep to an instruction for newline that will bypass further crm_mode processing or we would loop. + set code_as_pt [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $code] + #split using standard split for first foreach loop - grapheme based split when processing 2nd foreach loop + set chars [split $code_as_pt ""] + set codeparts [list] ;#list of 2-el lists each element {crmcontrol } or {g } + foreach c $chars { + if {$c eq "\n"} { + #use CNL (cursor next line) \x1b\[00001E ;#leading zeroes ok for this processor - used as debugging aid to distinguish + lappend codeparts [list crmcontrol "\x1b\[00001E"] + } else { + if {[llength $codeparts] > 0 && [lindex $codeparts end 0] eq "g"} { + set existing [lindex $codeparts end 1] + lset codeparts end [list g [string cat $existing $c]] + } else { + lappend codeparts [list g $c] + } + } + } + + set partidx 0 + foreach record $codeparts { + lassign $record rtype rval + switch -exact -- $rtype { + g { + append pt_overchars $rval + foreach grapheme [punk::char::grapheme_split $rval] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + crmcontrol { + #leave o_codestack + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol $rval] + } + } + } } else { - if {[punk::ansi::codetype::is_gx_open $code]} { - set o_gxstack [list "gx0_on"] - lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } elseif {[punk::ansi::codetype::is_gx_close $code]} { - set o_gxstack [list] - lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } else { + lappend overlay_grapheme_control_stacks $o_codestack + #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) + if {[punk::ansi::codetype::is_sgr_reset $code]} { + set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set o_codestack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #basic simplification first - remove straight dupes + set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars + set o_codestack [lremove $o_codestack {*}$dup_posns] + lappend o_codestack $code + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[regexp {\x1b7|\x1b\[s} $code]} { + #experiment + #cursor_save - for the replays review. + #jmn + #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] + lappend overlay_grapheme_control_list [list other $code] + } elseif {[regexp {\x1b8|\x1b\[u} $code]} { + #experiment + #cursor_restore - for the replays + set o_codestack [list $temp_cursor_saved] lappend overlay_grapheme_control_list [list other $code] + } else { + if {[punk::ansi::codetype::is_gx_open $code]} { + set o_gxstack [list "gx0_on"] + lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } elseif {[punk::ansi::codetype::is_gx_close $code]} { + set o_gxstack [list] + lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } else { + lappend overlay_grapheme_control_list [list other $code] + } } } } @@ -2135,9 +2305,6 @@ tcl::namespace::eval overtype { #movements only occur within the overlay range. #an underlay is however not necessary.. e.g #renderline -overflow 1 "" data - #foreach {pt code} $overmap {} - set insert_mode $opt_insert_mode ;#default 1 - set autowrap_mode $opt_autowrap_mode ;#default 1 #set re_mode {\x1b\[\?([0-9]*)(h|l)} ;#e.g DECAWM #set re_col_move {\x1b\[([0-9]*)(C|D|G)$} @@ -2163,13 +2330,28 @@ tcl::namespace::eval overtype { switch -- $type { g { set ch $item + #crm_mode affects both graphic and control + if {$crm_mode} { + set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $ch] + set chars [string map [list \n "\x1b\[00001E"] $chars] + if {[llength [split $chars ""]] > 1} { + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + #incr idx_over + break + } else { + set ch $chars + } + } incr idx_over; #idx_over (until unapplied reached anyway) is per *grapheme* in the overlay - not per col. if {($idx < ($opt_colstart -1))} { incr idx [grapheme_width_cached $ch] continue } #set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our active data width - set within_undercols [expr {$idx <= $colwidth-1}] + set within_undercols [expr {$idx <= $renderwidth-1}] #https://www.enigma.com/resources/blog/the-secret-world-of-newline-characters #\x85 NEL in the c1 control set is treated by some terminal emulators (e.g Hyper) as a newline, @@ -2311,6 +2493,7 @@ tcl::namespace::eval overtype { } else { #todo - punk::char::char_width set g [lindex $outcols $idx] + #JMN set uwidth [grapheme_width_cached $g] if {[lindex $outcols $idx] eq ""} { #2nd col of 2-wide char in underlay @@ -2485,13 +2668,29 @@ tcl::namespace::eval overtype { } - other { + other - crmcontrol { + if {$crm_mode && $type ne "crmcontrol" && $item ne "\x1b\[00001E"} { + if {$item eq "\x1b\[3l"} { + set crm_mode 0 + } else { + #When our initial overlay split was done - we weren't in crm_mode - so there are codes that weren't mapped to unicode control character representations + #set within_undercols [expr {$idx <= $renderwidth-1}] + #set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $item] + set chars [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $item] + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + + break + } + } + #todo - consider CSI s DECSLRM vs ansi.sys \x1b\[s - we need \x1b\[s for oldschool ansi art - but may have to enable only for that. - #we should probably therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore + #we should possibly therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore? set code [tcl::string::map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $item] #since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied' - set matchinfo [list] #remap of DEC cursor_save/cursor_restore from ESC sequence to equivalent CSI #probably not ideal - consider putting cursor_save/cursor_restore in functions so they can be called from the appropriate switch branch instead of using this mapping @@ -2501,7 +2700,7 @@ tcl::namespace::eval overtype { set c1c2c3 [tcl::string::range $code 0 2] #set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)} #tcl 8.7 - faster to use inline list than to store it in a local var outside of loop. - #(surprising - but presumably ) + #(somewhat surprising) set leadernorm [tcl::string::range [tcl::string::map [list\ \x1b\[< 1006\ \x1b\[ 7CSI\ @@ -2509,7 +2708,7 @@ tcl::namespace::eval overtype { \x1b\] 7OSC\ \x9d 8OSC\ \x1b 7ESC\ - ] $c1c2c3] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars + ] $c1c2c3] 0 3] ;#leadernorm is 1st 1,2 or 3 chars mapped to 4char normalised indicator - or is original first chars (1,2 or 3 len) #we leave the tail of the code unmapped for now switch -- $leadernorm { @@ -2528,7 +2727,10 @@ tcl::namespace::eval overtype { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } default { + puts stderr "Sequence detected as ANSI, but not handled in leadernorm switch. code: [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" #we haven't made a mapping for this + #could in theory be 1,2 or 3 in len + #although we shouldn't be getting here if the regexp for ansi codes is kept in sync with our switch branches set codenorm $code } } @@ -2551,44 +2753,44 @@ tcl::namespace::eval overtype { {7CSI} - {8CSI} { set param [tcl::string::range $codenorm 4 end-1] #puts stdout "--> CSI [tcl::string::index $leadernorm 0] bit param:$param" - switch -- [tcl::string::index $codenorm end] { - D { - #Col move - #puts stdout "<-back" - #cursor back - #left-arrow/move-back when ltr mode + set code_end [tcl::string::index $codenorm end] ;#used for e.g h|l set/unset mode + switch -exact -- $code_end { + A { + #Row move - up + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set num $param if {$num eq ""} {set num 1} + incr cursor_row -$num - set version 2 - if {$version eq "2"} { - #todo - startcolumn offset! - if {$cursor_column - $num >= 1} { - incr idx -$num - incr cursor_column -$num - } else { - if {!$autowrap_mode} { - set cursor_column 1 - set idx 0 - } else { - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - incr cursor_column -$num - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction wrapmovebackward - break - } - } - } else { - incr idx -$num - incr cursor_column -$num - if {$idx < $opt_colstart-1} { - #wrap to previous line and position cursor at end of data - set idx [expr {$opt_colstart-1}] - set cursor_column $opt_colstart - } + if {$cursor_row < 1} { + set cursor_row 1 } + + #ensure rest of *overlay* is emitted to remainder + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction up + #retain cursor_column + break + } + B { + #CUD - Cursor Down + #Row move - down + set num $param + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #move down + if {$num eq ""} {set num 1} + incr cursor_row $num + + + incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction down + #retain cursor_column + break } C { + #CUF - Cursor Forward #Col move #puts stdout "->forward" #todo - consider right-to-left cursor mode (e.g Hebrew).. some day. @@ -2692,80 +2894,215 @@ tcl::namespace::eval overtype { } } } - G { + D { #Col move - #move absolute column - #adjust to colstart - as column 1 is within overlay - #??? - set idx [expr {$param + $opt_colstart -1}] - set cursor_column $param - error "renderline absolute col move ESC G unimplemented" - } - A { - #Row move - up - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #puts stdout "<-back" + #cursor back + #left-arrow/move-back when ltr mode set num $param if {$num eq ""} {set num 1} - incr cursor_row -$num - if {$cursor_row < 1} { - set cursor_row 1 + set version 2 + if {$version eq "2"} { + #todo - startcolumn offset! + if {$cursor_column - $num >= 1} { + incr idx -$num + incr cursor_column -$num + } else { + if {!$autowrap_mode} { + set cursor_column 1 + set idx 0 + } else { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr cursor_column -$num + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction wrapmovebackward + break + } + } + } else { + incr idx -$num + incr cursor_column -$num + if {$idx < $opt_colstart-1} { + #wrap to previous line and position cursor at end of data + set idx [expr {$opt_colstart-1}] + set cursor_column $opt_colstart + } } - - #ensure rest of *overlay* is emitted to remainder + } + E { + #CNL - Cursor Next Line + if {$param eq ""} { + set downmove 1 + } else { + set downmove [expr {$param}] + } + puts stderr "renderline CNL down-by-$downmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row + $downmove}] + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction up - #retain cursor_column - break + set instruction move + break + } - B { - #Row move - down - set num $param + F { + #CPL - Cursor Previous Line + if {$param eq ""} { + set upmove 1 + } else { + set upmove [expr {$param}] + } + puts stderr "renderline CPL up-by-$upmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row -$upmove}] + if {$cursor_row < 1} { + set cursor_row 1 + } + set idx [expr {$cursor_column - 1}] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #move down - if {$num eq ""} {set num 1} - incr cursor_row $num - - - incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction down - #retain cursor_column - break + set instruction move + break + + } + G { + #CHA - Cursor Horizontal Absolute (move to absolute column no) + if {$param eq ""} { + set targetcol 1 + } else { + set targetcol $param + if {![string is integer -strict $targetcol]} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Unrecognised parameter '$param'" + } + set targetcol [expr {$param}] + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$targetcol > $max} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Param '$param' > max: $max" + set targetcol $max + } + } + #adjust to colstart - as column 1 is within overlay + #??? REVIEW + set idx [expr {($targetcol -1) + $opt_colstart -1}] + + + set cursor_column $targetcol + #puts stderr "renderline absolute col move ESC G (TEST)" } H - f { - #$re_both_move - lassign [split $param {;}] row col - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #lassign $matchinfo _match row col + #CSI n;m H - CUP - Cursor Position - if {$col eq ""} {set col 1} - set max [llength $outcols] - if {$overflow_idx == -1} { - incr max - } - if {$col > $max} { - set cursor_column $max + #CSI n;m f - HVP - Horizontal Vertical Position REVIEW - same as CUP with differences (what?) in some terminal modes + # - 'counts as effector format function (like CR or LF) rather than an editor function (like CUD or CNL)' + # - REVIEW + #see Annex A at: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf + + #test e.g ansicat face_2.ans + #$re_both_move + lassign [split $param {;}] paramrow paramcol + #missing defaults to 1 + #CSI ;5H = CSI 1;5H -> row 1 col 5 + #CSI 17;H = CSI 17H = CSI 17;1H -> row 17 col 1 + + if {$paramcol eq ""} {set paramcol 1} + if {$paramrow eq ""} {set paramrow 1} + if {![string is integer -strict $paramcol] || ![string is integer -strict $paramrow]} { + puts stderr "renderline CUP (CSI H) unrecognised param $param" + #ignore? } else { - set cursor_column $col + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$paramcol > $max} { + set target_column $max + } else { + set target_column [expr {$paramcol}] + } + + + if {$paramrow < 1} { + puts stderr "renderline CUP (CSI H) bad row target 0. Assuming 1" + set target_row 1 + } else { + set target_row [expr {$paramrow}] + } + if {$target_row == $cursor_row} { + #col move only - no need for break and move + #puts stderr "renderline CUP col move only to col $target_column param:$param" + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + } else { + set cursor_row $target_row + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } } - set idx [expr {$cursor_column -1}] + } + J { + puts stderr "overtype::renderline ED - ERASE IN DISPLAY (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of screen + } + 1 { + #clear from cursor to beginning of screen + } + 2 { + #clear entire screen + #ansi.sys - move cursor to upper left REVIEW + set cursor_row 1 + set cursor_column 1 + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } + 3 { + #clear entire screen. presumably cursor doesn't move - otherwise it would be same as 2J ? - if {$row eq ""} {set row 1} - set cursor_row $row - if {$cursor_row < 1} { - set cursor_row 1 + } + default { + } } - incr idx_over - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction move - break + } + K { + puts stderr "overtype::renderline EL - ERASE IN LINE (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line + } + 1 { + #clear from cursor to beginning of line + } + 2 { + #clear entire line + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } } X { - puts stderr "X - $param" + puts stderr "overtype::renderline X ECH ERASE CHARACTER - $param" #ECH - erase character if {$param eq "" || $param eq "0"} {set param 1}; #param=count of chars to erase priv::render_erasechar $idx $param @@ -2789,78 +3126,119 @@ tcl::namespace::eval overtype { break } s { - # - todo - make ansi.sys CSI s cursor save only apply for certain cases? - may need to support DECSLRM instead which uses same code - - #$re_cursor_save - #cursor save could come after last column - if {$overflow_idx != -1 && $idx == $overflow_idx} { - #bartman2.ans test file - fixes misalignment at bottom of dialog bubble - #incr cursor_row - #set cursor_column 1 - #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) - set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] - } else { - set cursor_saved_position [list row $cursor_row column $cursor_column] - } - #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. - #we need the SGR and gx overlay codes prior to the cursor_save + #code conflict between ansi emulation and DECSLRM - REVIEW + #ANSISYSSC (when no parameters) - like other terminals - essentially treat same as DECSC + # todo - when parameters - support DECSLRM instead + + if {$param ne ""} { + #DECSLRM - should only be recognised if DECLRMM is set (vertical split screen mode) + lassign [split $param {;} margin_left margin_right + puts stderr "overtype DECSLRM not yet supported - got [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$margin_left eq ""} { + set margin_left 1 + } + set columns_per_page 80 ;#todo - set to 'page width (DECSCPP set columns per page)' - could be 132 or?? + if {$margin_right eq ""} { + set margin_right $columns_per_page + } + puts stderr "DECSLRM margin left: $margin_left margin right: $margin_right" + if {![string is integer -strict $margin_left] || $margin_left < 0} { + puts stderr "DECSLRM invalid margin_left" + } + if {![string is integer -strict $margin_right] || $margin_right < 0} { + puts stderr "DECSLRM invalid margin_right" + } + set scrolling_region_size [expr {$margin_right - $margin_left}] + if {$scrolling_region_size < 2 || $scrolling_region_size > $columns_per_page} { + puts stderr "DECSLRM region size '$scrolling_regsion_size' must be between 1 and $columns_per_page" + } + #todo - #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. - #set sgr_stack [lindex $understacks $idx] - #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) - - set sgr_stack [list] - set gx_stack [list] - - #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. - #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. - - foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { - lassign $gc type code - #types g other sgr gx0 - switch -- $type { - gx0 { - #code is actually a stand-in for the graphics on/off code - not the raw code - #It is either gx0_on or gx0_off - set gx_stack [list $code] - } - sgr { - #code is the raw code - if {[punk::ansi::codetype::is_sgr_reset $code]} { - #jmn - set sgr_stack [list "\x1b\[m"] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set sgr_stack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #often we don't get resets - and codes just pile up. - #as a first step to simplifying - at least remove earlier straight up dupes - set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) - set sgr_stack [lremove $sgr_stack {*}$dup_posns] - lappend sgr_stack $code + + } else { + #DECSC + #//notes on expected behaviour: + #DECSC - saves following items in terminal's memory + #cursor position + #character attributes set by the SGR command + #character sets (G0,G1,G2 or G3) currently in GL and GR + #Wrap flag (autowrap or no autowrap) + #State of origin mode (DECOM) + #selective erase attribute + #any single shift 2 (SS2) or single shift 3(SSD) functions sent + + #$re_cursor_save + #cursor save could come after last column + if {$overflow_idx != -1 && $idx == $overflow_idx} { + #bartman2.ans test file - fixes misalignment at bottom of dialog bubble + #incr cursor_row + #set cursor_column 1 + #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) + set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] + } else { + set cursor_saved_position [list row $cursor_row column $cursor_column] + } + #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. + #we need the SGR and gx overlay codes prior to the cursor_save + + #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. + #set sgr_stack [lindex $understacks $idx] + #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) + + set sgr_stack [list] + set gx_stack [list] + + #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. + #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. + + foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { + lassign $gc type code + #types g other sgr gx0 + switch -- $type { + gx0 { + #code is actually a stand-in for the graphics on/off code - not the raw code + #It is either gx0_on or gx0_off + set gx_stack [list $code] + } + sgr { + #code is the raw code + if {[punk::ansi::codetype::is_sgr_reset $code]} { + #jmn + set sgr_stack [list "\x1b\[m"] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set sgr_stack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #often we don't get resets - and codes just pile up. + #as a first step to simplifying - at least remove earlier straight up dupes + set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) + set sgr_stack [lremove $sgr_stack {*}$dup_posns] + lappend sgr_stack $code + } } } } - } - set cursor_saved_attributes "" - switch -- [lindex $gx_stack 0] { - gx0_on { - append cursor_saved_attributes "\x1b(0" - } - gx0_off { - append cursor_saved_attributes "\x1b(B" + set cursor_saved_attributes "" + switch -- [lindex $gx_stack 0] { + gx0_on { + append cursor_saved_attributes "\x1b(0" + } + gx0_off { + append cursor_saved_attributes "\x1b(B" + } } - } - #append cursor_saved_attributes [join $sgr_stack ""] - append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] + #append cursor_saved_attributes [join $sgr_stack ""] + append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] - #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. + #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. - #don't incr index - or the save will cause cursor to move to the right - #carry on - + #don't incr index - or the save will cause cursor to move to the right + #carry on + } } u { + #ANSISYSRC save cursor (when no parameters) (DECSC) + #$re_cursor_restore #we are going to jump somewhere.. for now we will assume another line, and process accordingly. #The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line) @@ -2903,7 +3281,6 @@ tcl::namespace::eval overtype { } ~ { #$re_vt_sequence - #lassign $matchinfo _match key mod lassign [split $param {;}] key mod #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ @@ -2972,64 +3349,129 @@ tcl::namespace::eval overtype { } h - l { + #set mode unset mode #we are matching only last char to get to this arm - but are there other sequences ending in h|l we need to handle? #$re_mode if first after CSI is "?" #some docs mention ESC=h|l - not seen on windows terminals.. review #e.g https://www2.math.upenn.edu/~kazdan/210/computer/ansi.html - if {[tcl::string::index $codenorm 4] eq "?"} { - set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l - #lassign $matchinfo _match num type - switch -- $num { - 5 { - #DECSNM - reverse video - #How we simulate this to render within a block of text is an open question. - #track all SGR stacks and constantly flip based on the current SGR reverse state? - #It is the job of the calling loop to do this - so at this stage we'll just set the states - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set reverse_mode 1 - } else { - #reset (disable) - set reverse_mode 0 + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? = + switch -exact -- $modegroup { + ? { + set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l + switch -- $num { + 5 { + #DECSNM - reverse video + #How we simulate this to render within a block of text is an open question. + #track all SGR stacks and constantly flip based on the current SGR reverse state? + #It is the job of the calling loop to do this - so at this stage we'll just set the states + + if {$code_end eq "h"} { + #set (enable) + set reverse_mode 1 + } else { + #reset (disable) + set reverse_mode 0 + } + + } + 7 { + #DECAWM autowrap + if {$code_end eq "h"} { + #set (enable) + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } + #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. + if {$idx >= $overflow_idx} { + puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + } else { + #reset (disable) + set autowrap_mode 0 + set overflow_idx -1 + } } + 25 { + if {$code_end eq "h"} { + #visible cursor + } else { + #invisible cursor + + } + } } - 7 { - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set autowrap_mode 1 - if {$opt_width ne "\uFFEF"} { - set overflow_idx $opt_width + } + = { + set num [tcl::string::range $codenorm 5 end-1] ;#param between = and h|l + puts stderr "overtype::renderline CSI=...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + #e.g CSI 4 h + set num [tcl::string::range $codenorm 4 end-1] ;#param before h|l + switch -exact -- $num { + 3 { + puts stderr "CRM MODE $code_end" + #CRM - Show control character mode + # 'No control functions are executed except LF,FF and VT which are represented in the CRM FONT before a CRLF(new line) is executed' + # + #use ansistring VIEW -nul 1 -lf 2 -ff 2 -vt 2 + #https://vt100.net/docs/vt510-rm/CRM.html + if {$code_end eq "h"} { + set crm_mode 1 } else { - #review - this is also the cursor position when adding a char at end of line? - set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + set crm_mode 0 } - #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. - if {$idx >= $overflow_idx} { - puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + 4 { + #IRM - Insert/Replace Mode + if {$code_end eq "h"} { + set insert_mode 1 + } else { + #replace mode + set insert_mode 0 } - } else { - #reset (disable) - set autowrap_mode 0 - set overflow_idx -1 } + default { + puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + } + } + } + } + | { + switch -- [tcl::string::index $codenorm end-1] { + {$} { + #CSI ... $ | DECSCPP set columns per page- (recommended in vt510 docs as preferable to DECCOLM) + #real terminals generally only supported 80/132 + #some other virtuals support any where from 2 to 65,536? + #we will allow arbitrary widths >= 2 .. to some as yet undetermined limit. + #CSI $ | + #empty or 0 param is 80 for compatibility - other numbers > 2 accepted + set page_width -1 ;#flag as unset + if {$param eq ""} { + set page_width 80 + } elseif {[string is integer -strict $param] && $param >=2 0} { + set page_width [expr {$param}] ;#we should allow leading zeros in the number - but lets normalize using expr + } else { + puts stderr "overtype::renderline unacceptable DECSPP value '$param'" } - 25 { - if {$type eq "h"} { - #visible cursor - } else { - #invisible cursor + if {$page_width > 2} { + puts stderr "overtype::renderline DECSCPP - not implemented - but selected width '$page_width' looks ok" + #if cursor already beyond new page_width - will move to right colum - otherwise no cursor movement - } } - } - } else { - puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + puts stderr "overtype::renderline unrecognised CSI code ending in pipe (|) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } } } default { @@ -3038,8 +3480,9 @@ tcl::namespace::eval overtype { } } 7ESC { - #$re_other_single - switch -- [tcl::string::index $codenorm end] { + #re_other_single {\x1b(D|M|E)$} + #also PM \x1b^...(ST) + switch -- [tcl::string::index $codenorm 4] { D { #\x84 #index (IND) @@ -3080,20 +3523,66 @@ tcl::namespace::eval overtype { puts stderr "ESC E unimplemented" } + ^ { + #puts stderr "renderline PM" + #Privacy Message. + if {[string index $code end] eq "\007"} { + set pm_content [string range $code 2 end-1] ;#ST is \007 + } else { + set pm_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #We don't want to render it - but we need to make it available to the application + #see the textblock library in punk, for the exception we make here for single backspace. + #It is unlikely to be encountered as a useful PM - so we hack to pass it through as a fix + #for spacing issues on old terminals which miscalculate the single-width 'Symbols for Legacy Computing' + if {$pm_content eq "\b"} { + #puts stderr "renderline PM sole backspace special handling for \U1FB00 - \U1FBFF" + #esc^\b\007 or esc^\besc\\ + #HACKY pass-through - targeting terminals that both mis-space legacy symbols *and* don't support PMs + #The result is repair of the extra space. If the terminal is a modern one and does support PM - the \b should be hidden anyway. + #If the terminal has the space problem AND does support PMs - then this just won't fix it. + #The fix relies on the symbol-supplier to cooperate by appending esc^\b\esc\\ to the problematic symbols. + + #priv::render_addchar $idx $code [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode + #idx has been incremented after last grapheme added + priv::render_append_to_char [expr {$idx -1}] $code + } + #lappend to a dict element in the result for application-specific processing + lappend pm_list $pm_content + } + N - O { + puts stderr "overtype::renderline single shift command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + P { + puts stderr "overtype::renderline DEVICE CONTROL STRING command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + X { + #SOS + if {[string index $code end] eq "\007"} { + set sos_content [string range $code 2 end-1] ;#ST is \007 + } else { + set sos_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #return in some useful form to the caller + #TODO! + lappend sos_list [list string $sos_content row $cursor_row column $cursor_column] + puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + _ { + #APC Application Program Command + #just warn for now.. + puts stderr "overtype::renderline ESC_ APC command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } default { - puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented codenorm:[ansistring VIEW -lf 1 -vt 1 -nul 1 $codenorm]" } } } + default { + } } - #switch -regexp -matchvar matchinfo -- $code\ - #$re_mode { - #}\ - #default { - # puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" - #} } default { @@ -3275,8 +3764,10 @@ tcl::namespace::eval overtype { overflow_right $overflow_right\ unapplied $unapplied\ unapplied_list $unapplied_list\ - insert_mode $insert_mode\ - autowrap_mode $autowrap_mode\ + insert_mode $insert_mode\ + autowrap_mode $autowrap_mode\ + crm_mode $crm_mode\ + reverse_mode $reverse_mode\ insert_lines_above $insert_lines_above\ insert_lines_below $insert_lines_below\ cursor_saved_position $cursor_saved_position\ @@ -3287,6 +3778,7 @@ tcl::namespace::eval overtype { replay_codes $replay_codes\ replay_codes_underlay $replay_codes_underlay\ replay_codes_overlay $replay_codes_overlay\ + pm_list $pm_list\ ] if {$opt_returnextra == 1} { return $result @@ -3370,8 +3862,9 @@ tcl::namespace::eval overtype::piper { } interp alias "" piper_renderline "" overtype::piper::renderline -#intended for single grapheme - but will work for multiple -#cannot contain ansi or newlines +#intended primarily for single grapheme - but will work for multiple +#WARNING: query CAN contain ansi or newlines - but if cache was not already set manually,the answer will be incorrect! +#We deliberately allow this for PM/SOS attached within a column #(a cache of ansifreestring_width calls - as these are quite regex heavy) proc overtype::grapheme_width_cached {ch} { variable grapheme_widths @@ -3439,6 +3932,7 @@ tcl::namespace::eval overtype::priv { tcl::dict::set cache_is_sgr $code $answer return $answer } + # better named render_to_unapplied? proc render_unapplied {overlay_grapheme_control_list gci} { upvar idx_over idx_over upvar unapplied unapplied @@ -3532,7 +4026,7 @@ tcl::namespace::eval overtype::priv { set ustacks [lreplace $ustacks $i $i] set gxstacks [lreplace $gxstacks $i $i] } else { - + puts stderr "render_delchar - attempt to delchar at index $i >= number of outcols $nxt - shouldn't happen" } } proc render_erasechar {i count} { @@ -3563,21 +4057,68 @@ tcl::namespace::eval overtype::priv { upvar outcols o lset o $i $c } + + #Initial usecase is for old-terminal hack to add PM-wrapped \b + #review - can be used for other multibyte sequences that occupy one column? + #combiners? diacritics? + proc render_append_to_char {i c} { + upvar outcols o + if {$i > [llength $o]-1} { + error "render_append_to_char cannot append [ansistring VIEW -lf 1 -nul 1 $c] to existing char at index $i while $i >= llength outcols [llength $o]" + } + set existing [lindex $o $i] + if {$existing eq "\0"} { + lset o $i $c + } else { + lset o $i [string cat $existing $c] + } + } #is actually addgrapheme? proc render_addchar {i c sgrstack gx0stack {insert_mode 0}} { upvar outcols o upvar understacks ustacks upvar understacks_gx gxstacks - if 0 { - if {$c eq "c"} { - puts "i:$i c:$c sgrstack:[ansistring VIEW $sgrstack]" - puts "understacks:[ansistring VIEW $ustacks]" - upvar overstacks overstacks - puts "overstacks:[ansistring VIEW $overstacks]" - puts "info level 0:[info level 0]" - } + # -- --- --- + #this is somewhat of a hack.. probably not really the equivalent of proper reverse video? review + #we should ideally be able to reverse the video of a sequence that already includes SGR reverse/noreverse attributes + upvar reverse_mode do_reverse + #if {$do_reverse} { + # lappend sgrstack [a+ reverse] + #} else { + # lappend sgrstack [a+ noreverse] + #} + + #JMN3 + if {$do_reverse} { + #note we can't just look for \x1b\[7m or \x1b\[27m + # it may be a more complex sequence like \x1b\[0\;\;7\;31m etc + + set existing_reverse_state 0 + set codeinfo [punk::ansi::codetype::sgr_merge $sgrstack -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set sgrstack [list [dict get $codeinfo mergeresult] $rflip] + #set sgrstack [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] } + + # -- --- --- set nxt [llength $o] if {!$insert_mode} { diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm index 85cb9f27..7a2f9443 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm @@ -553,28 +553,51 @@ tcl::namespace::eval punk::ansi { $obj destroy return $result } - proc example {} { + proc example {args} { + set base [punk::repo::find_project] + set default_ansibase [file join $base src/testansi] + + set argd [punk::args::get_dict [tstr -return string { + *proc -name punk::ansi::example -help "Display .ans image files in a grid that will fit in console + " + -colwidth -default 82 -help "Width of each column - default of 82 will fit a standard 80wide ansi image (when framed) + You can specify a narrower width to truncate images on the right side" + -folder -default "${$default_ansibase}" -help "Base folder for files if relative paths are used. + Defaults to /src/testansi - where projectbase is determined from current directory. + " + *values -min 0 -max -1 + files -default {belinda.ans bot.ans flower.ans fish.ans} -multiple true -help "List of filenames - leave empty to display 4 defaults" + }] $args] + set colwidth [dict get $argd opts -colwidth] + set ansibase [file normalize [dict get $argd opts -folder]] + set fnames [dict get $argd values files] + + #assumes fixed column widths e.g 80col images will fit in 82-width frames (common standard for old ansi art) (of arbitrary height) #todo - review dependency on punk::repo ? package require textblock package require punk::repo package require punk::console - set fnames [list belinda.ans bot.ans flower.ans fish.ans] - set base [punk::repo::find_project] - set ansibase [file join $base src/testansi] if {![file exists $ansibase]} { - puts stderr "Missing testansi folder at $base/src/testansi" + puts stderr "Missing folder at $ansibase" puts stderr "Ensure ansi test files exist: $fnames" #error "punk::ansi::example Cannot find example files" } - set missingbase [a+ yellow][textblock::block 80 23 ?][a] + set missingbase [a+ yellow][textblock::block [expr {$colwidth-2}] 23 ?][a] ;#assuming standard frame - subtract 2 for left/right borders set pics [list] foreach f $fnames { - if {![file exists $ansibase/$f]} { - set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$ansibase/$f[a]"] + if {[file pathtype $f] ne "absolute"} { + set filepath [file normalize $ansibase/$f] + } else { + set filepath [file normalize $f] + } + if {![file exists $filepath]} { + set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$f[a]"] lappend pics [tcl::dict::create filename $f pic $p status missing] } else { - set img [join [lines_as_list -line trimline -block trimtail [ansicat $ansibase/$f]] \n] + #set img [join [lines_as_list -line trimline -block trimtail [ansicat $filepath]] \n] + #-line trimline will wreck some images + set img [join [lines_as_list -block trimtail [ansicat $filepath]] \n] lappend pics [tcl::dict::create filename $f pic $img status ok] } } @@ -582,30 +605,73 @@ tcl::namespace::eval punk::ansi { set termsize [punk::console:::get_size] set margin 4 set freewidth [expr {[tcl::dict::get $termsize columns]-$margin}] - set per_row [expr {$freewidth / 80}] - - set rowlist [list] - set row [list] - set i 1 + set per_row [expr {$freewidth / $colwidth}] + + set rowlist [list] ;# { { } { } } + set heightlist [list] ;# { { } { } } + set maxheights [list] ;# { } + set row [list] ;#wip row + set rowh [list] ;#wip row img heights + set i 1 ;#track image index of whole pics list + set rowindex 0 foreach picinfo $pics { set subtitle "" if {[tcl::dict::get $picinfo status] ne "ok"} { set subtitle [tcl::dict::get $picinfo status] } set title [tcl::dict::get $picinfo filename] - lappend row [textblock::frame -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + set fr [textblock::frame -width $colwidth -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + # -- --- --- --- + #we need the max height of a row element to use join_basic instead of join below + # -- --- --- --- + set fr_height [textblock::height $fr] + lappend row $fr + lappend rowh $fr_height + + set rowmax [lindex $maxheights $rowindex] + if {$rowmax eq ""} { + #empty result means no maxheights entry for this row yet + set rowmax $fr_height + lappend maxheights $rowmax + } else { + if {$fr_height > $rowmax} { + set rowmax $fr_height + lset maxheights end $rowmax + } + } + # -- --- --- --- + if {$i % $per_row == 0} { lappend rowlist $row + lappend heightlist $rowh + incr rowindex set row [list] + set rowh [list] } elseif {$i == [llength $pics]} { lappend rowlist $row + lappend heightlist $rowh } incr i } - + #puts "--> maxheights: $maxheights" + #puts "--> heightlist: $heightlist" set result "" - foreach r $rowlist { - append result [textblock::join_basic -- {*}$r] \n + set rowindex 0 + set blankline [string repeat " " $colwidth] + foreach imgs $rowlist heights $heightlist { + set maxheight [lindex $maxheights $rowindex] + set adjusted_row [list] + foreach i $imgs h $heights { + if {$h < $maxheight} { + #add blank lines to bottom of shorter images so join_basic can be used. + #textblock::join of ragged-height images would work and remove the need for all the height calculation + #.. but it requires much more processing + append i [string repeat \n$blankline [expr {$maxheight - $h}]] + } + lappend adjusted_row $i + } + append result [textblock::join_basic -- {*}$adjusted_row] \n + incr rowindex } @@ -3199,6 +3265,28 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu return \x1b8 } # -- --- --- --- --- + #CRM Show Control Character Mode + proc enable_crm {} { + return \x1b\[3h + } + proc disable_crm {} { + return \x1b\[3l + } + + #DECSNM + #Note this can invert the enclosed section including any already reversed by SGR 7 - depending on terminal support. + #e.g + #set test [a+ reverse]aaa[a+ noreverse]bbb + # - $test above can't just be reversed by putting another [a+ reverse] in front of it. + # - but the following will work (even if underlying terminal doesn't support ?5 sequences) + #overtype::renderspace -width 20 [enable_inverse]$test + proc enable_inverse {} { + return \x1b\[?5h + } + proc disable_inverse {} { + return \x1b\[?5l + } + #DECAWM - automatic line wrapping proc enable_line_wrap {} { @@ -3399,6 +3487,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu #the purpose of backspace (or line cr) in embedded text is unclear. Should it allow some sort of character combining/overstrike as it has sometimes done historically (nroff/less)? e.g a\b` as an alternative combiner or bolding if same char #This should presumably only be done if the over_strike (os) capability is enabled in the terminal. Either way - it presumably won't affect printing width? set line [punk::ansi::ansistrip $line] + #ANSI (e.g PM/SOS) can contain \b or \n or \t but won't contribute to length + #ansistrip must come before any other processing of these chars. + #we can't use simple \b processing if we get ansi codes and aren't actually processing them (e.g moves) set line [punk::char::strip_nonprinting_ascii $line] ;#only strip nonprinting after ansistrip - some like BEL are part of ansi @@ -3748,6 +3839,7 @@ tcl::namespace::eval punk::ansi { -filter_fg 0\ -filter_bg 0\ -filter_reset 0\ + -info 0\ ] #codes *must* already have been split so that one esc per element in codelist @@ -3760,7 +3852,8 @@ tcl::namespace::eval punk::ansi { set opts $defaultopts_sgr_merge_singles foreach {k v} $args { switch -- $k { - -filter_fg - -filter_bg - -filter_reset { + -filter_fg - -filter_bg - -filter_reset - + -info { tcl::dict::set opts $k $v } default { @@ -4139,19 +4232,24 @@ tcl::namespace::eval punk::ansi { set codemerge [tcl::string::trimright $codemerge {;}] if {$unmergeable ne ""} { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" } else { - return "\x1b\[${codemerge}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m[join $othercodes ""]" } } else { if {$unmergeable eq ""} { #there were no SGR codes - not even resets - return [join $othercodes ""] + set mergeresult [join $othercodes ""] } else { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${unmergeable}m[join $othercodes ""]" } } + if {[tcl::dict::get $opts -info]} { + return [dict create sgr $codemerge unmergeable $unmergeable othercodes $othercodes mergeresult $mergeresult codestate $codestate] + } else { + return $mergeresult + } } #has_sgr_reset - rather than support this function - create an sgr normalize function that removes dead params and brings reset to front of param list? @@ -4240,7 +4338,7 @@ tcl::namespace::eval punk::ansi::ta { #we also need to track the start of ST terminated code and not add it for replay (in the ansistring functions) #variable re_ST {(?:\x1bX|\u0098|\x1b\^|\u009E|\x1b_|\u009F)(?:[^\x1b\007\u009c]*)(?:\x1b\\|\007|\u009c)} ;#downsides: early terminating with nests, mixes 7bit 8bit start/ends (does that exist in the wild?) #keep our 8bit/7bit start-end codes separate - variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} + variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} @@ -4252,7 +4350,7 @@ tcl::namespace::eval punk::ansi::ta { # -- --- --- --- #handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regext TRIE generator that works with Tcl regexes #This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone. - variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} + variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} # -- --- --- --- @@ -5674,7 +5772,12 @@ tcl::namespace::eval punk::ansi::ansistring { ENQ [list \x05 \u2405]\ ACK [list \x06 \u2406]\ BEL [list \x07 \u2407]\ + BS [list \x08 \u2408]\ + HT [list \x09 \u2409]\ + LF [list \x0a \u240a]\ + VT [list \x0b \u240b]\ FF [list \x0c \u240c]\ + CR [list \x0d \u240d]\ SO [list \x0e \u240e]\ SF [list \x0f \u240f]\ DLE [list \x10 \u2410]\ @@ -5688,12 +5791,15 @@ tcl::namespace::eval punk::ansi::ansistring { CAN [list \x18 \u2418]\ EM [list \x19 \u2419]\ SUB [list \x1a \u241a]\ + ESC [list \x1b \u241b]\ FS [list \x1c \u241c]\ GS [list \x1d \u241d]\ RS [list \x1e \u241e]\ US [list \x1f \u241f]\ + SP [list \x20 \u2420]\ DEL [list \x7f \u2421]\ ] + #alternate symbols for space # \u2422 Blank Symbol (b with forwardslash overly) # \u2423 Open Box (square bracket facing up like a tray/box) @@ -5836,6 +5942,7 @@ tcl::namespace::eval punk::ansi::ansistring { -cr 1\ -lf 0\ -vt 0\ + -ff 1\ -ht 1\ -bs 1\ -sp 1\ @@ -5850,16 +5957,22 @@ tcl::namespace::eval punk::ansi::ansistring { set opt_cr [tcl::dict::get $opts -cr] set opt_lf [tcl::dict::get $opts -lf] set opt_vt [tcl::dict::get $opts -vt] + set opt_ff [tcl::dict::get $opts -ff] set opt_ht [tcl::dict::get $opts -ht] set opt_bs [tcl::dict::get $opts -bs] set opt_sp [tcl::dict::get $opts -sp] # -- --- --- --- --- + # -lf 2, -vt 2 and -ff 2 are useful for CRM mode (Show Control Character Mode) in the terminal - where a newline is expected to display after the character. set visuals_opt $debug_visuals + set visuals_opt [dict remove $visuals_opt CR ESC LF VT FF HT BS SP] + if {$opt_esc} { tcl::dict::set visuals_opt ESC [list \x1b \u241b] + } else { + tcl::dict::unset visuals_opt ESC } if {$opt_cr} { tcl::dict::set visuals_opt CR [list \x0d \u240d] @@ -5870,9 +5983,20 @@ tcl::namespace::eval punk::ansi::ansistring { if {$opt_lf == 2} { tcl::dict::set visuals_opt LF [list \x0a \u240a\n] } - if {$opt_vt} { + if {$opt_vt == 1} { tcl::dict::set visuals_opt VT [list \x0b \u240b] } + if {$opt_vt == 2} { + tcl::dict::set visuals_opt VT [list \x0b \u240b\n] + } + switch -exact -- $opt_ff { + 1 { + tcl::dict::set visuals_opt FF [list \x0c \u240c] + } + 2 { + tcl::dict::set visuals_opt FF [list \x0c \u240c\n] + } + } if {$opt_ht} { tcl::dict::set visuals_opt HT [list \x09 \u2409] } diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/char-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/char-0.1.0.tm index ed4b22e4..e47ba051 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/char-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/char-0.1.0.tm @@ -552,13 +552,26 @@ tcl::namespace::eval punk::char { string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] } } else { + #review - use -profile? proc encodable "s {enc [encoding system]}" { set encname [encname $enc] - string eq $s [encoding convertfrom $encname [encoding convertto $encname $s]] + if {![catch { + string eq $s [encoding convertfrom $encname [encoding convertto $encname $s]] + } result]} { + return $result + } else { + return 0 + } } proc decodable "s {enc [encoding system]}" { set encname [encname $enc] - string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] + if {![catch { + string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] + } result]} { + return $result + } else { + return 0 + } } } #-- --- --- --- --- --- --- --- diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/console-0.1.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/console-0.1.1.tm index 3c64c7e3..6368aeae 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/console-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/console-0.1.1.tm @@ -13,11 +13,51 @@ # @@ Meta End +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_punk::console 0 0.1.1] +#[copyright "2024"] +#[titledesc {punk console}] [comment {-- Name section and table of contents description --}] +#[moddesc {punk console}] [comment {-- Description at end of page heading --}] +#[require punk::console] +#[keywords module console terminal] +#[description] +#[para] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section Overview] +#[para] overview of punk::console +#[subsection Concepts] +#[para] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements -##e.g package require frobz +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by punk::console +#[list_begin itemized] + +package require Tcl 8.6- package require punk::ansi +#*** !doctools +#[item] [package {Tcl 8.6-}] +#[item] [package {punk::ansi}] + + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + #if {"windows" eq $::tcl_platform(platform)} { @@ -30,6 +70,13 @@ package require punk::ansi # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval punk::console { + #*** !doctools + #[subsection {Namespace punk::console}] + #[para] + + #*** !doctools + #[list_begin definitions] + variable tabwidth 8 ;#default only - will attempt to detect and set to that configured in terminal #Note that windows terminal cooked mode seems to use 8 for interactive use even if set differently #e.g typing tab characters may still be echoed 8-spaced while writing to stdout my obey the terminal's tab stops. @@ -1028,23 +1075,37 @@ namespace eval punk::console { return [split [get_cursor_pos $inoutchannels] ";"] } - #todo - determine cursor on/off state before the call to restore properly. May only be possible + #todo - determine cursor on/off state before the call to restore properly. proc get_size {{inoutchannels {stdin stdout}}} { lassign $inoutchannels in out #we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810 #chan eof is faster whether chan exists or not than - if {[catch {chan eof $in} is_eof]} { - error "punk::console::get_size input channel $in seems to be closed ([info level 1])" + if {[catch {chan eof $out} is_eof]} { + error "punk::console::get_size output channel $out seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on input channel $in ([info level 1])" + error "punk::console::get_size eof on output channel $out ([info level 1])" } } - if {[catch {chan eof $out} is_eof]} { - error "punk::console::get_size output channel $out seems to be closed ([info level 1])" + #we don't need to care about the input channel if chan configure on the output can give us the info. + #short circuit ansi cursor movement method if chan configure supports the -winsize value + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + #this mechanism is much faster than ansi cursor movements + #REVIEW check if any x-platform anomalies with this method? + #can -winsize key exist but contain erroneous info? We will check that we get 2 ints at least + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + #continue on to ansi mechanism if we didn't get 2 ints + } + + if {[catch {chan eof $in} is_eof]} { + error "punk::console::get_size input channel $in seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on output channel $out ([info level 1])" + error "punk::console::get_size eof on input channel $in ([info level 1])" } } @@ -1067,18 +1128,28 @@ namespace eval punk::console { } } - #faster - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore - proc get_size_cursorrestore {} { + #faster than get_size when it is using ansi mechanism - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore + proc get_size_cursorrestore {{inoutchannels {stdin stdout}}} { + lassign $inoutchannels in out + #we use the same shortcircuit mechanism as get_size to avoid ansi at all if the output channel will give us the info directly + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + } + if {[catch { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. - puts -nonewline [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] - lassign [get_cursor_pos_list] lines cols - puts -nonewline [punk::ansi::cursor_restore][punk::console::cursor_on];flush stdout + puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] + lassign [get_cursor_pos_list $inoutchannels] lines cols + puts -nonewline $out [punk::ansi::cursor_restore][punk::console::cursor_on];flush $out set result [list columns $cols rows $lines] } errM]} { - puts -nonewline [punk::ansi::cursor_restore_dec] - puts -nonewline [punk::ansi::cursor_on] + puts -nonewline $out [punk::ansi::cursor_restore_dec] + puts -nonewline $out [punk::ansi::cursor_on] error "$errM" } else { return $result @@ -1803,6 +1874,9 @@ namespace eval punk::console { } #run the test and allow warnings to be emitted to stderr on package load. User should know the terminal and/or Tcl version are not optimal for unicode character work #set testresult [test1] + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::console ---}] } @@ -1825,4 +1899,7 @@ package provide punk::console [namespace eval punk::console { variable version set version 0.1.1 }] -return \ No newline at end of file +return + +#*** !doctools +#[manpage_end] diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/du-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/du-0.1.0.tm index f0e96a28..1eca1f47 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/du-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/du-0.1.0.tm @@ -967,7 +967,7 @@ namespace eval punk::du { dict set effective_opts -with_times $timed_types dict set effective_opts -with_sizes $sized_types - return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors] + return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden $flaggedhidden flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors] } #zipfs attributes/behaviour fairly different to tclvfs - keep separate diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm index cb786f22..63f32dee 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm @@ -328,7 +328,17 @@ tcl::namespace::eval punk::lib::compat { # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval punk::lib { tcl::namespace::export * - #variable xyz + variable has_struct_list + set has_struct_list [expr {![catch {package require struct::list}]}] + variable has_struct_set + set has_struct_set [expr {![catch {package require struct::set}]}] + variable has_punk_ansi + set has_punk_ansi [expr {![catch {package require punk::ansi}]}] + set has_twapi 0 + if {"windows" eq $::tcl_platform(platform)} { + set has_twapi [expr {![catch {package require twapi}]}] + } + #*** !doctools #[subsection {Namespace punk::lib}] @@ -614,7 +624,9 @@ namespace eval punk::lib { } proc pdict {args} { - if {[catch {package require punk::ansi} errM]} { + package require punk::args + variable has_punk_ansi + if {!$has_punk_ansi} { set sep " = " } else { #set sep " [a+ Web-seagreen]=[a] " @@ -691,14 +703,15 @@ namespace eval punk::lib { # - Copy proc and attempt rework so we can get back to this as a baseline for functionality proc showdict {args} { ;# analogous to parray (except that it takes the dict as a value) #set sep " [a+ Web-seagreen]=[a] " - if {[catch {package require punk::ansi} errM]} { - set sep " = " + variable has_punk_ansi + if {!$has_punk_ansi} { set RST "" + set sep " = " set sep_mismatch " mismatch " } else { - set sep " [punk::ansi::a+ Green]=[punk::ansi::a] " ;#stick to basic default colours for wider terminal support set RST [punk::ansi::a] - set sep_mismatch " [punk::ansi::a+ Brightred undercurly underline undt-white]mismatch[punk::ansi::a] " + set sep " [punk::ansi::a+ Green]=$RST " ;#stick to basic default colours for wider terminal support + set sep_mismatch " [punk::ansi::a+ Brightred undercurly underline undt-white]mismatch$RST " } package require punk ;#we need pipeline pattern matching features package require textblock @@ -836,7 +849,7 @@ namespace eval punk::lib { lappend keyset_structure dict } @* { - puts ---->HERE<---- + #puts "showdict ---->@*<----" dict set pattern_this_structure $p list set keys [punk::lib::range 0 [llength $dval]-1] lappend keyset {*}$keys @@ -1405,16 +1418,29 @@ namespace eval punk::lib { } proc is_list_all_in_list {small large} { - package require struct::list - package require struct::set set small_in_large [lsort [struct::set intersect [lsort -unique $small] $large ]] return [struct::list equal [lsort $small] $small_in_large] } + if {!$has_struct_list || !$has_struct_set} { + set body { + package require struct::list + package require struct::set + } + append body [info body is_list_all_in_list] + proc is_list_all_in_list {small large} $body + } + proc is_list_all_ni_list {a b} { - package require struct::set set i [struct::set intersect $a $b] return [expr {[llength $i] == 0}] } + if {!$has_struct_set} { + set body { + package require struct::list + } + append body [info body is_list_all_ni_list] + proc is_list_all_ni_list {a b} $body + } #somewhat like struct::set difference - but order preserving, and doesn't treat as a 'set' so preserves dupes in fromlist #struct::set difference may happen to preserve ordering when items are integers, but order can't be relied on, @@ -1465,18 +1491,22 @@ namespace eval punk::lib { return [array names tmp] } - package require struct::set - if {[struct::set equal [struct::set union {a a} {}] {a}]} { - proc lunique_unordered {list} { - struct::set union $list {} - } - } else { - puts stderr "WARNING: struct::set union no longer dedupes!" - #we could also test a sequence of: struct::set add - proc lunique_unordered {list} { - tailcall lunique $list + #default/fallback implementation + proc lunique_unordered {list} { + lunique $list + } + if {$has_struct_set} { + if {[struct::set equal [struct::set union {a a} {}] {a}]} { + proc lunique_unordered {list} { + struct::set union $list {} + } + } else { + puts stderr "WARNING: struct::set union no longer dedupes!" + #we could also test a sequence of: struct::set add } } + + #order-preserving proc lunique {list} { set new {} @@ -1863,14 +1893,14 @@ namespace eval punk::lib { set opt_empty [tcl::dict::get $opts -empty_as_hex] # -- --- --- --- - set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map [list _ ""] [string trim $h]}] + set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map {_ ""} [string trim $h]}] if {$opt_validate} { #Note appended F so that we accept list of empty strings as per the documentation if {![string is xdigit -strict [join $list_largeHex ""]F ]} { error "[namespace current]::hex2dec error: non-hex digits encountered after stripping underscores and leading/trailing whitespace for each element\n $list_largeHex" } } - if {![string is xdigit -strict [string map [list _ ""] $opt_empty]]} { + if {![string is xdigit -strict [string map {_ ""} $opt_empty]]} { #mapping empty string to a value destroys any advantage of -scanonly #todo - document that -scanonly has 2 restrictions - each element must be valid hex and less than 7 chars long #set list_largeHex [lmap v $list_largeHex[set list_largeHex {}] {expr {$v eq ""} ? {0} : {[set v]}}] @@ -1878,7 +1908,7 @@ namespace eval punk::lib { error "[namespace current]::hex2dec error: empty values in list cannot be mapped to non-hex $opt_empty" } } else { - set opt_empty [string trim [string map [list _ ""] $opt_empty]] + set opt_empty [string trim [string map {_ ""} $opt_empty]] if {[set first_empty [lsearch $list_largeHex ""]] >= 0} { #set list_largeHex [lmap v $list_largeHex[set list_largeHex {}] {expr {$v eq ""} ? {$opt_empty} : {$v}}] set nonempty_head [lrange $list_largeHex 0 $first_empty-1] @@ -1931,13 +1961,13 @@ namespace eval punk::lib { } set fmt "%${opt_width}.${opt_width}ll${spec}" - set list_decimals [lmap d $list_decimals[unset list_decimals] {string map [list _ ""] [string trim $d]}] - if {![string is digit -strict [string map [list _ ""] $opt_empty]]} { + set list_decimals [lmap d $list_decimals[unset list_decimals] {string map {_ ""} [string trim $d]}] + if {![string is digit -strict [string map {_ ""} $opt_empty]]} { if {[lsearch $list_decimals ""] >=0} { error "[namespace current]::dec2hex error: empty values in list cannot be mapped to non-decimal $opt_empty" } } else { - set opt_empty [string map [list _ ""] $opt_empty] + set opt_empty [string map {_ ""} $opt_empty] if {[set first_empty [lsearch $list_decimals ""]] >= 0} { set nonempty_head [lrange $list_decimals 0 $first_empty-1] set list_decimals [concat $nonempty_head [lmap v [lrange $list_decimals $first_empty end] {expr {$v eq ""} ? {$opt_empty} : {$v}}]] @@ -2402,13 +2432,14 @@ namespace eval punk::lib { # important for pipeline & match_assign # -line trimline|trimleft|trimright -block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty -commandprefix {string length} ? # -block trimming only trims completely empty lines. use -line trimming to remove whitespace e.g -line trimright will clear empty lines without affecting leading whitespace on other lines that aren't pure whitespace - proc linelist {args} { + + set linelist_body { set usage "linelist ?-line trimline|trimleft|trimright? ?-block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty? -commandprefix text" if {[llength $args] == 0} { error "linelist missing textchunk argument usage:$usage" } set text [lindex $args end] - set text [string map [list \r\n \n] $text] ;#review - option? + set text [string map {\r\n \n} $text] ;#review - option? set arglist [lrange $args 0 end-1] set opts [tcl::dict::create\ @@ -2441,10 +2472,10 @@ namespace eval punk::lib { } } #normalize certain combos - if {[set posn [lsearch $opt_block trimhead1]] >=0 && "trimhead" in $opt_block} { + if {"trimhead" in $opt_block && [set posn [lsearch $opt_block trimhead1]] >=0} { set opt_block [lreplace $opt_block $posn $posn] } - if {[set posn [lsearch $opt_block trimtail1]] >=0 && "trimtail" in $opt_block} { + if {"trimtail" in $opt_block && [set posn [lsearch $opt_block trimtail1]] >=0} { set opt_block [lreplace $opt_block $posn $posn] } if {"trimall" in $opt_block} { @@ -2594,9 +2625,10 @@ namespace eval punk::lib { #Each resulting line should have a reset of some type at start and a pure-reset at end to stop #see if we can find an ST sequence that most terminals will not display for marking sections? if {$opt_ansireplays} { - package require punk::ansi + #package require punk::ansi + if {$opt_ansiresets} { - set RST [punk::ansi::a] + set RST "\x1b\[0m" } else { set RST "" } @@ -2721,6 +2753,15 @@ namespace eval punk::lib { return $linelist } + if {$has_punk_ansi} { + #optimise linelist as much as possible + set linelist_body [string map { ""} $linelist_body] + } else { + #punk ansi not avail at time of package load. + #by putting in calls to punk::ansi the user will get appropriate error messages + set linelist_body [string map { "package require punk::ansi"} $linelist_body] + } + proc linelist {args} $linelist_body interp alias {} errortime {} punk::lib::errortime @@ -2846,6 +2887,133 @@ namespace eval punk::lib { proc temperature_c_to_f {deg_celsius} { return [expr {($deg_celsius * (9/5.0)) + 32}] } + + proc interp_sync_package_paths {interp} { + if {![interp exists $interp]} { + error "interp_sync_package_paths error. interp '$interp' not found. Create it first with \[interp create $interp\]" + } + interp eval $interp [list set ::auto_path $::auto_path] + interp eval $interp {tcl::tm::remove {*}[tcl::tm::list]} + interp eval $interp [list tcl::tm::add {*}[lreverse [tcl::tm::list]]] + } + + proc objclone {obj} { + append obj2 $obj {} + } + + + + proc format_number {numbers_or_commaformattednumbers {delim ""} {groupsize ""}} { + variable has_twapi + if {$has_twapi} { + if {$delim eq "" && $groupsize eq ""} { + set localeid [twapi::get_system_default_lcid] + } + } + + set results [list] + set nums [objclone $numbers_or_commaformattednumbers] ;#stops single num from getting internal rep of list + foreach inputnum $nums { + set number [objclone $inputnum] + #also handle tcl 8.7+ underscores in numbers + set number [string map [list _ "" , ""] $number] + #normalize e.g 2e4 -> 20000.0 + set number [expr {$number}] + + if {$has_twapi} { + if {$delim eq "" && $groupsize eq ""} { + lappend results [twapi::format_number $number $localeid -idigits -1] + continue + } else { + if {$delim eq ""} {set delim ","} + if {$groupsize eq ""} {set groupsize 3} + lappend results [twapi::format_number $number 0 -idigits -1 -sthousand $delim -sgrouping $groupsize] + continue + } + } + #todo - get configured user defaults + set delim "," + set groupsize 3 + + lappend results [delimit_number $number $delim $groupsize] + } + + if {[llength $results] == 1} { + #keep intrep as string rather than list + return [lindex $results 0] + } + return $results + } + + + #from wiki https://wiki.tcl-lang.org/page/Delimiting+Numberse + # Given a number represented as a string, insert delimiters to break it up for + # readability. Normally, the delimiter will be a comma which will be inserted every + # three digits. However, the delimiter and groupsize are optional arguments, + # permitting use in other locales. + # + # The string is assumed to consist of digits, possibly preceded by spaces, + # and possibly containing a decimal point, i.e.: [:space:]*[:digit:]*\.[:digit:]* + + proc delimit_number {unformattednumber {delim ","} {GroupSize 3}} { + set number [punk::objclone $unformattednumber] + set number [string map {_ ""} $number] + #normalize using expr - e.g 2e4 -> 20000.0 + set number [expr {$number}] + # First, extract right hand part of number, up to and including decimal point + set point [string last "." $number]; + if {$point >= 0} { + set PostDecimal [string range $number [expr $point + 1] end]; + set PostDecimalP 1; + } else { + set point [expr [string length $number] + 1] + set PostDecimal ""; + set PostDecimalP 0; + } + + # Now extract any leading spaces. review - regex for whitespace instead of just ascii space? + set ind 0; + while {[string equal [string index $number $ind] \u0020]} { + incr ind; + } + set FirstNonSpace $ind; + set LastSpace [expr $FirstNonSpace - 1]; + set LeadingSpaces [string range $number 0 $LastSpace]; + + # Now extract the non-fractional part of the number, omitting leading spaces. + set MainNumber [string range $number $FirstNonSpace [expr $point -1]]; + + # Insert commas into the non-fractional part. + set Length [string length $MainNumber]; + set Phase [expr $Length % $GroupSize] + set PhaseMinusOne [expr $Phase -1]; + set DelimitedMain ""; + + #First we deal with the extra stuff. + if {$Phase > 0} { + append DelimitedMain [string range $MainNumber 0 $PhaseMinusOne]; + } + set FirstInGroup $Phase; + set LastInGroup [expr $FirstInGroup + $GroupSize -1]; + while {$LastInGroup < $Length} { + if {$FirstInGroup > 0} { + append DelimitedMain $delim; + } + append DelimitedMain [string range $MainNumber $FirstInGroup $LastInGroup]; + incr FirstInGroup $GroupSize + incr LastInGroup $GroupSize + } + + # Reassemble the number. + if {$PostDecimalP} { + return [format "%s%s.%s" $LeadingSpaces $DelimitedMain $PostDecimal]; + } else { + return [format "%s%s" $LeadingSpaces $DelimitedMain]; + } + } + + + #*** !doctools #[list_end] [comment {--- end definitions namespace punk::lib ---}] } @@ -2998,7 +3166,9 @@ tcl::namespace::eval punk::lib::system { return [concat $smallfactors [lreverse $largefactors] $x] } - # incomplte - report which is the innermost bracket/quote etc awaiting completion for a Tcl command + + + # incomplete - report which is the innermost bracket/quote etc awaiting completion for a Tcl command #important - used by punk::repl proc incomplete {partial} { #we can apparently get away without concatenating current innerpartial to previous in list - REVIEW. diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm index 1e90b5ca..932c1db6 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm @@ -35,12 +35,14 @@ namespace eval punk::mix::base { } #puts stderr "punk::mix::base extension: [string trimleft $extension :]" if {![string length $extension]} { - #if still no extension - must have been called dirctly as punk::mix::base::_cli + #if still no extension - must have been called directly as punk::mix::base::_cli if {![llength $args]} { set args "help" } set extension [namespace current] } + #init usually used to load commandsets (and export their names) into the extension namespace/ensemble + ${extension}::_init if {![llength $args]} { if {[info exists ${extension}::default_command]} { tailcall $extension [set ${extension}::default_command] diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm index 5b1ec6da..cd6f3025 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm @@ -31,47 +31,58 @@ namespace eval punk::mix::cli { namespace eval temp_import { } namespace ensemble create + variable initialised 0 - package require punk::overlay - catch { - punk::overlay::import_commandset module . ::punk::mix::commandset::module - } - punk::overlay::import_commandset debug . ::punk::mix::commandset::debug - punk::overlay::import_commandset repo . ::punk::mix::commandset::repo - punk::overlay::import_commandset lib . ::punk::mix::commandset::loadedlib - - catch { - package require punk::mix::commandset::project - punk::overlay::import_commandset project . ::punk::mix::commandset::project - punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection - } - if {[catch { - package require punk::mix::commandset::layout - punk::overlay::import_commandset project.layout . ::punk::mix::commandset::layout - punk::overlay::import_commandset project.layouts . ::punk::mix::commandset::layout::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::layout" - puts stderr $errM - } - if {[catch { - package require punk::mix::commandset::buildsuite - punk::overlay::import_commandset buildsuite . ::punk::mix::commandset::buildsuite - punk::overlay::import_commandset buildsuites . ::punk::mix::commandset::buildsuite::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::buildsuite" - puts stderr $errM - } - punk::overlay::import_commandset scriptwrap . ::punk::mix::commandset::scriptwrap - if {[catch { - package require punk::mix::commandset::doc - punk::overlay::import_commandset doc . ::punk::mix::commandset::doc - punk::overlay::import_commandset "" "" ::punk::mix::commandset::doc::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::doc" - puts stderr $errM + #lazy _init - called by punk::mix::base::_cli when ensemble used + proc _init {args} { + variable initialised + if {$initialised} { + return + } + puts stderr "punk::mix::cli::init $args" + package require punk::overlay + namespace eval ::punk::mix::cli { + catch { + punk::overlay::import_commandset module . ::punk::mix::commandset::module + } + punk::overlay::import_commandset debug . ::punk::mix::commandset::debug + punk::overlay::import_commandset repo . ::punk::mix::commandset::repo + punk::overlay::import_commandset lib . ::punk::mix::commandset::loadedlib + + catch { + package require punk::mix::commandset::project + punk::overlay::import_commandset project . ::punk::mix::commandset::project + punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection + } + if {[catch { + package require punk::mix::commandset::layout + punk::overlay::import_commandset project.layout . ::punk::mix::commandset::layout + punk::overlay::import_commandset project.layouts . ::punk::mix::commandset::layout::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::layout" + puts stderr $errM + } + if {[catch { + package require punk::mix::commandset::buildsuite + punk::overlay::import_commandset buildsuite . ::punk::mix::commandset::buildsuite + punk::overlay::import_commandset buildsuites . ::punk::mix::commandset::buildsuite::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::buildsuite" + puts stderr $errM + } + punk::overlay::import_commandset scriptwrap . ::punk::mix::commandset::scriptwrap + if {[catch { + package require punk::mix::commandset::doc + punk::overlay::import_commandset doc . ::punk::mix::commandset::doc + punk::overlay::import_commandset "" "" ::punk::mix::commandset::doc::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::doc" + puts stderr $errM + } + } + set initialised 1 } - proc help {args} { #set basehelp [punk::mix::base::help -extension [namespace current] {*}$args] set basehelp [punk::mix::base help {*}$args] @@ -210,11 +221,12 @@ namespace eval punk::mix::cli { proc validate_modulename {modulename args} { set opts [list\ -errorprefix validate_modulename\ + -strict 0\ ] if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} foreach {k v} $args { switch -- $k { - -errorprefix { + -errorprefix - -strict { dict set opts $k $v } default { @@ -223,8 +235,14 @@ namespace eval punk::mix::cli { } } # -- --- --- --- --- --- --- --- --- --- --- --- --- --- - set opt_errorprefix [dict get $opts -errorprefix] + set opt_errorprefix [dict get $opts -errorprefix] + set opt_strict [dict get $opts -strict] # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + if {$opt_strict} { + if {[regexp {[A-Z]} $modulename]} { + error "$opt_errorprefix '$modulename' contains uppercase which is not recommended as per tip 590, and option -strict is set to 1" + } + } validate_name_not_empty_or_spaced $modulename -errorprefix $opt_errorprefix set testname [string map {:: {}} $modulename] @@ -239,6 +257,56 @@ namespace eval punk::mix::cli { } return $modulename } + proc confirm_modulename {modulename} { + set finalised 0 + set aborted 0 + while {!$finalised && !$aborted} { + #first validate with -strict 0 to confirm acceptable while ignoring case issues. + #uppercase is generally valid but not recommended - so has separate prompting. + if {[catch {validate_modulename $modulename -strict 0} errM]} { + set msg "Chosen name didn't pass validation\n" + append msg "reason: $errM\n" + append msg "Please retype the modulename. You will be given a further prompt to confirm or abort." + set modulename [util::askuser $msg] + } elseif {[regexp {[A-Z]} $modulename]} { + set msg "module names containing uppercase are not recommended (see tip 590).\n" + append msg "Please retype the module name '$modulename' to proceed.\n" + append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" + append msg "Retype it all in lowercase to use recommended naming" + set answer [util::askuser $msg] + if {[regexp {[A-Z]} $answer]} { + if {$answer eq $modulename} { + #ok - user insists + set finalised 1 + } else { + #user supplied a different uppercase name - don't set finalised so we bug them again to type it two times the same way to proceed + puts stdout "A different uppercase name was supplied - reconfirmation required." + } + set modulename $answer + } else { + #user has resupplied modulename all as lowercase + if {$answer eq [string tolower $modulename]} { + set finalised 1 + } else { + #.. but it doesn't match original - require rerun + } + set modulename $answer + } + } else { + set answer [util::askuser "Proceed with the module name '$modulename'? Y to continue N to abort"] + if {[string tolower $answer] eq "y"} { + set finalised 1 + } else { + set aborted 1 + } + } + } + if {$aborted} { + return [dict create status error reason errmsg] + } else { + return [dict create status ok modulename $modulename] + } + } proc validate_projectname {projectname args} { set defaults [list\ diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm index fafc3cec..856c9340 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm @@ -165,7 +165,17 @@ namespace eval punk::mix::commandset::doc { cd $original_wd } - proc validate {} { + proc validate {args} { + set argd [punk::args::get_dict { + -- -type none -optional 1 -help "end of options marker --" + -individual -type boolean -default 1 + *values -min 0 -max -1 + patterns -default {*} -type any -multiple 1 + } $args] + set opt_individual [tcl::dict::get $argd opts -individual] + set patterns [tcl::dict::get $argd values patterns] + + #todo - run and validate punk::docgen output set projectdir [punk::repo::find_project] if {$projectdir eq ""} { @@ -180,7 +190,23 @@ namespace eval punk::mix::commandset::doc { set docroot $projectdir/src/doc cd $docroot - dtplite validate $docroot + if {!$opt_individual && "*" in $patterns} { + if {[catch { + dtplite validate $docroot + } errM]} { + puts stderr "commandset::doc::validate failed for projectdir '$projectdir'" + puts stderr "docroot '$docroot'" + puts stderr "dtplite error was: $errM" + } + } else { + foreach p $patterns { + set treefiles [punk::path::treefilenames $p] + foreach path $treefiles { + puts stdout "dtplite validate $path" + dtplite validate $path + } + } + } #punk::mix::cli::lib::kettle_call lib validate-doc diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm index bd0b5358..08d103ee 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm @@ -179,7 +179,16 @@ namespace eval punk::mix::commandset::loadedlib { return [join $loaded_libs \n] } - proc info {libname} { + proc info {args} { + set argspecs { + *values -min 1 + libname -help "library/package name" + } + set argd [punk::args::get_dict $argspecs $args] + set libname [dict get $argd values libname] + + + if {[catch {package require natsort}]} { set has_natsort 0 } else { diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm index 9955c53b..029be3ce 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm @@ -204,6 +204,30 @@ namespace eval punk::mix::commandset::module { set modulename $module } punk::mix::cli::lib::validate_modulename $modulename -errorprefix "punk::mix::commandset::module::new" + + if {[regexp {[A-Z]} $module]} { + set msg "module names containing uppercase are not recommended (see tip 590).\n" + append msg "Please retype the module name '$module' to proceed.\n" + append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" + append msg "Retype it all in lowercase to use recommended naming" + set answer [util::askuser $msg] + if {[regexp {[A-Z]} $answer]} { + if {$answer eq $module} { + #ok - user insists + } else { + + } + } else { + #user has resupplied modulename all as lowercase + if {$answer eq [string tolower $module]} { + set module $answer + } else { + #.. but it doesn't match original - require rerun + } + } + } + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #options # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm index aa630d36..9afc685c 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm @@ -165,7 +165,7 @@ namespace eval punk::mix::commandset::project { #user can use dev module.new manually or supply module name in -modules set opt_modules [list] } else { - set opt_modules [list $projectname] + set opt_modules [list [string tolower $projectname]] ;#default modules to lowercase as is the modern (tip 590) recommendation for Tcl } } # -- --- --- --- --- --- --- --- --- --- --- --- --- @@ -919,10 +919,18 @@ namespace eval punk::mix::commandset::project { if {[llength $col_states]} { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes s $col_states { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode] [overtype::left $col6 $s]" \n } } else { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode]" \n } } diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/overlay-0.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/overlay-0.1.tm index 5534dad3..73b8ef39 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/overlay-0.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/overlay-0.1.tm @@ -130,6 +130,7 @@ tcl::namespace::eval ::punk::overlay { }] set imported_commands [list] + set imported_tails [list] set nscaller [uplevel 1 [list tcl::namespace::current]] if {[catch { #review - noclobber? @@ -143,7 +144,10 @@ tcl::namespace::eval ::punk::overlay { } rename $cmd $import_as lappend imported_commands $import_as + lappend imported_tails [namespace tail $import_as] } + #make imported commands exported so they are available to the ensemble + tcl::namespace::eval ${nscaller} [list namespace export {*}$imported_tails] } errM]} { puts stderr "Error loading commandset $prefix $separator $cmdnamespace" puts stderr "err: $errM" diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm index 933ef860..2165c0fd 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm @@ -63,11 +63,11 @@ package require Tcl 8.6- # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # oo::class namespace # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ -namespace eval punk::path::class { +#namespace eval punk::path::class { #*** !doctools #[subsection {Namespace punk::path::class}] #[para] class definitions - if {[info commands [namespace current]::interface_sample1] eq ""} { + #if {[info commands [namespace current]::interface_sample1] eq ""} { #*** !doctools #[list_begin enumerated] @@ -89,8 +89,8 @@ namespace eval punk::path::class { #*** !doctools #[list_end] [comment {--- end class enumeration ---}] - } -} + #} +#} # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ @@ -105,6 +105,448 @@ namespace eval punk::path { #[para] Core API functions for punk::path #[list_begin definitions] + # -- --- + #punk::path::normjoin + # - simplify . and .. segments as far as possible whilst respecting specific types of root. + # -- --- + #a form of file normalize that supports //xxx to be treated as server path names + #(ie regardless of unices ignoring (generally) leading double slashes, and regardless of windows volumerelative path syntax) + #(sometimes //server.com used as a short form for urls - which doesn't seem too incompatible with this anyway) + # -- --- + #This is intended to be purely a string analysis - without reference to filesystem volumes or vfs or zipfs mountpoints etc + # + #TODO - option for caller to provide a -base below which we can't backtrack. + #This is preferable to setting policy here for example regarding forcing no trackback below //servername/share + #Our default is to allow trackback to: + # :// + # :/ + # //./ (dos device volume) + # //server (while normalizing //./UNC/server to same) + # / (ordinary unix root) + # ./../ - (track back indefinitely on relpath as we are not resolving to anything physical and can't fully simplify the leading backtracks) + # + #The caller should do the file/vfs operations to determine this - not us. + # -- --- + #simplify path with respect to /./ & /../ elements - independent of platform + #NOTE: "anomalies" in standard tcl processing on windows: + #e.g file normalize {//host} -> c:/host (or e.g d:/host if we happen to be on another volume) + #file normalize {//host/share} -> //host/share + #This is because //host is treated as volume-relative in cmd/powershell and Tcl quite reasonably follows suit. + #This prevents cwd and windows commandlines from pointing to the server (above the share) + #Explorer however does allow pointing to the //server level and seeing shares as if they are directory entries. + #we are more interested in supporting the explorer-like behaviour - as while volumerelative paths are also useful on windows - they are lesser known. + #REVIEW. + #To get back to some consistent cross platform behaviour - we will treat //something as a root/volume i.e we can't backtrack above it with ".." + #note too that file split on UNC paths doesn't give a clear indication of the root + # file split //./UNC/server/share/subpath -> //./UNC server share subpath + # file split //server/share/subpath -> //server/share subpath + #TODO - disallow all change of root or change from relative path to absolute result. + #e.g normjoin relpath/../d:/secret should not return d:/secret - but ./d:/secret + # ================ + #known issues: + #1) + # normjoin d://a//b//c -> d://a/b/c + # This is because we don't detect specific schemes. ie it's treated the same as https://a/b/c -> https://a/b/c + # Not considered a problem - just potentially surprising. + # To avoid it we would have to enumerate possible schemes. + # As it stands a unix system could define a 'scheme' that happens to match windows style driveletters. Consider a 'feature' ? review. + # won't fix? + #2) + # normjoin https:///real.com/../fake.com -> https:///fake.com + # The extra slash means effectively our servername is empty - this is potentially confusing but probably the right thing to do here. + # It's a concern only if upstream treats the tripple slash in this case as valid and maps it to https:// - which would probably be bad anyway. + # won't fix (review) + #3) + #similarly + # normjoin //./UNC//server/share/subpath -> ///server/share/subpath (when 2 or more slashes directly after UNC) + # normjoin ///server/share -> ///server/share + #This is effectively an empty servername in the input with 'server' being pushed one level down - and the output is consistent + # possibly won't fix - review + #4) inconsistency + # we return normalized //server/share for //./UNC/server share + # but other dos device paths are maintained + # e.g //./c:/etc + # This is because such paths could contain alternate segment names (windows shortnames) which we aren't in a position to resolve. + # caller should + # #as with 'case' below - caller will need to run a post 'file normalize' + #5) we don't normalize case like file normalize does on windows platform. + # This is intentional. It could only be done with reference to underlying filesystem which we don't want here. + # + # ================ + # + #relpaths all end up with leading . - while not always the simplest form, this is ok. (helps stop inadvertent conversions to absolutes) + # Tests - TODO + # normjoin /d:/..//vfs:/test -> /vfs:/test (good - not converted to //vfs:/test) + proc normjoin {args} { + set args [lmap a $args {string map "\\\\ /" $a}] + set path [plainjoin {*}$args] + switch -exact $path { + "" { + return "" + } + / - // { + #treated in unixlike manner - (but leading doubleslashes with subsequent data are server indication) + #// not considered a servername indicator - but /// (for consistency) is. (empty servername?) + return / + } + /// { + #if this is effectively //$emptyservername/ + #then for consistency we should trail //=3 + #todo - shortcircuit that here? + } + } + # /// + set doubleslash1_posn [string first // $path] + + # -- --- --- temp warning on windows only - no x-platform difference in result + #on windows //host is of type volumerelative + # whereas //host/share is of type absolute + if {"windows" eq $::tcl_platform(platform) && [file pathtype $path] eq "volumerelative"} { + #volumerelative probably only occurs on windows anyway + if {$doubleslash1_posn == 0} { + #e.g //something where no further slashes + #review - eventually get rid of this warning and require upstream to know the appropriate usecase + puts stderr "Warning - ambiguous path $path - treating as server path - not 'volumerelative'" + } else { + # /something/etc + # /mnt/c/stuff + #output will retain leading / as if on unix. + #on windows - the result would still be interpreted as volumerelative if the caller normalizes it + } + } + # -- --- --- + + set is_relpath 0 + + #set path [string map [list \\ /] $path] + set finalparts [list] + set is_nonunc_dosdevice 0 + if {[punk::winpath::is_dos_device_path $path]} { + #review + if {[string range $path 4 6] eq "UNC"} { + #convert to 'standard' //server/... path for processing + set path "/[string range $path 7 end]" ;# //server/... + } else { + #error "normjoin non-UNC dos device path '$path' not supported" + #first segment after //./ or //?/ represents the volume or drive. + #not applicable to unix - but unlikely to conflict with a genuine usecase there (review) + #we should pass through and stop navigation below //./vol + #!!! + #not anomaly in tcl (continues in tcl9) + #file exists //./c:/test -> 0 + #file exists //?/c:/test -> 1 + #file exists //./BootPartition/Windows -> 1 + #file exists //?/BootPartition/Windows -> 0 + set is_nonunc_dosdevice 1 + } + } + + if {$is_nonunc_dosdevice} { + #dosdevice prefix //./ or //?/ - preserve it (without trailing slash which will be put back in with join) + set prefix [string range $path 0 2] + set tail [string range $path 4 end] + set tailparts [split $tail /] + set parts [concat [list $prefix] $tailparts] + set rootindex 1 ;#disallow backtrack below //./ + } else { + #note use of ordinary ::split vs file split is deliberate. + if {$doubleslash1_posn == 0} { + #this is handled differently on different platforms as far as 'file split' is concerned. + #e.g for file split //sharehost/share/path/etc + #e.g on windows: -> //sharehost/share path + #e.g on freebsd: -> / sharehost share path etc + #however..also on windows: file split //sharehost -> / sharehost + #normalize by dropping leading slash before split - and then treating first 2 segments as a root + #set parts [file split [string range $path 1 end]] + set parts [split $path /] + #assert parts here has {} {} as first 2 entries + set rootindex 2 + #currently prefer can backtrack to the //zipfs:/ scheme (below the mountpoint - to browse other mounts) + #alternative handling for //zipfs:/path - don't go below mountpoint + #but we can't determine just from string if mountpoint is direct subpath or a lower one e.g //zipfs:/arbitraryname/actualmountpoint + #review - more generally //:/path ? + #todo - make an option for zipfs and others to determine the 'base' + #if {"zipfs:" eq [lindex $parts 2]} { + # set rootindex 3 + #} + } else { + #path may or may not begin with a single slash here. + #treat same on unix and windows + set rootindex 0 + #set parts [file split $path] + set parts [::split $path /] + #e.g /a/b/c -> {} a b c + #or relative path a/b/c -> a b c + #or c:/a/b/c -> c: a b c + if {[string match *: [lindex $parts 0]]} { + if {[lindex $parts 1] eq ""} { + #scheme://x splits to scheme: {} x + set parts [concat [list [lindex $parts 0]/] [lrange $parts 2 end]] + #e.g {scheme:/ x} + set rootindex 1 ;#disallow below first element of scheme + } else { + set rootindex 0 + } + } elseif {[lindex $parts 0] ne ""} { + #relpath a/b/c + set parts [linsert $parts 0 .] + set rootindex 0 + #allow backtracking arbitrarily for leading .. entries - simplify where possible + #also need to stop possible conversion to absolute path + set is_relpath 1 + } + } + } + set baseparts [lrange $parts 0 $rootindex] ;#base below which we can't retreat via ".." + #puts stderr "-->baseparts:$baseparts" + #ensure that if our rootindex already spans a dotted segment (after the first one) we remove it + #must maintain initial . for relpaths to stop them converting to absolute via backtrack + # + set finalparts [list [lindex $baseparts 0]] + foreach b [lrange $baseparts 1 end] { + if {$b ni {. ..}} { + lappend finalparts $b + } + } + set baselen [expr {$rootindex + 1}] + if {$is_relpath} { + set i [expr {$rootindex+1}] + foreach p [lrange $parts $i end] { + switch -exact -- $p { + . - "" {} + .. { + switch -exact -- [lindex $finalparts end] { + . - .. { + lappend finalparts .. + } + default { + lpop finalparts + } + } + } + default { + lappend finalparts $p + } + } + incr i + } + } else { + foreach p [lrange $parts $rootindex+1 end] { + if {[llength $finalparts] <= $baselen} { + if {$p ni {. .. ""}} { + lappend finalparts $p + } + } else { + switch -exact -- $p { + . - "" {} + .. { + lpop finalparts ;#uses punk::lib::compat::lpop if on < 8.7 + } + default { + lappend finalparts $p + } + } + } + } + } + puts "==>finalparts: '$finalparts'" + # using join - {"" "" server share} -> //server/share and {a b} -> a/b + if {[llength $finalparts] == 1 && [lindex $finalparts 0] eq ""} { + #backtracking on unix-style path can end up with empty string as only member of finalparts + #e.g /x/.. + return / + } + set result [::join $finalparts /] + #normalize volumes and mountschemes to have trailing slash if no subpath + #e.g c: -> c:/ + #//zipfs: -> //zipfs:/ + if {[set lastchar [string index $result end]] eq ":"} { + if {$result eq "//zipfs:"} { + set result "//zipfs:/" + } else { + if {[string first / $result] < 0} { + set result $result/ + } + } + } elseif {[string match //* $result]} { + if {![punk::winpath::is_dos_device_path $result]} { + #server + set tail [string range $result 2 end] + set tailparts [split $tail /] + if {[llength $tailparts] <=1} { + #empty // or //servername + append result / + } + } + } elseif {[llength $finalparts] == 2} { + if {[string range [lindex $finalparts 0] end-1 end] eq ":/"} { + #e.g https://server/ -> finalparts {https:/ server} + #e.g https:/// -> finalparts {https:/ ""} + #scheme based path should always return trailing slash after server component - even if server component empty. + lappend finalparts "" ;#force trailing / + return [join $finalparts /] + } + } + return $result + } + + proc trim_final_slash {str} { + if {[string index $str end] eq "/"} { + return [string range $str 0 end-1] + } + return $str + } + + + #x-platform - punk::path::pathtype - can be used in safe interps - different concept of pathtypes to 'file pathtype' + # - no volumerelative + # - no lookup of file volumes (volume is a windows concept - but with //zipfs:/ somewhat applicable to other platforms) + # - /* as absolute (covers also //zipfs:/ (volume), //server , //./etc , //./UNC) + # - xxx:// as absolute (scheme) + # - xxx:/ or x:/ as absolute + # - x: xxx: -> as absolute (volume-basic or volume-extended) + + #note also on windows - legacy name for COM devices + # COM1 = COM1: + # //./COM1 ?? review + + proc pathtype {str} { + set str [string map "\\\\ /" $str] + if {[string index $str 0] eq "/"} { + #todo - look for //xxx:/ prefix (generalisation of //zipfs:/) as a 'volume' specifically {volume mount} ?? - review + # look for //server prefix as {absolute server} + # look for //./UNC/server or //?/UNC/server as {absolute server UNC} ? + # look for //./ as {absolute dosdevice} + return absolute + } + + #only firstsegment with single colon at last position (after some non empty string) counts as volume or scheme - review + #e.g a:b:/.. or a::/.. or :/.. is not treated as volume/scheme whereas ab:/ is. + set firstslash [string first / $str] + if {$firstslash == -1} { + set firstsegment $str + } else { + set firstsegment [string range $str 0 $firstslash-1] + } + if {[set firstc [string first : $firstsegment]] > 0} { + set lhs_firstsegment [string range $firstsegment 0 $firstc-1] + set rhs_firstsegment [string range $firstsegment $firstc+1 end] ;#exclude a:b/ etc + if {$rhs_firstsegment eq ""} { + set rhs_entire_path [string range $str $firstc+1 end] + #assert lhs_firstsegment not empty since firstc > 0 + #count following / sequence + set i 0 + set slashes_after_firstsegment "" ;#run of slashes *directly* following first segment + while {$i < [string length $rhs_entire_path]} { + if {[string index $rhs_entire_path $i] eq "/"} { + append slashes_after_firstsegment / + } else { + break + } + incr i + } + switch -exact -- $slashes_after_firstsegment { + "" - / { + if {[string length $lhs_firstsegment] == 1} { + return {absolute volume basic} + } else { + return {absolute volume extended} + } + } + default { + #2 or more / + #this will return 'scheme' even for c:// - even though that may look like a windows volume - review + return {absolute scheme} + } + } + } + } + #assert first element of any return has been absolute or relative + return relative + } + + + proc plain {str} { + set str [string map "\\\\ /" $str] + set pathinfo [punk::path::pathtype $str] + if {[lindex $pathinfo 0] eq "relative" && ![string match ./* $str]} { + set str ./$str + } + if {[string index $str end] eq "/"} { + if {[string map {/ ""} $str] eq ""} { + #all slash segment + return $str + } else { + if {[lindex $pathinfo 1] ni {volume scheme}} { + return [string range $str 0 end-1] + } + } + } + return $str + } + #purely string based - no reference to filesystem knowledge + #unix-style forward slash only + proc plainjoin {args} { + set args [lmap a $args {string map "\\\\ /" $a}] + #if {[llength $args] == 1} { + # return [lindex $args 0] + #} + set out "" + foreach a $args { + if {![string length $out]} { + append out [plain $a] + } else { + set a [plain $a] + if {[string map {/ ""} $out] eq ""} { + set out [string range $out 0 end-1] + } + + if {[string map {/ ""} $a] eq ""} { + #all / segment + append out [string range $a 0 end-1] + } else { + if {[string length $a] > 2 && [string match "./*" $a]} { + set a [string range $a 2 end] + } + if {[string index $out end] eq "/"} { + append out $a + } else { + append out / $a + } + } + } + } + return $out + } + proc plainjoin1 {args} { + if {[llength $args] == 1} { + return [lindex $args 0] + } + set out [trim_final_slash [lindex $args 0]] + foreach a [lrange $args 1 end] { + set a [trim_final_slash $a] + append out / $a + } + return $out + } + + #intention? + #proc filepath_dotted_dirname {path} { + #} + + proc strip_prefixdepth {path prefix} { + if {$prefix eq ""} { + return [norm $path] + } + return [file join \ + {*}[lrange \ + [file split [norm $path]] \ + [llength [file split [norm $prefix]]] \ + end]] + } proc pathglob_as_re {pathglob} { #*** !doctools diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm index ee2384b4..2cb5fd1d 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm @@ -134,13 +134,30 @@ namespace eval punk::repo { } interp alias "" fossil "" punk::repo::fossil_proxy + # --- + # Calling auto_execok on an external tool can be too slow to do during package load (e.g could be 150ms) + #safe interps can't call auto_execok #At least let them load the package even though much of it may be unusable depending on the safe configuration - catch { - if {[auto_execok fossil] ne ""} { - interp alias "" FOSSIL "" {*}[auto_execok fossil] - } + #catch { + # if {[auto_execok fossil] ne ""} { + # interp alias "" FOSSIL "" {*}[auto_execok fossil] + # } + #} + # --- + # ---------- + # + + #uppercase FOSSIL to bypass fossil as alias to fossil_proxy + proc establish_FOSSIL {args} { + if {![info exists ::auto_execs(FOSSIL)]} { + set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp + } + interp alias "" FOSSIL "" ;#delete establishment alias + FOSSIL {*}$args } + interp alias "" FOSSIL "" punk::repo::establish_FOSSIL + # ---------- proc askuser {question} { if {![catch {package require punk::lib}]} { @@ -370,7 +387,16 @@ namespace eval punk::repo { } if {$repodir eq ""} { - error "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "args: $args" + dict set resultdict revision {} + dict set resultdict revision_iso8601 {} + dict set resultdict paths {} + dict set resultdict ahead "" + dict set resultdict behind "" + dict set resultdict error {reason "no_repo_found"} + dict set resultdict repotype none + return $resultdict } set subpath [punk::path::relative $repodir $abspath] if {$subpath eq "."} { @@ -644,6 +670,16 @@ namespace eval punk::repo { set path_count_fields [list unchanged changed new missing extra] set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601] set dresult [dict create] + if {[dict exists $repostate error]} { + foreach f $state_fields { + dict set dresult $f "" + } + foreach f $path_count_fields { + dict set dresult $f "" + } + #todo? + return $dresult + } foreach f $state_fields { dict set dresult $f [dict get $repostate $f] } diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm index b30133ba..6de745a8 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm @@ -30,7 +30,7 @@ namespace eval punk::winpath { #\\servername\share etc or \\?\UNC\servername\share etc. proc is_unc_path {path} { - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway) if {[string first "//" $strcopy_path] == 0} { #check for "Dos device path" syntax @@ -77,7 +77,7 @@ namespace eval punk::winpath { #dos device path syntax allows windows api to acces extended-length paths and filenames with illegal path characters such as trailing dots or whitespace #(can exist on server shares and on NTFS - but standard apps can't access without dos device syntax) proc is_dos_device_path {path} { - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway) if {[string range $strcopy_path 0 3] in {//?/ //./}} { return 1 @@ -87,7 +87,7 @@ namespace eval punk::winpath { } proc strip_dos_device_prefix {path} { #it's unlikely to be valid to strip only //?/ from a //?/UNC path so check for it here and diver to strip that. - #(review.. or raise error because a //?/UNC path isn't *strictly* a UNC path? ) + #(review.. or raise error because a //?/UNC path isn't an ordinary dos device path? ) if {[is_unc_path $path]} { return [strip_unc_path_prefix $path] } @@ -98,18 +98,18 @@ namespace eval punk::winpath { } } proc strip_unc_path_prefix {path} { - if {[is_unc_path $path]} { - #//?/UNC/server/etc - set strcopy_path [punk::objclone $path] - set trimmedpath [string range $strcopy_path 7 end] - file pathtype $trimmedpath ;#shimmer it to path rep - return $trimmedpath - } elseif {is_unc_path_plain $path} { + if {[is_unc_path_plain $path]} { #plain unc //server - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set trimmedpath [string range $strcopy_path 2 end] file pathtype $trimmedpath return $trimmedpath + } elseif {is_unc_path $path} { + #//?/UNC/server/subpath or //./UNC/server/subpath + set strcopy_path [punk::winpath::system::objclone $path] + set trimmedpath [string range $strcopy_path 7 end] + file pathtype $trimmedpath ;#shimmer it to path rep + return $trimmedpath } else { return $path } @@ -153,7 +153,7 @@ namespace eval punk::winpath { error $err } - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] #Note: path could still have leading double slash if it is a Dos device path: e.g. //?/c:/etc @@ -225,27 +225,124 @@ namespace eval punk::winpath { return 0 } - proc test_ntfs_tunneling {f1 f2 args} { - file mkdir $f1 - puts stderr "waiting 15secs..." - after 5000 {puts -nonewline stderr .} - after 5000 {puts -nonewline stderr .} - after 5000 {puts -nonewline stderr .} - after 500 {puts stderr \n} - file mkdir $f2 - puts stdout "$f1 [file stat $f1]" - puts stdout "$f2 [file stat $f2]" - file delete $f1 - puts stdout "renaming $f2 to $f1" - file rename $f2 $f1 - puts stdout "$f1 [file stat $f1]" - + proc shortname {path} { + set shortname "NA" + if {[catch { + set shortname [dict get [file attributes $path] -shortname] + } errM]} { + puts stderr "Failed to get shortname for '$path'" + } + return $shortname + } + proc test_ntfs_tunneling {prefix args} { + puts stderr "We are looking for whether any of the final $prefix files or dirs took over the ctime attribute of the original $prefix files or dirs" + puts stderr "We expect the ino values to get potentially reassigned depending on order of deletion/creation so matches are coincidental and not material" + puts stderr "The shortnames are similarly allocated as they come - so presumably match by coincidence" + puts stderr "However - if we record a file's shortname, then delete it. Recreating it by shortname within the tunneling timeframe will magically reassociate the longname" + puts stderr "use test_ntfs_tunneling2 to test shortname tunneling" + file mkdir $prefix-dir-rename + file mkdir $prefix-dir-recreate + set fd [open $prefix-file-recreate.txt w] + puts $fd "original for recreate" + close $fd + set fd [open $prefix-file-rename.txt w] + puts $fd "original for rename" + close $fd + puts stdout "ORIGINAL files/dirs" + puts stdout "$prefix-dir-rename [file stat $prefix-dir-rename] " + puts stdout "$prefix-dir-recreate [file stat $prefix-dir-recreate]" + puts stdout "$prefix-file-recreate.txt [file stat $prefix-file-recreate.txt] short:[shortname $prefix-file-recreate.txt]" + puts stdout "$prefix-file-rename.txt [file stat $prefix-file-rename.txt] short:[shortname $prefix-file-rename.txt]" + puts stderr "waiting 10secs (to have discernable ctime differences)" + after 5000 + puts -nonewline stderr . + after 5000 + puts -nonewline stderr . + after 500 + + #-- + #seems to make no diff whether created or copied - no tunneling seen with dirs + #file mkdir $prefix-dir-rename-temp + file copy $prefix-dir-rename $prefix-dir-rename-temp + #-- + puts stderr \n + puts stdout "$prefix-dir-rename-temp [file stat $prefix-dir-rename-temp] (temp to rename into place)" + puts stderr "deleting $prefix-dir-rename" + file delete $prefix-dir-rename + puts stdout "renaming $prefix-dir-rename-temp to $prefix-dir-rename" + file rename $prefix-dir-rename-temp $prefix-dir-rename + + puts stderr "deleting $prefix-dir-recreate" + file delete $prefix-dir-recreate + puts stdout "re-creating $prefix-dir-recreate" + file mkdir $prefix-dir-recreate + + puts stderr "deleting $prefix-file-recreate.txt" + file delete $prefix-file-recreate.txt + puts stderr "Recreating $prefix-file-recreate.txt" + set fd [open $prefix-file-recreate.txt w] + puts $fd "replacement" + close $fd + + puts stderr "copying $prefix-file-rename.txt to $prefix-file-rename-temp.txt" + file copy $prefix-file-rename.txt $prefix-file-rename-temp.txt + puts stdout "$prefix-file-rename-temp.txt [file stat $prefix-file-rename-temp.txt] short:[shortname $prefix-file-rename-temp.txt] (status of initial temp copy)" + puts stderr "modifying temp copy before deletion of original.. (append)" + set fd [open $prefix-file-rename-temp.txt a] + puts $fd "added to file" + close $fd + puts stdout "$prefix-file-rename-temp.txt [file stat $prefix-file-rename-temp.txt] short:[shortname $prefix-file-rename-temp.txt] (status of appended temp copy)" + puts stderr "deleting $prefix-file-rename.txt" + file delete $prefix-file-rename.txt + puts stderr "renaming temp file $prefix-file-rename-temp.txt to original $prefix-file-rename.txt" + file rename $prefix-file-rename-temp.txt $prefix-file-rename.txt + + puts stdout "Final files/dirs" + puts stdout "$prefix-dir-rename [file stat $prefix-dir-rename]" + puts stdout "$prefix-dir-recreate [file stat $prefix-dir-recreate]" + puts stdout "$prefix-file-recreate.txt [file stat $prefix-file-recreate.txt] short:[shortname $prefix-file-recreate.txt]" + puts stdout "$prefix-file-rename.txt [file stat $prefix-file-rename.txt] short:[shortname $prefix-file-rename.txt]" + } + proc test_ntfs_tunneling2 {prefix {waitms 15000}} { + #shortname -> longname tunneling + puts stderr "Tunneling only happens if we delete via shortname? review" + set f1 $prefix-longname-file1.txt + set f2 $prefix-longname-file2.txt + + set fd [open $f1 w];close $fd + set shortname1 [shortname $f1] + puts stderr "longname:$f1 has shortname:$shortname1" + set fd [open $f2 w];close $fd + set shortname2 [shortname $f2] + puts stderr "longname:$f2 has shortname:$shortname2" + + puts stderr "deleting $f1 via name $shortname1" + file delete $shortname1 + puts stdout "immediately recreating $shortname1 - should retain longname $f1 via tunneling" + set fd [open $shortname1 w];close $fd + set f1_exists [file exists $f1] + puts stdout "file exists $f1 = $f1_exists" + + puts stderr "deleting $f2 via name $shortname2" + file delete $shortname2 + puts stderr "Waiting [expr {$waitms / 1000}] seconds.. (standard tunneling timeframe is 15 seconds if registry hasn't been tweaked)" + after $waitms + puts stdout "recreating $shortname2 after wait of $waitms ms - longname lost?" + set fd [open $shortname2 w];close $fd + set f2_exists [file exists $f2] + puts stdout "file exists $f2 = $f2_exists" + + puts stdout -done- } - } - +namespace eval punk::winpath::system { + #get a copy of the item without affecting internal rep + proc objclone {obj} { + append obj2 $obj {} + } +} diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.1.tm b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.1.tm index 94af61ba..5d127a38 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.1.tm @@ -12,25 +12,97 @@ # Meta license # @@ Meta End +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_textblock 0 0.1.1] +#[copyright "2024"] +#[titledesc {punk textblock functions}] [comment {-- Name section and table of contents description --}] +#[moddesc {punk textblock}] [comment {-- Description at end of page heading --}] +#[require textblock] +#[keywords module utility lib] +#[description] +#[para] Ansi-aware terminal textblock manipulation + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[section Overview] +#[para] overview of textblock +#[subsection Concepts] +#[para] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements -##e.g package require frobz +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by textblock +#[list_begin itemized] + +#*** !doctools +#[item] [package {Tcl 8.6-}] +#[item] [package {punk::args}] +#[item] [package {punk::char}] +#[item] [package {punk::ansi}] +#[item] [package {punk::lib}] +#[item] [package {overtype}] +#[item] [package {term::ansi::code::macros}] +#[item] [package {textutil}] + +## Requirements +package require Tcl 8.6- package require punk::args package require punk::char package require punk::ansi package require punk::lib catch {package require patternpunk} package require overtype + +#safebase interps as at 2024-08 can't access deeper paths - even though they are below the supposed safe list. package require term::ansi::code::macros ;#required for frame if old ansi g0 used - review - make package optional? package require textutil + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + tcl::namespace::eval textblock { #review - what about ansi off in punk::console? tcl::namespace::import ::punk::ansi::a ::punk::ansi::a+ tcl::namespace::export block frame frame_cache framedef frametypes gcross height width widthtopline join join_basic list_as_table pad testblock - + variable use_md5 ;#framecache + set use_md5 1 + if {[catch {package require md5}]} { + set use_md5 0 + } + proc use_md5 {{yes_no ""}} { + variable use_md5 + if {$yes_no eq ""} { + return $use_md5 + } + if {![string is boolean -strict $yes_no]} { + error "textblock::use_md5 requires a boolean (or empty string to query)" + } + if {$yes_no} { + package require md5 + set use_md5 1 + } else { + set use_md5 0 + } + return $use_md5 + } tcl::namespace::eval class { variable opts_table_defaults set opts_table_defaults [tcl::dict::create\ @@ -228,6 +300,7 @@ tcl::namespace::eval textblock { } return $map } + if {[tcl::info::commands [tcl::namespace::current]::table] eq ""} { #*** !doctools #[subsection {Namespace textblock::class}] @@ -249,7 +322,7 @@ tcl::namespace::eval textblock { oo::class create [tcl::namespace::current]::table [tcl::string::map [list %topt_keys% $topt_keys %topt_switchkeys% $switch_keys_valid_topts %copt_keys% $copt_keys %copt_switchkeys% $switch_keys_valid_copts] { #*** !doctools - #[enum] CLASS [class interface_caphandler.registry] + #[enum] CLASS [class textblock::class::table] #[list_begin definitions] # [para] [emph METHODS] variable o_opts_table ;#options as configured by user (with exception of -ansireset) @@ -3986,7 +4059,7 @@ tcl::namespace::eval textblock { if append is chosen the new values will always start at the first column" -columns -default "" -type integer -help "Number of table columns Will default to 2 if not using an existing -table object" - *values + *values -min 0 -max 1 datalist -default {} -help "flat list of table cell values which will be wrapped based on -columns value" }] $args] set opts [dict get $argd opts] @@ -4337,6 +4410,14 @@ tcl::namespace::eval textblock { return [tcl::dict::create width $width height $height] ;#maintain order in 'image processing' standard width then height - caller may use lassign [tcl::dict::values [blocksize ]] width height } + proc size_as_opts {textblock} { + set sz [size $textblock] + return [dict create -width [dict get $sz width] -height [dict get $sz height]] + } + proc size_as_list {textblock} { + set sz [size $textblock] + return [list [dict get $sz width] [dict get $sz height]] + } #must be able to handle block as string with or without newlines #if no newlines - attempt to treat as a list #must handle whitespace-only string,list elements, and/or lines. @@ -5061,6 +5142,7 @@ tcl::namespace::eval textblock { [punk::lib::list_as_lines -- [lrepeat 8 " | "]] } proc table {args} { + #todo - use punk::args upvar ::textblock::class::opts_table_defaults toptdefaults set defaults [tcl::dict::create\ -rows [list]\ @@ -5112,7 +5194,7 @@ tcl::namespace::eval textblock { } variable frametypes - set frametypes [list light heavy arc double block block1 block2 ascii altg] + set frametypes [list light heavy arc double block block1 block2 block2hack ascii altg] #class::table needs to be able to determine valid frametypes proc frametypes {} { variable frametypes @@ -5121,7 +5203,7 @@ tcl::namespace::eval textblock { proc frametype {f} { #set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] switch -- $f { - light - heavy - arc - double - block - block1 - block2 - ascii - altg { + light - heavy - arc - double - block - block1 - block2 - block2hack - ascii - altg { return [tcl::dict::create category predefined type $f] } default { @@ -5142,7 +5224,7 @@ tcl::namespace::eval textblock { set is_custom_dict_ok 0 } if {!$is_custom_dict_ok} { - error "frame option -type must be one of known types: $textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" + error "frame option -type must be one of known types: $::textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" } set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] set custom_frame [tcl::dict::merge $default_custom $f] @@ -6252,9 +6334,12 @@ tcl::namespace::eval textblock { set vlr \u2595 ;# right one eighth block set vll \u258f ;# left one eighth block + #some terminals (on windows as at 2024) miscount width of these single-width blocks internally + #resulting in extra spacing that is sometimes well removed from the character itself (e.g at next ansi reset) + #This was fixed in windows-terminal based systems (2021) but persists in others. + #https://github.com/microsoft/terminal/issues/11694 set tlc \U1fb7d ;#legacy block set trc \U1fb7e ;#legacy block - set blc \U1fb7c ;#legacy block set brc \U1fb7f ;#legacy block @@ -6265,6 +6350,42 @@ tcl::namespace::eval textblock { set vlrj $vlr } + block2hack { + #the resultant table will have text appear towards top of each box + #with 'legacy' computing unicode block - hopefully these become more widely supported - as they are useful and fill in some gaps + set hlt \u2594 ;# upper one eighth block + set hlb \u2581 ;# lower one eighth block + set vlr \u2595 ;# right one eighth block + set vll \u258f ;# left one eighth block + + #see comments in block2 regarding the problems in some terminals that this *may* hack around to some extent. + #the caller probably only needs block2hack if block2 doesn't work + + #1) + #review - this hack looks sort of promising - but overtype::renderline needs fixing ? + #set tlc \U1fb7d\b ;#legacy block + #set trc \U1fb7e\b ;#legacy block + #set blc \U1fb7c\b ;#legacy block + #set brc \U1fb7f\b ;#legacy block + + #2) - works on cmd.exe and some others + # a 'privacy message' is 'probably' also not supported on the old terminal but is on newer ones + #known exception - conemu on windows - displays junk for various ansi codes - (and slow terminal anyway) + #this hack has a reasonable chance of working + #except that the punk overtype library does recognise PMs + #A single backspace however is an unlikely and generally unuseful PM - so there is a corresponding hack in the renderline system to pass this PM through! + #ugly - in that we don't know the application specifics of what the PM data contains and where it's going. + set tlc \U1fb7d\x1b^\b\x1b\\ ;#legacy block + set trc \U1fb7e\x1b^\b\x1b\\ ;#legacy block + set blc \U1fb7c\x1b^\b\x1b\\ ;#legacy block + set brc \U1fb7f\x1b^\b\x1b\\ ;#legacy block + + #horizontal and vertical bar joins + set hltj $hlt + set hlbj $hlb + set vllj $vll + set vlrj $vlr + } block { set hlt \u2580 ;#upper half set hlb \u2584 ;#lower half @@ -6286,7 +6407,7 @@ tcl::namespace::eval textblock { set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] ;#only default the general types - these form defaults for more specific types if they're missing if {[llength $f] % 2 != 0} { #todo - retrieve usage from punk::args - error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $textblock::frametypes and does not appear to be a dictionary for a custom frametype" + error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $::textblock::frametypes and does not appear to be a dictionary for a custom frametype" } #unknown order of keys specified by user - validate before creating vars as we need more general elements to be available as defaults dict for {k v} $f { @@ -6388,7 +6509,7 @@ tcl::namespace::eval textblock { #options before content argument - which is allowed to be absent - #frame performance (noticeable with complex tables even of modest size) is improved significantly by frame_cache - but is still (2024) a fairly expensive operation. + #frame performance (noticeable with complex tables even of modest size) is improved somewhat by frame_cache - but is still (2024) a fairly expensive operation. # #consider if we can use -sticky nsew instead of -blockalign (as per Tk grid -sticky option) # This would require some sort of expand equivalent e.g for -sticky ew or -sticky ns - for which we have to decide a meaning for text.. e.g ansi padding? @@ -6397,6 +6518,7 @@ tcl::namespace::eval textblock { # - but we would need to maintain support for the rendered-string based operations too. proc frame {args} { variable frametypes + variable use_md5 #counterintuitively - in-proc dict create each time is generally slightly faster than linked namespace var set opts [tcl::dict::create\ @@ -6416,7 +6538,11 @@ tcl::namespace::eval textblock { -ellipsis 1\ -usecache 1\ -buildcache 1\ + -pad 1\ + -crm_mode 0\ ] + #-pad 1 is default so that simple 'textblock::frame "[a+ Red]a \nbbb[a]" extends the bg colour on the short ragged lines (and empty lines) + # for ansi art - -pad 0 is likely to be preferable set expect_optval 0 set argposn 0 @@ -6455,7 +6581,12 @@ tcl::namespace::eval textblock { #use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache foreach {k v} $arglist { switch -- $k { - -etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache { + -etabs - -type - -boxlimits - -boxmap - -joins + - -title - -subtitle - -width - -height + - -ansiborder - -ansibase + - -blockalign - -textalign - -ellipsis + - -crm_mode + - -usecache - -buildcache - -pad { tcl::dict::set opts $k $v } default { @@ -6471,11 +6602,13 @@ tcl::namespace::eval textblock { set opt_boxmap [tcl::dict::get $opts -boxmap] set opt_usecache [tcl::dict::get $opts -usecache] set opt_buildcache [tcl::dict::get $opts -buildcache] + set opt_pad [tcl::dict::get $opts -pad] + set opt_crm_mode [tcl::dict::get $opts -crm_mode] set usecache $opt_usecache ;#may need to override set buildcache $opt_buildcache set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] - set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable + set known_frametypes $frametypes ;# light, heavey etc as defined in the ::textblock::frametypes variable set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] lassign [textblock::frametype $opt_type] _cat category _type ftype @@ -6614,6 +6747,19 @@ tcl::namespace::eval textblock { } } set contents [tcl::string::map [list \r\n \n] $contents] + if {$opt_crm_mode} { + if {$opt_height eq ""} { + set h [textblock::height $contents] + } else { + set h [expr {$opt_height -2}] + } + if {$opt_width eq ""} { + set w [textblock::width $contents] + } else { + set w [expr {$opt_width -2}] + } + set contents [overtype::renderspace -crm_mode 1 -wrap 1 -width $w -height $h "" $contents] + } set actual_contentwidth [textblock::width $contents] ;#length of longest line in contents (contents can be ragged) set actual_contentheight [textblock::height $contents] } else { @@ -6652,9 +6798,14 @@ tcl::namespace::eval textblock { #review - custom frame affects frame_inner_width - exclude from caching? #set cache_key [concat $arglist $frame_inner_width $frame_inner_height] set hashables [concat $arglist $frame_inner_width $frame_inner_height] - package require md5 - #set hash $hashables - set hash [md5::md5 -hex [encoding convertto utf-8 $hashables]] ;#need fast and unique to content - not cryptographic - review + + if {$use_md5} { + #package require md5 ;#already required at package load + set hash [md5::md5 -hex [encoding convertto utf-8 $hashables]] ;#need fast and unique to content - not cryptographic - review + } else { + set hash $hashables + } + set cache_key "$hash-$frame_inner_width-$frame_inner_height-actualcontentwidth:$actual_contentwidth" #should be in a unicode private range different to that used in table construction #e.g BMP PUA U+E000 -> U+F8FF - although this is commonly used for example by nerdfonts @@ -7057,15 +7208,22 @@ tcl::namespace::eval textblock { append contents [::join [lrepeat $diff \n] ""] } - set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) - set paddedwidth [textblock::widthtopline $paddedcontents] - - #review - horizontal truncation - if {$paddedwidth > $cache_patternwidth} { - set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + if {$opt_pad} { + set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) + set paddedwidth [textblock::widthtopline $paddedcontents] + #review - horizontal truncation + if {$paddedwidth > $cache_patternwidth} { + set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + } + #important to supply end of opts -- to textblock::join - particularly here with arbitrary data + set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays + } else { + set cwidth [textblock::width $contents] + if {$cwidth > $cache_patternwidth} { + set contents [overtype::renderspace -width $cache_patternwidth "" $contents] + } + set contentblock [textblock::join -- $contents] } - #important to supply end of opts -- to textblock::join - particularly here with arbitrary data - set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays set tlines [split $template \n] @@ -7183,7 +7341,6 @@ tcl::namespace::eval textblock { #fastest to do row first then columns - because textblock::join must do line by line if {$crosscount > 1} { - package require textblock set row [textblock::join -- {*}[lrepeat $crosscount $onecross]] set rows [lrepeat $crosscount $row] set out [::join $rows \n] @@ -7223,4 +7380,8 @@ package provide textblock [tcl::namespace::eval textblock { variable version set version 0.1.1 }] -return \ No newline at end of file +return + +#*** !doctools +#[manpage_end] + diff --git a/src/project_layouts/custom/_project/punk.project-0.1/src/make.tcl b/src/project_layouts/custom/_project/punk.project-0.1/src/make.tcl index 1cf07c5b..9edd90b0 100644 --- a/src/project_layouts/custom/_project/punk.project-0.1/src/make.tcl +++ b/src/project_layouts/custom/_project/punk.project-0.1/src/make.tcl @@ -1212,8 +1212,9 @@ foreach vfstail $vfs_tails { set rtmountpoint //zipfs:/rtmounts/$runtime_fullname set changed_unchanged [$vfs_event targetset_source_changes] + set vfs_or_runtime_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]}] - if {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]} { + if {$vfs_or_runtime_changed} { #source .vfs folder has changes $vfs_event targetset_started # -- --- --- --- --- --- @@ -1283,6 +1284,7 @@ foreach vfstail $vfs_tails { puts stderr "RUNTIME capabilities unknown. Unsure if zip supported. trying anyway.." } } + #note - as at 2024-08 - there is some discussion about the interface to mkimg - it is considered unstable (may change to -option value syntax) puts stderr "calling: tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs \"\" $buildfolder/build_$runtime_fullname" tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs "" $buildfolder/build_$runtime_fullname } result ]} { @@ -1352,9 +1354,10 @@ foreach vfstail $vfs_tails { if {![catch { exec $pscmd | grep $targetkit } still_running]} { - - puts stdout "found $targetkit instances still running\n" + set still_running_lines [split [string trim $still_running] \n] + puts stdout "found ([llength $still_running_lines]) $targetkit instances still running\n" set count_killed 0 + set num_to_kill [llength $still_running_lines] foreach ln [split $still_running \n] { puts stdout " $ln" @@ -1387,9 +1390,6 @@ foreach vfstail $vfs_tails { #review - *no running instance* works with windows taskkill - "*No such process*" works with kill -9 on FreeBSD and linux - other platforms? if {![string match "*no running instance*" $errMsg] && ![string match "*No such process*" $errMsg]} { lappend failed_kits [list kit $targetkit reason "could not kill running process for $targetkit (using '$killcmd')"] - $vfs_event targetset_end FAILED - $vfs_event destroy - $vfs_installer destroy continue } } else { @@ -1397,10 +1397,15 @@ foreach vfstail $vfs_tails { incr count_killed } } - if {$count_killed > 0} { - puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" - after 1000 + if {$count_killed < $num_to_kill} { + $vfs_event targetset_end FAILED + $vfs_event destroy + $vfs_installer destroy + continue } + + puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" + after 1000 } else { puts stderr "Ok.. no running '$targetkit' processes found" } @@ -1426,22 +1431,35 @@ foreach vfstail $vfs_tails { # -- --- --- --- --- --- $vfs_event targetset_end OK + } else { + set skipped_vfs_build 1 + puts stderr "." + puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" + $vfs_event targetset_end SKIPPED + } + $vfs_event destroy + $vfs_installer destroy - after 200 - set deployment_folder [file dirname $sourcefolder]/bin - file mkdir $deployment_folder + after 200 + set deployment_folder [file dirname $sourcefolder]/bin + file mkdir $deployment_folder - # -- ---------- - set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] - $bin_installer set_source_target $buildfolder $deployment_folder - set bin_event [$bin_installer start_event {-make-step final_kit_install}] - $bin_event targetset_init INSTALL $deployment_folder/$targetkit - #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) - #set last_completion [$bin_event targetset_last_complete] - - $bin_event targetset_addsource $buildfolder/$targetkit - $bin_event targetset_started - # -- ---------- + # -- ---------- + set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] + $bin_installer set_source_target $buildfolder $deployment_folder + set bin_event [$bin_installer start_event {-make-step final_kit_install}] + $bin_event targetset_init INSTALL $deployment_folder/$targetkit + #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) + #set last_completion [$bin_event targetset_last_complete] + + $bin_event targetset_addsource $deployment_folder/$targetkit ;#add target as a source of metadata for change detection + $bin_event targetset_addsource $buildfolder/$targetkit + $bin_event targetset_started + # -- ---------- + + set changed_unchanged [$bin_event targetset_source_changes] + set built_or_installed_kit_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$bin_event get_targets_exist]] < [llength [$bin_event get_targets]]}] + if {$built_or_installed_kit_changed} { if {[file exists $deployment_folder/$targetkit]} { puts stderr "deleting existing deployed at $deployment_folder/$targetkit" @@ -1467,19 +1485,16 @@ foreach vfstail $vfs_tails { # -- ---------- $bin_event targetset_end OK # -- ---------- - $bin_event destroy - $bin_installer destroy - } else { - set skipped_vfs_build 1 + set skipped_kit_install 1 puts stderr "." - puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" - $vfs_event targetset_end SKIPPED + puts stdout "Skipping kit install for $targetkit with vfs $vfstail runtime $rtname - no change detected" + $bin_event targetset_end SKIPPED } + $bin_event destroy + $bin_installer destroy - $vfs_event destroy - $vfs_installer destroy } ;#end foreach targetkit } ;#end foreach rtname in runtimes diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/fileutil/paths-1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/fileutil/paths-1.tm new file mode 100644 index 00000000..e387acf7 --- /dev/null +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/fileutil/paths-1.tm @@ -0,0 +1,74 @@ +# paths.tcl -- +# +# Manage lists of search paths. +# +# Copyright (c) 2009-2019 Andreas Kupries +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +# Each object instance manages a list of paths. + +# ### ### ### ######### ######### ######### +## Requisites + +package require Tcl 8.4 +package require snit + +# ### ### ### ######### ######### ######### +## API + +snit::type ::fileutil::paths { + + # ### ### ### ######### ######### ######### + ## Options :: None + + # ### ### ### ######### ######### ######### + ## Creation, destruction + + # Default constructor. + # Default destructor. + + # ### ### ### ######### ######### ######### + ## Methods :: Querying and manipulating the list of paths. + + method paths {} { + return $mypaths + } + + method add {path} { + set pos [lsearch $mypaths $path] + if {$pos >= 0 } return + lappend mypaths $path + return + } + + method remove {path} { + set pos [lsearch $mypaths $path] + if {$pos < 0} return + set mypaths [lreplace $mypaths $pos $pos] + return + } + + method clear {} { + set mypaths {} + return + } + + # ### ### ### ######### ######### ######### + ## Internal methods :: None + + # ### ### ### ######### ######### ######### + ## State :: List of paths. + + variable mypaths {} + + ## + # ### ### ### ######### ######### ######### +} + +# ### ### ### ######### ######### ######### +## Ready + +package provide fileutil::paths 1 +return diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/fileutil/traverse-0.6.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/fileutil/traverse-0.6.tm new file mode 100644 index 00000000..2f36d109 --- /dev/null +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/fileutil/traverse-0.6.tm @@ -0,0 +1,504 @@ +# traverse.tcl -- +# +# Directory traversal. +# +# Copyright (c) 2006-2015 by Andreas Kupries +# +# 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.3 + +# OO core +if {[package vsatisfies [package present Tcl] 8.5]} { + # Use new Tcl 8.5a6+ features to specify the allowed packages. + # We can use anything above 1.3. This means v2 as well. + package require snit 1.3- +} else { + # For Tcl 8.{3,4} only snit1 of a suitable patchlevel is possible. + package require snit 1.3 +} +package require control ; # Helpers for control structures +package require fileutil ; # -> fullnormalize + +snit::type ::fileutil::traverse { + + # Incremental directory traversal. + + # API + # create %AUTO% basedirectory options... -> object + # next filevar -> boolean + # foreach filevar script + # files -> list (path ...) + + # Options + # -prefilter command-prefix + # -filter command-prefix + # -errorcmd command-prefix + + # Use cases + # + # (a) Basic incremental + # - Create and configure a traversal object. + # - Execute 'next' to retrieve one path at a time, + # until the command returns False, signaling that + # the iterator has exhausted the supply of paths. + # (The path is stored in the named variable). + # + # The execution of 'next' can be done in a loop, or via event + # processing. + + # (b) Basic loop + # - Create and configure a traversal object. + # - Run a script for each path, using 'foreach'. + # This is a convenient standard wrapper around 'next'. + # + # The loop properly handles all possible Tcl result codes. + + # (c) Non-incremental, non-looping. + # - Create and configure a traversal object. + # - Retrieve a list of all paths via 'files'. + + # The -prefilter callback is executed for directories. Its result + # determines if the traverser recurses into the directory or not. + # The default is to always recurse into all directories. The call- + # back is invoked with a single argument, the path of the + # directory. + # + # The -filter callback is executed for all paths. Its result + # determines if the current path is a valid result, and returned + # by 'next'. The default is to accept all paths as valid. The + # callback is invoked with a single argument, the path to check. + + # The -errorcmd callback is executed for all paths the traverser + # has trouble with. Like being unable to cd into them, get their + # status, etc. The default is to ignore any such problems. The + # callback is invoked with a two arguments, the path for which the + # error occured, and the error message. Errors thrown by the + # filter callbacks are handled through this callback too. Errors + # thrown by the error callback itself are not caught and ignored, + # but allowed to pass to the caller, usually of 'next'. + + # Note: Low-level functionality, version and platform dependent is + # implemented in procedures, and conditioally defined for optimal + # use of features, etc. ... + + # Note: Traversal is done in depth-first pre-order. + + # Note: The options are handled only during + # construction. Afterward they are read-only and attempts to + # modify them will cause the system to throw errors. + + # ### ### ### ######### ######### ######### + ## Implementation + + option -filter -default {} -readonly 1 + option -prefilter -default {} -readonly 1 + option -errorcmd -default {} -readonly 1 + + constructor {basedir args} { + set _base $basedir + $self configurelist $args + return + } + + method files {} { + set files {} + $self foreach f {lappend files $f} + return $files + } + + method foreach {fvar body} { + upvar 1 $fvar currentfile + + # (Re-)initialize the traversal state on every call. + $self Init + + while {[$self next currentfile]} { + set code [catch {uplevel 1 $body} result] + + # decide what to do upon the return code: + # + # 0 - the body executed successfully + # 1 - the body raised an error + # 2 - the body invoked [return] + # 3 - the body invoked [break] + # 4 - the body invoked [continue] + # everything else - return and pass on the results + # + switch -exact -- $code { + 0 {} + 1 { + return -errorinfo [::control::ErrorInfoAsCaller uplevel foreach] \ + -errorcode $::errorCode -code error $result + } + 3 { + # FRINK: nocheck + return + } + 4 {} + default { + return -code $code $result + } + } + } + return + } + + method next {fvar} { + upvar 1 $fvar currentfile + + # Initialize on first call. + if {!$_init} { + $self Init + } + + # We (still) have valid paths in the result stack, return the + # next one. + + if {[llength $_results]} { + set top [lindex $_results end] + set _results [lreplace $_results end end] + set currentfile $top + return 1 + } + + # Take the next directory waiting in the processing stack and + # fill the result stack with all valid files and sub- + # directories contained in it. Extend the processing queue + # with all sub-directories not yet seen already (!circular + # symlinks) and accepted by the prefilter. We stop iterating + # when we either have no directories to process anymore, or + # the result stack contains at least one path we can return. + + while {[llength $_pending]} { + set top [lindex $_pending end] + set _pending [lreplace $_pending end end] + + # Directory accessible? Skip if not. + if {![ACCESS $top]} { + Error $top "Inacessible directory" + continue + } + + # Expand the result stack with all files in the directory, + # modulo filtering. + + foreach f [GLOBF $top] { + if {![Valid $f]} continue + lappend _results $f + } + + # Expand the result stack with all sub-directories in the + # directory, modulo filtering. Further expand the + # processing stack with the same directories, if not seen + # yet and modulo pre-filtering. + + foreach f [GLOBD $top] { + if { + [string equal [file tail $f] "."] || + [string equal [file tail $f] ".."] + } continue + + if {[Valid $f]} { + lappend _results $f + } + + Enter $top $f + if {[Cycle $f]} continue + + if {[Recurse $f]} { + lappend _pending $f + } + } + + # Stop expanding if we have paths to return. + + if {[llength $_results]} { + set top [lindex $_results end] + set _results [lreplace $_results end end] + set currentfile $top + return 1 + } + } + + # Allow re-initialization with next call. + + set _init 0 + return 0 + } + + # ### ### ### ######### ######### ######### + ## Traversal state + + # * Initialization flag. Checked in 'next', reset by next when no + # more files are available. Set in 'Init'. + # * Base directory (or file) to start the traversal from. + # * Stack of prefiltered unknown directories waiting for + # processing, i.e. expansion (TOP at end). + # * Stack of valid paths waiting to be returned as results. + # * Set of directories already visited (normalized paths), for + # detection of circular symbolic links. + + variable _init 0 ; # Initialization flag. + variable _base {} ; # Base directory. + variable _pending {} ; # Processing stack. + variable _results {} ; # Result stack. + + # sym link handling (to break cycles, while allowing the following of non-cycle links). + # Notes + # - path parent tracking is lexical. + # - path identity tracking is based on the normalized path, i.e. the path with all + # symlinks resolved. + # Maps + # - path -> parent (easier to follow the list than doing dirname's) + # - path -> normalized (cache to avoid redundant calls of fullnormalize) + # cycle <=> A parent's normalized form (NF) is identical to the current path's NF + + variable _parent -array {} + variable _norm -array {} + + # ### ### ### ######### ######### ######### + ## Internal helpers. + + proc Enter {parent path} { + #puts ___E|$path + upvar 1 _parent _parent _norm _norm + set _parent($path) $parent + set _norm($path) [fileutil::fullnormalize $path] + } + + proc Cycle {path} { + upvar 1 _parent _parent _norm _norm + set nform $_norm($path) + set paren $_parent($path) + while {$paren ne {}} { + if {$_norm($paren) eq $nform} { return yes } + set paren $_parent($paren) + } + return no + } + + method Init {} { + array unset _parent * + array unset _norm * + + # Path ok as result? + if {[Valid $_base]} { + lappend _results $_base + } + + # Expansion allowed by prefilter? + if {[file isdirectory $_base] && [Recurse $_base]} { + Enter {} $_base + lappend _pending $_base + } + + # System is set up now. + set _init 1 + return + } + + proc Valid {path} { + #puts ___V|$path + upvar 1 options options + if {![llength $options(-filter)]} {return 1} + set path [file normalize $path] + set code [catch {uplevel \#0 [linsert $options(-filter) end $path]} valid] + if {!$code} {return $valid} + Error $path $valid + return 0 + } + + proc Recurse {path} { + #puts ___X|$path + upvar 1 options options _norm _norm + if {![llength $options(-prefilter)]} {return 1} + set path [file normalize $path] + set code [catch {uplevel \#0 [linsert $options(-prefilter) end $path]} valid] + if {!$code} {return $valid} + Error $path $valid + return 0 + } + + proc Error {path msg} { + upvar 1 options options + if {![llength $options(-errorcmd)]} return + set path [file normalize $path] + uplevel \#0 [linsert $options(-errorcmd) end $path $msg] + return + } + + ## + # ### ### ### ######### ######### ######### +} + +# ### ### ### ######### ######### ######### +## + +# The next three helper commands for the traverser depend strongly on +# the version of Tcl, and partially on the platform. + +# 1. In Tcl 8.3 using -types f will return only true files, but not +# links to files. This changed in 8.4+ where links to files are +# returned as well. So for 8.3 we have to handle the links +# separately (-types l) and also filter on our own. +# Note that Windows file links are hard links which are reported by +# -types f, but not -types l, so we can optimize that for the two +# platforms. +# +# 2. In Tcl 8.3 we also have a crashing bug in glob (SIGABRT, "stat on +# a known file") when trying to perform 'glob -types {hidden f}' on +# a directory without e'x'ecute permissions. We code around by +# testing if we can cd into the directory (stat might return enough +# information too (mode), but possibly also not portable). +# +# For Tcl 8.2 and 8.4+ glob simply delivers an empty result +# (-nocomplain), without crashing. For them this command is defined +# so that the bytecode compiler removes it from the bytecode. +# +# This bug made the ACCESS helper necessary. +# We code around the problem by testing if we can cd into the +# directory (stat might return enough information too (mode), but +# possibly also not portable). + +if {[package vsatisfies [package present Tcl] 8.5]} { + # Tcl 8.5+. + # We have to check readability of "current" on our own, glob + # changed to error out instead of returning nothing. + + proc ::fileutil::traverse::ACCESS {args} {return 1} + + proc ::fileutil::traverse::GLOBF {current} { + if {![file readable $current] || + [BadLink $current]} { + return {} + } + + set res [lsort -unique [concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]]] + + # Look for broken links (They are reported as neither file nor directory). + foreach l [lsort -unique [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *]]] { + if {[file isfile $l]} continue + if {[file isdirectory $l]} continue + lappend res $l + } + return [lsort -unique $res] + } + + proc ::fileutil::traverse::GLOBD {current} { + if {![file readable $current] || + [BadLink $current]} { + return {} + } + + lsort -unique [concat \ + [glob -nocomplain -directory $current -types d -- *] \ + [glob -nocomplain -directory $current -types {hidden d} -- *]] + } + + proc ::fileutil::traverse::BadLink {current} { + if {[file type $current] ne "link"} { return no } + + set dst [file join [file dirname $current] [file readlink $current]] + + if {![file exists $dst] || + ![file readable $dst]} { + return yes + } + + return no + } + +} elseif {[package vsatisfies [package present Tcl] 8.4]} { + # Tcl 8.4+. + # (Ad 1) We have -directory, and -types, + # (Ad 2) Links are returned for -types f/d if they refer to files/dirs. + # (Ad 3) No bug to code around + + proc ::fileutil::traverse::ACCESS {args} {return 1} + + proc ::fileutil::traverse::GLOBF {current} { + set res [concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]] + + # Look for broken links (They are reported as neither file nor directory). + foreach l [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *] ] { + if {[file isfile $l]} continue + if {[file isdirectory $l]} continue + lappend res $l + } + return $res + } + + proc ::fileutil::traverse::GLOBD {current} { + concat \ + [glob -nocomplain -directory $current -types d -- *] \ + [glob -nocomplain -directory $current -types {hidden d} -- *] + } + +} else { + # 8.3. + # (Ad 1) We have -directory, and -types, + # (Ad 2) Links are NOT returned for -types f/d, collect separately. + # No symbolic file links on Windows. + # (Ad 3) Bug to code around. + + proc ::fileutil::traverse::ACCESS {current} { + if {[catch { + set h [pwd] ; cd $current ; cd $h + }]} {return 0} + return 1 + } + + if {[string equal $::tcl_platform(platform) windows]} { + proc ::fileutil::traverse::GLOBF {current} { + concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]] + } + } else { + proc ::fileutil::traverse::GLOBF {current} { + set l [concat \ + [glob -nocomplain -directory $current -types f -- *] \ + [glob -nocomplain -directory $current -types {hidden f} -- *]] + + foreach x [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *]] { + if {[file isdirectory $x]} continue + # We have now accepted files, links to files, and broken links. + lappend l $x + } + + return $l + } + } + + proc ::fileutil::traverse::GLOBD {current} { + set l [concat \ + [glob -nocomplain -directory $current -types d -- *] \ + [glob -nocomplain -directory $current -types {hidden d} -- *]] + + foreach x [concat \ + [glob -nocomplain -directory $current -types l -- *] \ + [glob -nocomplain -directory $current -types {hidden l} -- *]] { + if {![file isdirectory $x]} continue + lappend l $x + } + + return $l + } +} + +# ### ### ### ######### ######### ######### +## Ready + +package provide fileutil::traverse 0.6 diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm index 1d91b53f..7f7c33cd 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/natsort-0.1.1.6.tm @@ -5,8 +5,9 @@ package require flagfilter namespace import ::flagfilter::check_flags namespace eval natsort { + #REVIEW - determine and document the purpose of scriptdir being added to tm path proc scriptdir {} { - set possibly_linked_script [file dirname [file normalize [file join [info script] ...]]] + set possibly_linked_script [file dirname [file normalize [file join [info script] __dummy__]]] if {[file isdirectory $possibly_linked_script]} { return $possibly_linked_script } else { @@ -14,7 +15,11 @@ namespace eval natsort { } } if {![interp issafe]} { - tcl::tm::add [scriptdir] + set sdir [scriptdir] + #puts stderr "natsort tcl::tm::add $sdir" + if {$sdir ni [tcl::tm::list]} { + catch {tcl::tm::add $sdir} + } } } @@ -36,6 +41,7 @@ namespace eval natsort { } else { puts stderr "|>natsort_call_err> unable to interpret 2nd argument to do_error: '$then' should be one of '$levels' or 'exit '" } + flush stderr if {$::tcl_interactive} { #may not always be desirable - but assumed to be more useful not to exit despite request, to aid in debugging if {[string tolower $type] eq "exit"} { @@ -43,6 +49,7 @@ namespace eval natsort { if {![string is digit -strict $code]} { puts stderr "|>natsort_call_err> unable to interpret 2nd argument to do_error: '$then' should be: 'exit '" } + flush stderr } return -code error $msg } else { @@ -1422,6 +1429,9 @@ namespace eval natsort { proc called_directly_namematch {} { global argv0 + if {[info script] eq ""} { + return 0 + } #see https://wiki.tcl-lang.org/page/main+script #trailing ... let's us resolve symlinks in last component of the path (could be something else like ___ but ... seems unlikely to collide with anything in the filesystem) if {[info exists argv0] @@ -1440,12 +1450,18 @@ namespace eval natsort { #Review issues around comparing names vs using inodes (esp with respect to samba shares) proc called_directly_inodematch {} { global argv0 + if {[info exists argv0] - && [file exists [info script]] && [file exists $argv0]} { + && [file exists [info script]] && [file exists $argv0]} { file stat $argv0 argv0Info file stat [info script] scriptInfo - expr {$argv0Info(dev) == $scriptInfo(dev) - && $argv0Info(ino) == $scriptInfo(ino)} + if {$argv0Info(ino) == 0 || $scriptInfo(ino) == 0 || $argv0Info(dev) == 0 || $scriptInfo(dev) == 0} { + #vfs? + #e.g //zipfs:/ + return 0 + } + return [expr {$argv0Info(dev) == $scriptInfo(dev) + && $argv0Info(ino) == $scriptInfo(ino)}] } else { return 0 } @@ -1460,6 +1476,11 @@ namespace eval natsort { #-- choose a policy and leave the others commented. #set is_called_directly $is_namematch #set is_called_directly $is_inodematch + + #puts "NATSORT: called_directly_namematch - $is_namematch" + #puts "NATSORT: called_directly_inodematch - $is_inodematch" + #flush stdout + set is_called_directly [expr {$is_namematch || $is_inodematch}] #set is_called_directly [expr {$is_namematch && $is_inodematch}] ### @@ -1921,6 +1942,8 @@ namespace eval natsort { #set args [check_flags -caller test1 -defaults [list -collate nocase -algorithm sort -topchars "\uFFFF" -winlike 0 -debug 0 -stacktrace 0 -showsplits 0] -required {all} -extras {none} -commandprocessors {{-cmd -default help} {-cmd -cmdarg1 -default "."} {-cmd -cmdarg2 -default j}} -values $::argv ] #set args [check_flags -caller test1 -defaults [list -collate nocase -algorithm sort -topchars "\uFFFF" -winlike 0 -debug 0 -stacktrace 0 -showsplits 0] -required {all} -extras {none} -commandprocessors {ls {ls lsdir -default "\uFFFF"}} -values $::argv ] + puts stderr "natsort directcall exit" + flush stderr exit 0 if {$::argc} { diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.6.5.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.6.5.tm index 143794fb..f7e4c1a5 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.6.5.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.6.5.tm @@ -163,7 +163,7 @@ proc overtype::string_columns {text} { tcl::namespace::eval overtype::priv { } -#could return larger than colwidth +#could return larger than renderwidth proc _get_row_append_column {row} { upvar outputlines outputlines set idx [expr {$row -1}] @@ -171,14 +171,14 @@ proc _get_row_append_column {row} { return 1 } else { upvar opt_overflow opt_overflow - upvar colwidth colwidth + upvar renderwidth renderwidth set existinglen [punk::ansi::printing_length [lindex $outputlines $idx]] set endpos [expr {$existinglen +1}] if {$opt_overflow} { return $endpos } else { - if {$endpos > $colwidth} { - return $colwidth + 1 + if {$endpos > $renderwidth} { + return $renderwidth + 1 } else { return $endpos } @@ -213,7 +213,20 @@ tcl::namespace::eval overtype { if {[llength $args] < 2} { error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} } - lassign [lrange $args end-1 end] underblock overblock + set optargs [lrange $args 0 end-2] + if {[llength $optargs] % 2 == 0} { + lassign [lrange $args end-1 end] underblock overblock + set argsflags [lrange $args 0 end-2] + } else { + set optargs [lrange $args 0 end-1] + if {[llength $optargs] %2 == 0} { + set overblock [lindex $args end] + set underblock "" + set argsflags [lrange $args 0 end-1] + } else { + error "renderspace expects opt-val pairs followed by: or just " + } + } set opts [tcl::dict::create\ -bias ignored\ -width \uFFEF\ @@ -230,12 +243,15 @@ tcl::namespace::eval overtype { -exposed2 \uFFFD\ -experimental 0\ -looplimit \uFFEF\ + -crm_mode 0\ + -reverse_mode 0\ ] #-ellipsis args not used if -wrap is true - set argsflags [lrange $args 0 end-2] foreach {k v} $argsflags { switch -- $k { - -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental { + -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines + - -transparent - -exposed1 - -exposed2 - -experimental + - -reverse_mode - -crm_mode { tcl::dict::set opts $k $v } default { @@ -261,6 +277,8 @@ tcl::namespace::eval overtype { set opt_exposed1 [tcl::dict::get $opts -exposed1] ;#widechar_exposed_left - todo set opt_exposed2 [tcl::dict::get $opts -exposed2] ;#widechar_exposed_right - todo # -- --- --- --- --- --- + set opt_crm_mode [tcl::dict::get $opts -crm_mode] + set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] # ---------------------------- # -experimental dev flag to set flags etc @@ -295,9 +313,10 @@ tcl::namespace::eval overtype { # ---------------------------- #modes - set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l - set autowrap_mode $opt_wrap - set reverse_mode 0 + set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l + set autowrap_mode $opt_wrap + set reverse_mode $opt_reverse_mode + set crm_mode $opt_crm_mode set underblock [tcl::string::map {\r\n \n} $underblock] @@ -307,33 +326,35 @@ tcl::namespace::eval overtype { #set underlines [split $underblock \n] #underblock is a 'rendered' block - so width height make sense - #colwidth & colheight were originally named with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. - #The naming is now confusing. It should be something like renderwidth renderheight ?? review + #only non-cursor affecting and non-width occupying ANSI codes should be present. + #ie SGR codes and perhaps things such as PM - although generally those should have been pushed to the application already + #renderwidth & renderheight were originally used with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. if {$opt_width eq "\uFFEF" || $opt_height eq "\uFFEF"} { - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } if {$opt_height ne "\uFFEF"} { - set colheight $opt_height + set renderheight $opt_height } } else { - set colwidth $opt_width - set colheight $opt_height + set renderwidth $opt_width + set renderheight $opt_height } # -- --- --- --- #REVIEW - do we need ansi resets in the underblock? if {$underblock eq ""} { - set underlines [lrepeat $colheight ""] + set underlines [lrepeat $renderheight ""] } else { + set underblock [textblock::join_basic -- $underblock] ;#ensure properly rendered - ansi per-line resets & replays set underlines [split $underblock \n] } #if {$underblock eq ""} { # set blank "\x1b\[0m\x1b\[0m" # #set underlines [list "\x1b\[0m\x1b\[0m"] - # set underlines [lrepeat $colheight $blank] + # set underlines [lrepeat $renderheight $blank] #} else { # #lines_as_list -ansiresets 1 will do nothing if -ansiresets 1 isn't specified - REVIEW # set underlines [lines_as_list -ansiresets 1 $underblock] @@ -341,7 +362,7 @@ tcl::namespace::eval overtype { # -- --- --- --- #todo - reconsider the 'line' as the natural chunking mechanism for the overlay. - #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth + #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output renderwidth #In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time. #(in cases where there are interline moves or cursor jumps anyway) #This works - but doesn't seem efficient. @@ -409,7 +430,7 @@ tcl::namespace::eval overtype { set replay_codes_underlay [tcl::dict::create 1 ""] #lappend replay_codes_overlay "" - set replay_codes_overlay "" + set replay_codes_overlay "[punk::ansi::a]" set unapplied "" set cursor_saved_position [tcl::dict::create] set cursor_saved_attributes "" @@ -452,14 +473,25 @@ tcl::namespace::eval overtype { } #review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary - #but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l - set LASTCALL [list -info 1 -insert_mode $insert_mode -autowrap_mode $autowrap_mode -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] + set LASTCALL [list -info 1\ + -insert_mode $insert_mode\ + -crm_mode $crm_mode\ + -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -transparent $opt_transparent\ + -width $renderwidth\ + -exposed1 $opt_exposed1\ + -exposed2 $opt_exposed2\ + -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] set rinfo [renderline -experimental $opt_experimental\ -info 1\ + -crm_mode $crm_mode\ -insert_mode $insert_mode\ - -cursor_restore_attributes $cursor_saved_attributes\ -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -cursor_restore_attributes $cursor_saved_attributes\ -transparent $opt_transparent\ - -width $colwidth\ + -width $renderwidth\ -exposed1 $opt_exposed1\ -exposed2 $opt_exposed2\ -overflow $opt_overflow\ @@ -471,7 +503,10 @@ tcl::namespace::eval overtype { set instruction [tcl::dict::get $rinfo instruction] set insert_mode [tcl::dict::get $rinfo insert_mode] set autowrap_mode [tcl::dict::get $rinfo autowrap_mode] ;# - #set reverse_mode [tcl::dict::get $rinfo reverse_mode];#how to support in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + set reverse_mode [tcl::dict::get $rinfo reverse_mode] + #how to support reverse_mode in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + # - review - the answer is probably that we don't need to - it is set/reset only during application of overtext + set crm_mode [tcl::dict::get $rinfo crm_mode] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] set overflow_right_column [tcl::dict::get $rinfo overflow_right_column] @@ -486,7 +521,36 @@ tcl::namespace::eval overtype { set insert_lines_below [tcl::dict::get $rinfo insert_lines_below] tcl::dict::set replay_codes_underlay [expr {$renderedrow+1}] [tcl::dict::get $rinfo replay_codes_underlay] #lset replay_codes_overlay [expr $overidx+1] [tcl::dict::get $rinfo replay_codes_overlay] - set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + if {0 && $reverse_mode} { + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + #review + #JMN3 + set existing_reverse_state 0 + #split_codes_single is single esc sequence - but could have multiple sgr codes within one esc sequence + #e.g \x1b\[0;31;7m has a reset,colour red and reverse + set codeinfo [punk::ansi::codetype::sgr_merge [list $replay_codes_overlay] -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + } @@ -520,7 +584,7 @@ tcl::namespace::eval overtype { incr row if {$data_mode} { set col [_get_row_append_column $row] - if {$col > $colwidth} { + if {$col > $renderwidth} { } } else { @@ -563,10 +627,10 @@ tcl::namespace::eval overtype { #we need renderline to return the number of the maximum column filled (or min if we ever do r-to-l) set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -601,10 +665,10 @@ tcl::namespace::eval overtype { } set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -640,9 +704,9 @@ tcl::namespace::eval overtype { puts stdout ">>>[a+ red bold]overflow_right during restore_cursor[a]" - set sub_info [overtype::renderline -info 1 -width $colwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] + set sub_info [overtype::renderline -info 1 -width $renderwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] set foldline [tcl::dict::get $sub_info result] - set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed.. + set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed..? set autowrap_mode [tcl::dict::get $sub_info autowrap_mode] ;#nor this.. linsert outputlines $renderedrow $foldline #review - row & col set by restore - but not if there was no save.. @@ -740,7 +804,7 @@ tcl::namespace::eval overtype { } } lf_overflow { - #linefeed after colwidth e.g at column 81 for an 80 col width + #linefeed after renderwidth e.g at column 81 for an 80 col width #we may also have other control sequences that came after col 80 e.g cursor save if 0 { @@ -833,10 +897,10 @@ tcl::namespace::eval overtype { } else { set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } } @@ -845,12 +909,12 @@ tcl::namespace::eval overtype { #doesn't seem to be used by fruit.ans testfile #used by dzds.ans #note that cursor_forward may move deep into the next line - or even span multiple lines !TODO - set c $colwidth + set c $renderwidth set r $post_render_row - if {$post_render_col > $colwidth} { + if {$post_render_col > $renderwidth} { set i $c while {$i <= $post_render_col} { - if {$c == $colwidth+1} { + if {$c == $renderwidth+1} { incr r if {$opt_appendlines} { if {$r < [llength $outputlines]} { @@ -874,7 +938,7 @@ tcl::namespace::eval overtype { set col $c } wrapmovebackward { - set c $colwidth + set c $renderwidth set r $post_render_row if {$post_render_col < 1} { set c 1 @@ -883,7 +947,7 @@ tcl::namespace::eval overtype { if {$c == 0} { if {$r > 1} { incr r -1 - set c $colwidth + set c $renderwidth } else { #leave r at 1 set c 1 #testfile besthpav.ans first line top left border alignment @@ -941,7 +1005,7 @@ tcl::namespace::eval overtype { #2nd half of grapheme would overflow - treggering grapheme is returned in unapplied. There may also be overflow_right from earlier inserts #todo - consider various options .. re-render a single trailing space or placeholder on same output line, etc if {$autowrap_mode} { - if {$colwidth < 2} { + if {$renderwidth < 2} { #edge case of rendering to a single column output - any 2w char will just cause a loop if we don't substitute with something, or drop the character set idx 0 set triggering_grapheme_index -1 @@ -960,7 +1024,7 @@ tcl::namespace::eval overtype { } else { set overflow_handled 1 #handled by dropping entire overflow if any - if {$colwidth < 2} { + if {$renderwidth < 2} { set idx 0 set triggering_grapheme_index -1 foreach u $unapplied_list { @@ -1141,12 +1205,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + #set renderwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] - #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {$colwidth - $overblock_width}] + set under_exposed_max [expr {$renderwidth - $overblock_width}] if {$under_exposed_max > 0} { #background block is wider if {$under_exposed_max % 2 == 0} { @@ -1176,14 +1239,14 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] set undertext "$undertext[string repeat { } $udiff]" } set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] #review - right-to-left langs should elide on left! - extra option required if {$overflowlength > 0} { @@ -1196,8 +1259,8 @@ tcl::namespace::eval overtype { #overlay line data is wider - trim if overflow not specified in opts - and overtype an ellipsis at right if it was specified if {![tcl::dict::get $opts -overflow]} { - #lappend outputlines [tcl::string::range $overtext 0 [expr {$colwidth - 1}]] - #set overtext [tcl::string::range $overtext 0 $colwidth-1 ] + #lappend outputlines [tcl::string::range $overtext 0 [expr {$renderwidth - 1}]] + #set overtext [tcl::string::range $overtext 0 $renderwidth-1 ] if {$opt_ellipsis} { set show_ellipsis 1 if {!$opt_ellipsiswhitespace} { @@ -1286,12 +1349,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] set left_exposed $under_exposed_max @@ -1307,8 +1369,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1336,10 +1398,17 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline\ + -info 1\ + -insert_mode 0\ + -transparent $opt_transparent\ + -exposed1 $opt_exposed1 -exposed2 $opt_exposed2\ + -overflow $opt_overflow\ + -startcolumn [expr {1 + $startoffset}]\ + $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] if {!$opt_overflow} { @@ -1433,12 +1502,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] switch -- $opt_blockalign { left { @@ -1484,8 +1552,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1513,7 +1581,7 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] @@ -1566,6 +1634,7 @@ tcl::namespace::eval overtype { #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #puts stderr "--> [ansistring VIEW -lf 1 -nul 1 $rinfo] <--" set overflow_right [tcl::dict::get $rinfo overflow_right] set unapplied [tcl::dict::get $rinfo unapplied] lappend outputlines [tcl::dict::get $rinfo result] @@ -1629,6 +1698,7 @@ tcl::namespace::eval overtype { -cursor_column 1\ -cursor_row ""\ -insert_mode 1\ + -crm_mode 0\ -autowrap_mode 1\ -reverse_mode 0\ -info 0\ @@ -1649,7 +1719,9 @@ tcl::namespace::eval overtype { set argsflags [lrange $args 0 end-2] tcl::dict::for {k v} $argsflags { switch -- $k { - -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -autowrap_mode - -reverse_mode - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { + -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row + - -crm_mode - -insert_mode - -autowrap_mode - -reverse_mode + - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { tcl::dict::set opts $k $v } default { @@ -1676,6 +1748,7 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_autowrap_mode [tcl::dict::get $opts -autowrap_mode] ;#DECAWM - char or movement can go beyond leftmost/rightmost col to prev/next line set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] ;#DECSNM + set opt_crm_mode [tcl::dict::get $opts -crm_mode];# CRM - show control character mode # -- --- --- --- --- --- --- --- --- --- --- --- set temp_cursor_saved [tcl::dict::get $opts -cursor_restore_attributes] @@ -1721,6 +1794,10 @@ tcl::namespace::eval overtype { set cursor_row $opt_row_context } + set insert_mode $opt_insert_mode ;#default 1 + set autowrap_mode $opt_autowrap_mode ;#default 1 + set crm_mode $opt_crm_mode ;#default 0 (Show Control Character mode) + set reverse_mode $opt_reverse_mode #----- # @@ -1768,6 +1845,7 @@ tcl::namespace::eval overtype { } set understacks [list] set understacks_gx [list] + set pm_list [list] set i_u -1 ;#underlay may legitimately be empty set undercols [list] @@ -1834,6 +1912,7 @@ tcl::namespace::eval overtype { #underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc + #keep any remaining PMs in place if {$code ne ""} { set c1c2 [tcl::string::range $code 0 1] @@ -1841,6 +1920,8 @@ tcl::namespace::eval overtype { \x1b\[ 7CSI\ \x9b 8CSI\ \x1b\( 7GFX\ + \x1b^ 7PMX\ + \x1bX 7SOS\ ] $c1c2] 0 3];# leadernorm is 1st 2 chars mapped to normalised indicator - or is original 2 chars switch -- $leadernorm { @@ -1875,6 +1956,26 @@ tcl::namespace::eval overtype { } } } + 7PMX - 7SOS { + #we can have PMs or SOS (start of string) in the underlay - though mostly the PMs should have been processed.. + #attach the PM/SOS (entire ANSI sequence) to the previous grapheme! + #It should not affect the size - but terminal display may get thrown out if terminal doesn't support them. + + #note that there may in theory already be ANSI stored - we don't assume it was a pure grapheme string + set graphemeplus [lindex $undercols end] + if {$graphemeplus ne "\0"} { + append graphemeplus $code + } else { + set graphemeplus $code + } + lset undercols end $graphemeplus + #The grapheme_width_cached function will be called on this later - and doesn't account for ansi. + #we need to manually cache the item with it's proper width + variable grapheme_widths + #stripped and plus version keys pointing to same length + dict set grapheme_widths $graphemeplus [grapheme_width_cached [::punk::ansi::ansistrip $graphemeplus]] + + } default { } @@ -1937,9 +2038,9 @@ tcl::namespace::eval overtype { } if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } else { - set colwidth [llength $undercols] + set renderwidth [llength $undercols] } @@ -2017,12 +2118,30 @@ tcl::namespace::eval overtype { } append pt_overchars $pt #will get empty pt between adjacent codes - foreach grapheme [punk::char::grapheme_split $pt] { - lappend overstacks $o_codestack - lappend overstacks_gx $o_gxstack - incr i_o - lappend overlay_grapheme_control_list [list g $grapheme] - lappend overlay_grapheme_control_stacks $o_codestack + if {!$crm_mode} { + foreach grapheme [punk::char::grapheme_split $pt] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } else { + foreach grapheme_original [punk::char::grapheme_split $pt] { + set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original] + foreach grapheme [punk::char::grapheme_split $pt_crm] { + if {$grapheme eq "\n"} { + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"] + } else { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + } } #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc @@ -2030,40 +2149,91 @@ tcl::namespace::eval overtype { # that pure resets are fairly common - more so than leading resets with other info # that non-sgr codes are not that common, so ok to check for resets before verifying it is actually SGR at all. if {$code ne ""} { - lappend overlay_grapheme_control_stacks $o_codestack - #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) - if {[punk::ansi::codetype::is_sgr_reset $code]} { - set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set o_codestack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #basic simplification first - remove straight dupes - set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars - set o_codestack [lremove $o_codestack {*}$dup_posns] - lappend o_codestack $code - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[regexp {\x1b7|\x1b\[s} $code]} { - #experiment - #cursor_save - for the replays review. - #jmn - #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] - lappend overlay_grapheme_control_list [list other $code] - } elseif {[regexp {\x1b8|\x1b\[u} $code]} { - #experiment - #cursor_restore - for the replays - set o_codestack [list $temp_cursor_saved] - lappend overlay_grapheme_control_list [list other $code] + #we need to immediately set crm_mode here if \x1b\[3h received + if {$code eq "\x1b\[3h"} { + set crm_mode 1 + } elseif {$code eq "\x1b\[3l"} { + set crm_mode 0 + } + #else crm_mode could be set either way from options + if {$crm_mode && $code ne "\x1b\[00001E"} { + #treat the code as type 'g' like above - only allow through codes to reset mode REVIEW for now just \x1b\[3l ? + #we need to somehow convert further \n in the graphical rep to an instruction for newline that will bypass further crm_mode processing or we would loop. + set code_as_pt [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $code] + #split using standard split for first foreach loop - grapheme based split when processing 2nd foreach loop + set chars [split $code_as_pt ""] + set codeparts [list] ;#list of 2-el lists each element {crmcontrol } or {g } + foreach c $chars { + if {$c eq "\n"} { + #use CNL (cursor next line) \x1b\[00001E ;#leading zeroes ok for this processor - used as debugging aid to distinguish + lappend codeparts [list crmcontrol "\x1b\[00001E"] + } else { + if {[llength $codeparts] > 0 && [lindex $codeparts end 0] eq "g"} { + set existing [lindex $codeparts end 1] + lset codeparts end [list g [string cat $existing $c]] + } else { + lappend codeparts [list g $c] + } + } + } + + set partidx 0 + foreach record $codeparts { + lassign $record rtype rval + switch -exact -- $rtype { + g { + append pt_overchars $rval + foreach grapheme [punk::char::grapheme_split $rval] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + crmcontrol { + #leave o_codestack + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol $rval] + } + } + } } else { - if {[punk::ansi::codetype::is_gx_open $code]} { - set o_gxstack [list "gx0_on"] - lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } elseif {[punk::ansi::codetype::is_gx_close $code]} { - set o_gxstack [list] - lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } else { + lappend overlay_grapheme_control_stacks $o_codestack + #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) + if {[punk::ansi::codetype::is_sgr_reset $code]} { + set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set o_codestack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #basic simplification first - remove straight dupes + set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars + set o_codestack [lremove $o_codestack {*}$dup_posns] + lappend o_codestack $code + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[regexp {\x1b7|\x1b\[s} $code]} { + #experiment + #cursor_save - for the replays review. + #jmn + #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] + lappend overlay_grapheme_control_list [list other $code] + } elseif {[regexp {\x1b8|\x1b\[u} $code]} { + #experiment + #cursor_restore - for the replays + set o_codestack [list $temp_cursor_saved] lappend overlay_grapheme_control_list [list other $code] + } else { + if {[punk::ansi::codetype::is_gx_open $code]} { + set o_gxstack [list "gx0_on"] + lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } elseif {[punk::ansi::codetype::is_gx_close $code]} { + set o_gxstack [list] + lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } else { + lappend overlay_grapheme_control_list [list other $code] + } } } } @@ -2135,9 +2305,6 @@ tcl::namespace::eval overtype { #movements only occur within the overlay range. #an underlay is however not necessary.. e.g #renderline -overflow 1 "" data - #foreach {pt code} $overmap {} - set insert_mode $opt_insert_mode ;#default 1 - set autowrap_mode $opt_autowrap_mode ;#default 1 #set re_mode {\x1b\[\?([0-9]*)(h|l)} ;#e.g DECAWM #set re_col_move {\x1b\[([0-9]*)(C|D|G)$} @@ -2163,13 +2330,28 @@ tcl::namespace::eval overtype { switch -- $type { g { set ch $item + #crm_mode affects both graphic and control + if {$crm_mode} { + set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $ch] + set chars [string map [list \n "\x1b\[00001E"] $chars] + if {[llength [split $chars ""]] > 1} { + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + #incr idx_over + break + } else { + set ch $chars + } + } incr idx_over; #idx_over (until unapplied reached anyway) is per *grapheme* in the overlay - not per col. if {($idx < ($opt_colstart -1))} { incr idx [grapheme_width_cached $ch] continue } #set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our active data width - set within_undercols [expr {$idx <= $colwidth-1}] + set within_undercols [expr {$idx <= $renderwidth-1}] #https://www.enigma.com/resources/blog/the-secret-world-of-newline-characters #\x85 NEL in the c1 control set is treated by some terminal emulators (e.g Hyper) as a newline, @@ -2311,6 +2493,7 @@ tcl::namespace::eval overtype { } else { #todo - punk::char::char_width set g [lindex $outcols $idx] + #JMN set uwidth [grapheme_width_cached $g] if {[lindex $outcols $idx] eq ""} { #2nd col of 2-wide char in underlay @@ -2485,13 +2668,29 @@ tcl::namespace::eval overtype { } - other { + other - crmcontrol { + if {$crm_mode && $type ne "crmcontrol" && $item ne "\x1b\[00001E"} { + if {$item eq "\x1b\[3l"} { + set crm_mode 0 + } else { + #When our initial overlay split was done - we weren't in crm_mode - so there are codes that weren't mapped to unicode control character representations + #set within_undercols [expr {$idx <= $renderwidth-1}] + #set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $item] + set chars [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $item] + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + + break + } + } + #todo - consider CSI s DECSLRM vs ansi.sys \x1b\[s - we need \x1b\[s for oldschool ansi art - but may have to enable only for that. - #we should probably therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore + #we should possibly therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore? set code [tcl::string::map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $item] #since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied' - set matchinfo [list] #remap of DEC cursor_save/cursor_restore from ESC sequence to equivalent CSI #probably not ideal - consider putting cursor_save/cursor_restore in functions so they can be called from the appropriate switch branch instead of using this mapping @@ -2501,7 +2700,7 @@ tcl::namespace::eval overtype { set c1c2c3 [tcl::string::range $code 0 2] #set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)} #tcl 8.7 - faster to use inline list than to store it in a local var outside of loop. - #(surprising - but presumably ) + #(somewhat surprising) set leadernorm [tcl::string::range [tcl::string::map [list\ \x1b\[< 1006\ \x1b\[ 7CSI\ @@ -2509,7 +2708,7 @@ tcl::namespace::eval overtype { \x1b\] 7OSC\ \x9d 8OSC\ \x1b 7ESC\ - ] $c1c2c3] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars + ] $c1c2c3] 0 3] ;#leadernorm is 1st 1,2 or 3 chars mapped to 4char normalised indicator - or is original first chars (1,2 or 3 len) #we leave the tail of the code unmapped for now switch -- $leadernorm { @@ -2528,7 +2727,10 @@ tcl::namespace::eval overtype { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } default { + puts stderr "Sequence detected as ANSI, but not handled in leadernorm switch. code: [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" #we haven't made a mapping for this + #could in theory be 1,2 or 3 in len + #although we shouldn't be getting here if the regexp for ansi codes is kept in sync with our switch branches set codenorm $code } } @@ -2551,44 +2753,44 @@ tcl::namespace::eval overtype { {7CSI} - {8CSI} { set param [tcl::string::range $codenorm 4 end-1] #puts stdout "--> CSI [tcl::string::index $leadernorm 0] bit param:$param" - switch -- [tcl::string::index $codenorm end] { - D { - #Col move - #puts stdout "<-back" - #cursor back - #left-arrow/move-back when ltr mode + set code_end [tcl::string::index $codenorm end] ;#used for e.g h|l set/unset mode + switch -exact -- $code_end { + A { + #Row move - up + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set num $param if {$num eq ""} {set num 1} + incr cursor_row -$num - set version 2 - if {$version eq "2"} { - #todo - startcolumn offset! - if {$cursor_column - $num >= 1} { - incr idx -$num - incr cursor_column -$num - } else { - if {!$autowrap_mode} { - set cursor_column 1 - set idx 0 - } else { - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - incr cursor_column -$num - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction wrapmovebackward - break - } - } - } else { - incr idx -$num - incr cursor_column -$num - if {$idx < $opt_colstart-1} { - #wrap to previous line and position cursor at end of data - set idx [expr {$opt_colstart-1}] - set cursor_column $opt_colstart - } + if {$cursor_row < 1} { + set cursor_row 1 } + + #ensure rest of *overlay* is emitted to remainder + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction up + #retain cursor_column + break + } + B { + #CUD - Cursor Down + #Row move - down + set num $param + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #move down + if {$num eq ""} {set num 1} + incr cursor_row $num + + + incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction down + #retain cursor_column + break } C { + #CUF - Cursor Forward #Col move #puts stdout "->forward" #todo - consider right-to-left cursor mode (e.g Hebrew).. some day. @@ -2692,80 +2894,215 @@ tcl::namespace::eval overtype { } } } - G { + D { #Col move - #move absolute column - #adjust to colstart - as column 1 is within overlay - #??? - set idx [expr {$param + $opt_colstart -1}] - set cursor_column $param - error "renderline absolute col move ESC G unimplemented" - } - A { - #Row move - up - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #puts stdout "<-back" + #cursor back + #left-arrow/move-back when ltr mode set num $param if {$num eq ""} {set num 1} - incr cursor_row -$num - if {$cursor_row < 1} { - set cursor_row 1 + set version 2 + if {$version eq "2"} { + #todo - startcolumn offset! + if {$cursor_column - $num >= 1} { + incr idx -$num + incr cursor_column -$num + } else { + if {!$autowrap_mode} { + set cursor_column 1 + set idx 0 + } else { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr cursor_column -$num + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction wrapmovebackward + break + } + } + } else { + incr idx -$num + incr cursor_column -$num + if {$idx < $opt_colstart-1} { + #wrap to previous line and position cursor at end of data + set idx [expr {$opt_colstart-1}] + set cursor_column $opt_colstart + } } - - #ensure rest of *overlay* is emitted to remainder + } + E { + #CNL - Cursor Next Line + if {$param eq ""} { + set downmove 1 + } else { + set downmove [expr {$param}] + } + puts stderr "renderline CNL down-by-$downmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row + $downmove}] + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction up - #retain cursor_column - break + set instruction move + break + } - B { - #Row move - down - set num $param + F { + #CPL - Cursor Previous Line + if {$param eq ""} { + set upmove 1 + } else { + set upmove [expr {$param}] + } + puts stderr "renderline CPL up-by-$upmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row -$upmove}] + if {$cursor_row < 1} { + set cursor_row 1 + } + set idx [expr {$cursor_column - 1}] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #move down - if {$num eq ""} {set num 1} - incr cursor_row $num - - - incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction down - #retain cursor_column - break + set instruction move + break + + } + G { + #CHA - Cursor Horizontal Absolute (move to absolute column no) + if {$param eq ""} { + set targetcol 1 + } else { + set targetcol $param + if {![string is integer -strict $targetcol]} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Unrecognised parameter '$param'" + } + set targetcol [expr {$param}] + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$targetcol > $max} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Param '$param' > max: $max" + set targetcol $max + } + } + #adjust to colstart - as column 1 is within overlay + #??? REVIEW + set idx [expr {($targetcol -1) + $opt_colstart -1}] + + + set cursor_column $targetcol + #puts stderr "renderline absolute col move ESC G (TEST)" } H - f { - #$re_both_move - lassign [split $param {;}] row col - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #lassign $matchinfo _match row col + #CSI n;m H - CUP - Cursor Position - if {$col eq ""} {set col 1} - set max [llength $outcols] - if {$overflow_idx == -1} { - incr max - } - if {$col > $max} { - set cursor_column $max + #CSI n;m f - HVP - Horizontal Vertical Position REVIEW - same as CUP with differences (what?) in some terminal modes + # - 'counts as effector format function (like CR or LF) rather than an editor function (like CUD or CNL)' + # - REVIEW + #see Annex A at: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf + + #test e.g ansicat face_2.ans + #$re_both_move + lassign [split $param {;}] paramrow paramcol + #missing defaults to 1 + #CSI ;5H = CSI 1;5H -> row 1 col 5 + #CSI 17;H = CSI 17H = CSI 17;1H -> row 17 col 1 + + if {$paramcol eq ""} {set paramcol 1} + if {$paramrow eq ""} {set paramrow 1} + if {![string is integer -strict $paramcol] || ![string is integer -strict $paramrow]} { + puts stderr "renderline CUP (CSI H) unrecognised param $param" + #ignore? } else { - set cursor_column $col + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$paramcol > $max} { + set target_column $max + } else { + set target_column [expr {$paramcol}] + } + + + if {$paramrow < 1} { + puts stderr "renderline CUP (CSI H) bad row target 0. Assuming 1" + set target_row 1 + } else { + set target_row [expr {$paramrow}] + } + if {$target_row == $cursor_row} { + #col move only - no need for break and move + #puts stderr "renderline CUP col move only to col $target_column param:$param" + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + } else { + set cursor_row $target_row + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } } - set idx [expr {$cursor_column -1}] + } + J { + puts stderr "overtype::renderline ED - ERASE IN DISPLAY (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of screen + } + 1 { + #clear from cursor to beginning of screen + } + 2 { + #clear entire screen + #ansi.sys - move cursor to upper left REVIEW + set cursor_row 1 + set cursor_column 1 + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } + 3 { + #clear entire screen. presumably cursor doesn't move - otherwise it would be same as 2J ? - if {$row eq ""} {set row 1} - set cursor_row $row - if {$cursor_row < 1} { - set cursor_row 1 + } + default { + } } - incr idx_over - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction move - break + } + K { + puts stderr "overtype::renderline EL - ERASE IN LINE (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line + } + 1 { + #clear from cursor to beginning of line + } + 2 { + #clear entire line + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } } X { - puts stderr "X - $param" + puts stderr "overtype::renderline X ECH ERASE CHARACTER - $param" #ECH - erase character if {$param eq "" || $param eq "0"} {set param 1}; #param=count of chars to erase priv::render_erasechar $idx $param @@ -2789,78 +3126,119 @@ tcl::namespace::eval overtype { break } s { - # - todo - make ansi.sys CSI s cursor save only apply for certain cases? - may need to support DECSLRM instead which uses same code - - #$re_cursor_save - #cursor save could come after last column - if {$overflow_idx != -1 && $idx == $overflow_idx} { - #bartman2.ans test file - fixes misalignment at bottom of dialog bubble - #incr cursor_row - #set cursor_column 1 - #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) - set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] - } else { - set cursor_saved_position [list row $cursor_row column $cursor_column] - } - #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. - #we need the SGR and gx overlay codes prior to the cursor_save + #code conflict between ansi emulation and DECSLRM - REVIEW + #ANSISYSSC (when no parameters) - like other terminals - essentially treat same as DECSC + # todo - when parameters - support DECSLRM instead + + if {$param ne ""} { + #DECSLRM - should only be recognised if DECLRMM is set (vertical split screen mode) + lassign [split $param {;} margin_left margin_right + puts stderr "overtype DECSLRM not yet supported - got [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$margin_left eq ""} { + set margin_left 1 + } + set columns_per_page 80 ;#todo - set to 'page width (DECSCPP set columns per page)' - could be 132 or?? + if {$margin_right eq ""} { + set margin_right $columns_per_page + } + puts stderr "DECSLRM margin left: $margin_left margin right: $margin_right" + if {![string is integer -strict $margin_left] || $margin_left < 0} { + puts stderr "DECSLRM invalid margin_left" + } + if {![string is integer -strict $margin_right] || $margin_right < 0} { + puts stderr "DECSLRM invalid margin_right" + } + set scrolling_region_size [expr {$margin_right - $margin_left}] + if {$scrolling_region_size < 2 || $scrolling_region_size > $columns_per_page} { + puts stderr "DECSLRM region size '$scrolling_regsion_size' must be between 1 and $columns_per_page" + } + #todo - #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. - #set sgr_stack [lindex $understacks $idx] - #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) - - set sgr_stack [list] - set gx_stack [list] - - #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. - #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. - - foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { - lassign $gc type code - #types g other sgr gx0 - switch -- $type { - gx0 { - #code is actually a stand-in for the graphics on/off code - not the raw code - #It is either gx0_on or gx0_off - set gx_stack [list $code] - } - sgr { - #code is the raw code - if {[punk::ansi::codetype::is_sgr_reset $code]} { - #jmn - set sgr_stack [list "\x1b\[m"] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set sgr_stack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #often we don't get resets - and codes just pile up. - #as a first step to simplifying - at least remove earlier straight up dupes - set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) - set sgr_stack [lremove $sgr_stack {*}$dup_posns] - lappend sgr_stack $code + + } else { + #DECSC + #//notes on expected behaviour: + #DECSC - saves following items in terminal's memory + #cursor position + #character attributes set by the SGR command + #character sets (G0,G1,G2 or G3) currently in GL and GR + #Wrap flag (autowrap or no autowrap) + #State of origin mode (DECOM) + #selective erase attribute + #any single shift 2 (SS2) or single shift 3(SSD) functions sent + + #$re_cursor_save + #cursor save could come after last column + if {$overflow_idx != -1 && $idx == $overflow_idx} { + #bartman2.ans test file - fixes misalignment at bottom of dialog bubble + #incr cursor_row + #set cursor_column 1 + #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) + set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] + } else { + set cursor_saved_position [list row $cursor_row column $cursor_column] + } + #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. + #we need the SGR and gx overlay codes prior to the cursor_save + + #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. + #set sgr_stack [lindex $understacks $idx] + #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) + + set sgr_stack [list] + set gx_stack [list] + + #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. + #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. + + foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { + lassign $gc type code + #types g other sgr gx0 + switch -- $type { + gx0 { + #code is actually a stand-in for the graphics on/off code - not the raw code + #It is either gx0_on or gx0_off + set gx_stack [list $code] + } + sgr { + #code is the raw code + if {[punk::ansi::codetype::is_sgr_reset $code]} { + #jmn + set sgr_stack [list "\x1b\[m"] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set sgr_stack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #often we don't get resets - and codes just pile up. + #as a first step to simplifying - at least remove earlier straight up dupes + set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) + set sgr_stack [lremove $sgr_stack {*}$dup_posns] + lappend sgr_stack $code + } } } } - } - set cursor_saved_attributes "" - switch -- [lindex $gx_stack 0] { - gx0_on { - append cursor_saved_attributes "\x1b(0" - } - gx0_off { - append cursor_saved_attributes "\x1b(B" + set cursor_saved_attributes "" + switch -- [lindex $gx_stack 0] { + gx0_on { + append cursor_saved_attributes "\x1b(0" + } + gx0_off { + append cursor_saved_attributes "\x1b(B" + } } - } - #append cursor_saved_attributes [join $sgr_stack ""] - append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] + #append cursor_saved_attributes [join $sgr_stack ""] + append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] - #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. + #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. - #don't incr index - or the save will cause cursor to move to the right - #carry on - + #don't incr index - or the save will cause cursor to move to the right + #carry on + } } u { + #ANSISYSRC save cursor (when no parameters) (DECSC) + #$re_cursor_restore #we are going to jump somewhere.. for now we will assume another line, and process accordingly. #The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line) @@ -2903,7 +3281,6 @@ tcl::namespace::eval overtype { } ~ { #$re_vt_sequence - #lassign $matchinfo _match key mod lassign [split $param {;}] key mod #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ @@ -2972,64 +3349,129 @@ tcl::namespace::eval overtype { } h - l { + #set mode unset mode #we are matching only last char to get to this arm - but are there other sequences ending in h|l we need to handle? #$re_mode if first after CSI is "?" #some docs mention ESC=h|l - not seen on windows terminals.. review #e.g https://www2.math.upenn.edu/~kazdan/210/computer/ansi.html - if {[tcl::string::index $codenorm 4] eq "?"} { - set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l - #lassign $matchinfo _match num type - switch -- $num { - 5 { - #DECSNM - reverse video - #How we simulate this to render within a block of text is an open question. - #track all SGR stacks and constantly flip based on the current SGR reverse state? - #It is the job of the calling loop to do this - so at this stage we'll just set the states - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set reverse_mode 1 - } else { - #reset (disable) - set reverse_mode 0 + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? = + switch -exact -- $modegroup { + ? { + set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l + switch -- $num { + 5 { + #DECSNM - reverse video + #How we simulate this to render within a block of text is an open question. + #track all SGR stacks and constantly flip based on the current SGR reverse state? + #It is the job of the calling loop to do this - so at this stage we'll just set the states + + if {$code_end eq "h"} { + #set (enable) + set reverse_mode 1 + } else { + #reset (disable) + set reverse_mode 0 + } + + } + 7 { + #DECAWM autowrap + if {$code_end eq "h"} { + #set (enable) + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } + #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. + if {$idx >= $overflow_idx} { + puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + } else { + #reset (disable) + set autowrap_mode 0 + set overflow_idx -1 + } } + 25 { + if {$code_end eq "h"} { + #visible cursor + } else { + #invisible cursor + + } + } } - 7 { - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set autowrap_mode 1 - if {$opt_width ne "\uFFEF"} { - set overflow_idx $opt_width + } + = { + set num [tcl::string::range $codenorm 5 end-1] ;#param between = and h|l + puts stderr "overtype::renderline CSI=...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + #e.g CSI 4 h + set num [tcl::string::range $codenorm 4 end-1] ;#param before h|l + switch -exact -- $num { + 3 { + puts stderr "CRM MODE $code_end" + #CRM - Show control character mode + # 'No control functions are executed except LF,FF and VT which are represented in the CRM FONT before a CRLF(new line) is executed' + # + #use ansistring VIEW -nul 1 -lf 2 -ff 2 -vt 2 + #https://vt100.net/docs/vt510-rm/CRM.html + if {$code_end eq "h"} { + set crm_mode 1 } else { - #review - this is also the cursor position when adding a char at end of line? - set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + set crm_mode 0 } - #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. - if {$idx >= $overflow_idx} { - puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + 4 { + #IRM - Insert/Replace Mode + if {$code_end eq "h"} { + set insert_mode 1 + } else { + #replace mode + set insert_mode 0 } - } else { - #reset (disable) - set autowrap_mode 0 - set overflow_idx -1 } + default { + puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + } + } + } + } + | { + switch -- [tcl::string::index $codenorm end-1] { + {$} { + #CSI ... $ | DECSCPP set columns per page- (recommended in vt510 docs as preferable to DECCOLM) + #real terminals generally only supported 80/132 + #some other virtuals support any where from 2 to 65,536? + #we will allow arbitrary widths >= 2 .. to some as yet undetermined limit. + #CSI $ | + #empty or 0 param is 80 for compatibility - other numbers > 2 accepted + set page_width -1 ;#flag as unset + if {$param eq ""} { + set page_width 80 + } elseif {[string is integer -strict $param] && $param >=2 0} { + set page_width [expr {$param}] ;#we should allow leading zeros in the number - but lets normalize using expr + } else { + puts stderr "overtype::renderline unacceptable DECSPP value '$param'" } - 25 { - if {$type eq "h"} { - #visible cursor - } else { - #invisible cursor + if {$page_width > 2} { + puts stderr "overtype::renderline DECSCPP - not implemented - but selected width '$page_width' looks ok" + #if cursor already beyond new page_width - will move to right colum - otherwise no cursor movement - } } - } - } else { - puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + puts stderr "overtype::renderline unrecognised CSI code ending in pipe (|) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } } } default { @@ -3038,8 +3480,9 @@ tcl::namespace::eval overtype { } } 7ESC { - #$re_other_single - switch -- [tcl::string::index $codenorm end] { + #re_other_single {\x1b(D|M|E)$} + #also PM \x1b^...(ST) + switch -- [tcl::string::index $codenorm 4] { D { #\x84 #index (IND) @@ -3080,20 +3523,66 @@ tcl::namespace::eval overtype { puts stderr "ESC E unimplemented" } + ^ { + #puts stderr "renderline PM" + #Privacy Message. + if {[string index $code end] eq "\007"} { + set pm_content [string range $code 2 end-1] ;#ST is \007 + } else { + set pm_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #We don't want to render it - but we need to make it available to the application + #see the textblock library in punk, for the exception we make here for single backspace. + #It is unlikely to be encountered as a useful PM - so we hack to pass it through as a fix + #for spacing issues on old terminals which miscalculate the single-width 'Symbols for Legacy Computing' + if {$pm_content eq "\b"} { + #puts stderr "renderline PM sole backspace special handling for \U1FB00 - \U1FBFF" + #esc^\b\007 or esc^\besc\\ + #HACKY pass-through - targeting terminals that both mis-space legacy symbols *and* don't support PMs + #The result is repair of the extra space. If the terminal is a modern one and does support PM - the \b should be hidden anyway. + #If the terminal has the space problem AND does support PMs - then this just won't fix it. + #The fix relies on the symbol-supplier to cooperate by appending esc^\b\esc\\ to the problematic symbols. + + #priv::render_addchar $idx $code [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode + #idx has been incremented after last grapheme added + priv::render_append_to_char [expr {$idx -1}] $code + } + #lappend to a dict element in the result for application-specific processing + lappend pm_list $pm_content + } + N - O { + puts stderr "overtype::renderline single shift command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + P { + puts stderr "overtype::renderline DEVICE CONTROL STRING command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + X { + #SOS + if {[string index $code end] eq "\007"} { + set sos_content [string range $code 2 end-1] ;#ST is \007 + } else { + set sos_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #return in some useful form to the caller + #TODO! + lappend sos_list [list string $sos_content row $cursor_row column $cursor_column] + puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + _ { + #APC Application Program Command + #just warn for now.. + puts stderr "overtype::renderline ESC_ APC command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } default { - puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented codenorm:[ansistring VIEW -lf 1 -vt 1 -nul 1 $codenorm]" } } } + default { + } } - #switch -regexp -matchvar matchinfo -- $code\ - #$re_mode { - #}\ - #default { - # puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" - #} } default { @@ -3275,8 +3764,10 @@ tcl::namespace::eval overtype { overflow_right $overflow_right\ unapplied $unapplied\ unapplied_list $unapplied_list\ - insert_mode $insert_mode\ - autowrap_mode $autowrap_mode\ + insert_mode $insert_mode\ + autowrap_mode $autowrap_mode\ + crm_mode $crm_mode\ + reverse_mode $reverse_mode\ insert_lines_above $insert_lines_above\ insert_lines_below $insert_lines_below\ cursor_saved_position $cursor_saved_position\ @@ -3287,6 +3778,7 @@ tcl::namespace::eval overtype { replay_codes $replay_codes\ replay_codes_underlay $replay_codes_underlay\ replay_codes_overlay $replay_codes_overlay\ + pm_list $pm_list\ ] if {$opt_returnextra == 1} { return $result @@ -3370,8 +3862,9 @@ tcl::namespace::eval overtype::piper { } interp alias "" piper_renderline "" overtype::piper::renderline -#intended for single grapheme - but will work for multiple -#cannot contain ansi or newlines +#intended primarily for single grapheme - but will work for multiple +#WARNING: query CAN contain ansi or newlines - but if cache was not already set manually,the answer will be incorrect! +#We deliberately allow this for PM/SOS attached within a column #(a cache of ansifreestring_width calls - as these are quite regex heavy) proc overtype::grapheme_width_cached {ch} { variable grapheme_widths @@ -3439,6 +3932,7 @@ tcl::namespace::eval overtype::priv { tcl::dict::set cache_is_sgr $code $answer return $answer } + # better named render_to_unapplied? proc render_unapplied {overlay_grapheme_control_list gci} { upvar idx_over idx_over upvar unapplied unapplied @@ -3532,7 +4026,7 @@ tcl::namespace::eval overtype::priv { set ustacks [lreplace $ustacks $i $i] set gxstacks [lreplace $gxstacks $i $i] } else { - + puts stderr "render_delchar - attempt to delchar at index $i >= number of outcols $nxt - shouldn't happen" } } proc render_erasechar {i count} { @@ -3563,21 +4057,68 @@ tcl::namespace::eval overtype::priv { upvar outcols o lset o $i $c } + + #Initial usecase is for old-terminal hack to add PM-wrapped \b + #review - can be used for other multibyte sequences that occupy one column? + #combiners? diacritics? + proc render_append_to_char {i c} { + upvar outcols o + if {$i > [llength $o]-1} { + error "render_append_to_char cannot append [ansistring VIEW -lf 1 -nul 1 $c] to existing char at index $i while $i >= llength outcols [llength $o]" + } + set existing [lindex $o $i] + if {$existing eq "\0"} { + lset o $i $c + } else { + lset o $i [string cat $existing $c] + } + } #is actually addgrapheme? proc render_addchar {i c sgrstack gx0stack {insert_mode 0}} { upvar outcols o upvar understacks ustacks upvar understacks_gx gxstacks - if 0 { - if {$c eq "c"} { - puts "i:$i c:$c sgrstack:[ansistring VIEW $sgrstack]" - puts "understacks:[ansistring VIEW $ustacks]" - upvar overstacks overstacks - puts "overstacks:[ansistring VIEW $overstacks]" - puts "info level 0:[info level 0]" - } + # -- --- --- + #this is somewhat of a hack.. probably not really the equivalent of proper reverse video? review + #we should ideally be able to reverse the video of a sequence that already includes SGR reverse/noreverse attributes + upvar reverse_mode do_reverse + #if {$do_reverse} { + # lappend sgrstack [a+ reverse] + #} else { + # lappend sgrstack [a+ noreverse] + #} + + #JMN3 + if {$do_reverse} { + #note we can't just look for \x1b\[7m or \x1b\[27m + # it may be a more complex sequence like \x1b\[0\;\;7\;31m etc + + set existing_reverse_state 0 + set codeinfo [punk::ansi::codetype::sgr_merge $sgrstack -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set sgrstack [list [dict get $codeinfo mergeresult] $rflip] + #set sgrstack [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] } + + # -- --- --- set nxt [llength $o] if {!$insert_mode} { diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm index 85cb9f27..7a2f9443 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm @@ -553,28 +553,51 @@ tcl::namespace::eval punk::ansi { $obj destroy return $result } - proc example {} { + proc example {args} { + set base [punk::repo::find_project] + set default_ansibase [file join $base src/testansi] + + set argd [punk::args::get_dict [tstr -return string { + *proc -name punk::ansi::example -help "Display .ans image files in a grid that will fit in console + " + -colwidth -default 82 -help "Width of each column - default of 82 will fit a standard 80wide ansi image (when framed) + You can specify a narrower width to truncate images on the right side" + -folder -default "${$default_ansibase}" -help "Base folder for files if relative paths are used. + Defaults to /src/testansi - where projectbase is determined from current directory. + " + *values -min 0 -max -1 + files -default {belinda.ans bot.ans flower.ans fish.ans} -multiple true -help "List of filenames - leave empty to display 4 defaults" + }] $args] + set colwidth [dict get $argd opts -colwidth] + set ansibase [file normalize [dict get $argd opts -folder]] + set fnames [dict get $argd values files] + + #assumes fixed column widths e.g 80col images will fit in 82-width frames (common standard for old ansi art) (of arbitrary height) #todo - review dependency on punk::repo ? package require textblock package require punk::repo package require punk::console - set fnames [list belinda.ans bot.ans flower.ans fish.ans] - set base [punk::repo::find_project] - set ansibase [file join $base src/testansi] if {![file exists $ansibase]} { - puts stderr "Missing testansi folder at $base/src/testansi" + puts stderr "Missing folder at $ansibase" puts stderr "Ensure ansi test files exist: $fnames" #error "punk::ansi::example Cannot find example files" } - set missingbase [a+ yellow][textblock::block 80 23 ?][a] + set missingbase [a+ yellow][textblock::block [expr {$colwidth-2}] 23 ?][a] ;#assuming standard frame - subtract 2 for left/right borders set pics [list] foreach f $fnames { - if {![file exists $ansibase/$f]} { - set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$ansibase/$f[a]"] + if {[file pathtype $f] ne "absolute"} { + set filepath [file normalize $ansibase/$f] + } else { + set filepath [file normalize $f] + } + if {![file exists $filepath]} { + set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$f[a]"] lappend pics [tcl::dict::create filename $f pic $p status missing] } else { - set img [join [lines_as_list -line trimline -block trimtail [ansicat $ansibase/$f]] \n] + #set img [join [lines_as_list -line trimline -block trimtail [ansicat $filepath]] \n] + #-line trimline will wreck some images + set img [join [lines_as_list -block trimtail [ansicat $filepath]] \n] lappend pics [tcl::dict::create filename $f pic $img status ok] } } @@ -582,30 +605,73 @@ tcl::namespace::eval punk::ansi { set termsize [punk::console:::get_size] set margin 4 set freewidth [expr {[tcl::dict::get $termsize columns]-$margin}] - set per_row [expr {$freewidth / 80}] - - set rowlist [list] - set row [list] - set i 1 + set per_row [expr {$freewidth / $colwidth}] + + set rowlist [list] ;# { { } { } } + set heightlist [list] ;# { { } { } } + set maxheights [list] ;# { } + set row [list] ;#wip row + set rowh [list] ;#wip row img heights + set i 1 ;#track image index of whole pics list + set rowindex 0 foreach picinfo $pics { set subtitle "" if {[tcl::dict::get $picinfo status] ne "ok"} { set subtitle [tcl::dict::get $picinfo status] } set title [tcl::dict::get $picinfo filename] - lappend row [textblock::frame -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + set fr [textblock::frame -width $colwidth -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + # -- --- --- --- + #we need the max height of a row element to use join_basic instead of join below + # -- --- --- --- + set fr_height [textblock::height $fr] + lappend row $fr + lappend rowh $fr_height + + set rowmax [lindex $maxheights $rowindex] + if {$rowmax eq ""} { + #empty result means no maxheights entry for this row yet + set rowmax $fr_height + lappend maxheights $rowmax + } else { + if {$fr_height > $rowmax} { + set rowmax $fr_height + lset maxheights end $rowmax + } + } + # -- --- --- --- + if {$i % $per_row == 0} { lappend rowlist $row + lappend heightlist $rowh + incr rowindex set row [list] + set rowh [list] } elseif {$i == [llength $pics]} { lappend rowlist $row + lappend heightlist $rowh } incr i } - + #puts "--> maxheights: $maxheights" + #puts "--> heightlist: $heightlist" set result "" - foreach r $rowlist { - append result [textblock::join_basic -- {*}$r] \n + set rowindex 0 + set blankline [string repeat " " $colwidth] + foreach imgs $rowlist heights $heightlist { + set maxheight [lindex $maxheights $rowindex] + set adjusted_row [list] + foreach i $imgs h $heights { + if {$h < $maxheight} { + #add blank lines to bottom of shorter images so join_basic can be used. + #textblock::join of ragged-height images would work and remove the need for all the height calculation + #.. but it requires much more processing + append i [string repeat \n$blankline [expr {$maxheight - $h}]] + } + lappend adjusted_row $i + } + append result [textblock::join_basic -- {*}$adjusted_row] \n + incr rowindex } @@ -3199,6 +3265,28 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu return \x1b8 } # -- --- --- --- --- + #CRM Show Control Character Mode + proc enable_crm {} { + return \x1b\[3h + } + proc disable_crm {} { + return \x1b\[3l + } + + #DECSNM + #Note this can invert the enclosed section including any already reversed by SGR 7 - depending on terminal support. + #e.g + #set test [a+ reverse]aaa[a+ noreverse]bbb + # - $test above can't just be reversed by putting another [a+ reverse] in front of it. + # - but the following will work (even if underlying terminal doesn't support ?5 sequences) + #overtype::renderspace -width 20 [enable_inverse]$test + proc enable_inverse {} { + return \x1b\[?5h + } + proc disable_inverse {} { + return \x1b\[?5l + } + #DECAWM - automatic line wrapping proc enable_line_wrap {} { @@ -3399,6 +3487,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu #the purpose of backspace (or line cr) in embedded text is unclear. Should it allow some sort of character combining/overstrike as it has sometimes done historically (nroff/less)? e.g a\b` as an alternative combiner or bolding if same char #This should presumably only be done if the over_strike (os) capability is enabled in the terminal. Either way - it presumably won't affect printing width? set line [punk::ansi::ansistrip $line] + #ANSI (e.g PM/SOS) can contain \b or \n or \t but won't contribute to length + #ansistrip must come before any other processing of these chars. + #we can't use simple \b processing if we get ansi codes and aren't actually processing them (e.g moves) set line [punk::char::strip_nonprinting_ascii $line] ;#only strip nonprinting after ansistrip - some like BEL are part of ansi @@ -3748,6 +3839,7 @@ tcl::namespace::eval punk::ansi { -filter_fg 0\ -filter_bg 0\ -filter_reset 0\ + -info 0\ ] #codes *must* already have been split so that one esc per element in codelist @@ -3760,7 +3852,8 @@ tcl::namespace::eval punk::ansi { set opts $defaultopts_sgr_merge_singles foreach {k v} $args { switch -- $k { - -filter_fg - -filter_bg - -filter_reset { + -filter_fg - -filter_bg - -filter_reset - + -info { tcl::dict::set opts $k $v } default { @@ -4139,19 +4232,24 @@ tcl::namespace::eval punk::ansi { set codemerge [tcl::string::trimright $codemerge {;}] if {$unmergeable ne ""} { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" } else { - return "\x1b\[${codemerge}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m[join $othercodes ""]" } } else { if {$unmergeable eq ""} { #there were no SGR codes - not even resets - return [join $othercodes ""] + set mergeresult [join $othercodes ""] } else { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${unmergeable}m[join $othercodes ""]" } } + if {[tcl::dict::get $opts -info]} { + return [dict create sgr $codemerge unmergeable $unmergeable othercodes $othercodes mergeresult $mergeresult codestate $codestate] + } else { + return $mergeresult + } } #has_sgr_reset - rather than support this function - create an sgr normalize function that removes dead params and brings reset to front of param list? @@ -4240,7 +4338,7 @@ tcl::namespace::eval punk::ansi::ta { #we also need to track the start of ST terminated code and not add it for replay (in the ansistring functions) #variable re_ST {(?:\x1bX|\u0098|\x1b\^|\u009E|\x1b_|\u009F)(?:[^\x1b\007\u009c]*)(?:\x1b\\|\007|\u009c)} ;#downsides: early terminating with nests, mixes 7bit 8bit start/ends (does that exist in the wild?) #keep our 8bit/7bit start-end codes separate - variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} + variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} @@ -4252,7 +4350,7 @@ tcl::namespace::eval punk::ansi::ta { # -- --- --- --- #handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regext TRIE generator that works with Tcl regexes #This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone. - variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} + variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} # -- --- --- --- @@ -5674,7 +5772,12 @@ tcl::namespace::eval punk::ansi::ansistring { ENQ [list \x05 \u2405]\ ACK [list \x06 \u2406]\ BEL [list \x07 \u2407]\ + BS [list \x08 \u2408]\ + HT [list \x09 \u2409]\ + LF [list \x0a \u240a]\ + VT [list \x0b \u240b]\ FF [list \x0c \u240c]\ + CR [list \x0d \u240d]\ SO [list \x0e \u240e]\ SF [list \x0f \u240f]\ DLE [list \x10 \u2410]\ @@ -5688,12 +5791,15 @@ tcl::namespace::eval punk::ansi::ansistring { CAN [list \x18 \u2418]\ EM [list \x19 \u2419]\ SUB [list \x1a \u241a]\ + ESC [list \x1b \u241b]\ FS [list \x1c \u241c]\ GS [list \x1d \u241d]\ RS [list \x1e \u241e]\ US [list \x1f \u241f]\ + SP [list \x20 \u2420]\ DEL [list \x7f \u2421]\ ] + #alternate symbols for space # \u2422 Blank Symbol (b with forwardslash overly) # \u2423 Open Box (square bracket facing up like a tray/box) @@ -5836,6 +5942,7 @@ tcl::namespace::eval punk::ansi::ansistring { -cr 1\ -lf 0\ -vt 0\ + -ff 1\ -ht 1\ -bs 1\ -sp 1\ @@ -5850,16 +5957,22 @@ tcl::namespace::eval punk::ansi::ansistring { set opt_cr [tcl::dict::get $opts -cr] set opt_lf [tcl::dict::get $opts -lf] set opt_vt [tcl::dict::get $opts -vt] + set opt_ff [tcl::dict::get $opts -ff] set opt_ht [tcl::dict::get $opts -ht] set opt_bs [tcl::dict::get $opts -bs] set opt_sp [tcl::dict::get $opts -sp] # -- --- --- --- --- + # -lf 2, -vt 2 and -ff 2 are useful for CRM mode (Show Control Character Mode) in the terminal - where a newline is expected to display after the character. set visuals_opt $debug_visuals + set visuals_opt [dict remove $visuals_opt CR ESC LF VT FF HT BS SP] + if {$opt_esc} { tcl::dict::set visuals_opt ESC [list \x1b \u241b] + } else { + tcl::dict::unset visuals_opt ESC } if {$opt_cr} { tcl::dict::set visuals_opt CR [list \x0d \u240d] @@ -5870,9 +5983,20 @@ tcl::namespace::eval punk::ansi::ansistring { if {$opt_lf == 2} { tcl::dict::set visuals_opt LF [list \x0a \u240a\n] } - if {$opt_vt} { + if {$opt_vt == 1} { tcl::dict::set visuals_opt VT [list \x0b \u240b] } + if {$opt_vt == 2} { + tcl::dict::set visuals_opt VT [list \x0b \u240b\n] + } + switch -exact -- $opt_ff { + 1 { + tcl::dict::set visuals_opt FF [list \x0c \u240c] + } + 2 { + tcl::dict::set visuals_opt FF [list \x0c \u240c\n] + } + } if {$opt_ht} { tcl::dict::set visuals_opt HT [list \x09 \u2409] } diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/char-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/char-0.1.0.tm index ed4b22e4..e47ba051 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/char-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/char-0.1.0.tm @@ -552,13 +552,26 @@ tcl::namespace::eval punk::char { string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] } } else { + #review - use -profile? proc encodable "s {enc [encoding system]}" { set encname [encname $enc] - string eq $s [encoding convertfrom $encname [encoding convertto $encname $s]] + if {![catch { + string eq $s [encoding convertfrom $encname [encoding convertto $encname $s]] + } result]} { + return $result + } else { + return 0 + } } proc decodable "s {enc [encoding system]}" { set encname [encname $enc] - string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] + if {![catch { + string eq $s [encoding convertto $encname [encoding convertfrom $encname $s]] + } result]} { + return $result + } else { + return 0 + } } } #-- --- --- --- --- --- --- --- diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/console-0.1.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/console-0.1.1.tm index 3c64c7e3..6368aeae 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/console-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/console-0.1.1.tm @@ -13,11 +13,51 @@ # @@ Meta End +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_punk::console 0 0.1.1] +#[copyright "2024"] +#[titledesc {punk console}] [comment {-- Name section and table of contents description --}] +#[moddesc {punk console}] [comment {-- Description at end of page heading --}] +#[require punk::console] +#[keywords module console terminal] +#[description] +#[para] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section Overview] +#[para] overview of punk::console +#[subsection Concepts] +#[para] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements -##e.g package require frobz +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by punk::console +#[list_begin itemized] + +package require Tcl 8.6- package require punk::ansi +#*** !doctools +#[item] [package {Tcl 8.6-}] +#[item] [package {punk::ansi}] + + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + #if {"windows" eq $::tcl_platform(platform)} { @@ -30,6 +70,13 @@ package require punk::ansi # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval punk::console { + #*** !doctools + #[subsection {Namespace punk::console}] + #[para] + + #*** !doctools + #[list_begin definitions] + variable tabwidth 8 ;#default only - will attempt to detect and set to that configured in terminal #Note that windows terminal cooked mode seems to use 8 for interactive use even if set differently #e.g typing tab characters may still be echoed 8-spaced while writing to stdout my obey the terminal's tab stops. @@ -1028,23 +1075,37 @@ namespace eval punk::console { return [split [get_cursor_pos $inoutchannels] ";"] } - #todo - determine cursor on/off state before the call to restore properly. May only be possible + #todo - determine cursor on/off state before the call to restore properly. proc get_size {{inoutchannels {stdin stdout}}} { lassign $inoutchannels in out #we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810 #chan eof is faster whether chan exists or not than - if {[catch {chan eof $in} is_eof]} { - error "punk::console::get_size input channel $in seems to be closed ([info level 1])" + if {[catch {chan eof $out} is_eof]} { + error "punk::console::get_size output channel $out seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on input channel $in ([info level 1])" + error "punk::console::get_size eof on output channel $out ([info level 1])" } } - if {[catch {chan eof $out} is_eof]} { - error "punk::console::get_size output channel $out seems to be closed ([info level 1])" + #we don't need to care about the input channel if chan configure on the output can give us the info. + #short circuit ansi cursor movement method if chan configure supports the -winsize value + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + #this mechanism is much faster than ansi cursor movements + #REVIEW check if any x-platform anomalies with this method? + #can -winsize key exist but contain erroneous info? We will check that we get 2 ints at least + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + #continue on to ansi mechanism if we didn't get 2 ints + } + + if {[catch {chan eof $in} is_eof]} { + error "punk::console::get_size input channel $in seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on output channel $out ([info level 1])" + error "punk::console::get_size eof on input channel $in ([info level 1])" } } @@ -1067,18 +1128,28 @@ namespace eval punk::console { } } - #faster - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore - proc get_size_cursorrestore {} { + #faster than get_size when it is using ansi mechanism - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore + proc get_size_cursorrestore {{inoutchannels {stdin stdout}}} { + lassign $inoutchannels in out + #we use the same shortcircuit mechanism as get_size to avoid ansi at all if the output channel will give us the info directly + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + } + if {[catch { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. - puts -nonewline [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] - lassign [get_cursor_pos_list] lines cols - puts -nonewline [punk::ansi::cursor_restore][punk::console::cursor_on];flush stdout + puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] + lassign [get_cursor_pos_list $inoutchannels] lines cols + puts -nonewline $out [punk::ansi::cursor_restore][punk::console::cursor_on];flush $out set result [list columns $cols rows $lines] } errM]} { - puts -nonewline [punk::ansi::cursor_restore_dec] - puts -nonewline [punk::ansi::cursor_on] + puts -nonewline $out [punk::ansi::cursor_restore_dec] + puts -nonewline $out [punk::ansi::cursor_on] error "$errM" } else { return $result @@ -1803,6 +1874,9 @@ namespace eval punk::console { } #run the test and allow warnings to be emitted to stderr on package load. User should know the terminal and/or Tcl version are not optimal for unicode character work #set testresult [test1] + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::console ---}] } @@ -1825,4 +1899,7 @@ package provide punk::console [namespace eval punk::console { variable version set version 0.1.1 }] -return \ No newline at end of file +return + +#*** !doctools +#[manpage_end] diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/du-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/du-0.1.0.tm index f0e96a28..1eca1f47 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/du-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/du-0.1.0.tm @@ -967,7 +967,7 @@ namespace eval punk::du { dict set effective_opts -with_times $timed_types dict set effective_opts -with_sizes $sized_types - return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors] + return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden $flaggedhidden flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors] } #zipfs attributes/behaviour fairly different to tclvfs - keep separate diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm index cb786f22..63f32dee 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/lib-0.1.1.tm @@ -328,7 +328,17 @@ tcl::namespace::eval punk::lib::compat { # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval punk::lib { tcl::namespace::export * - #variable xyz + variable has_struct_list + set has_struct_list [expr {![catch {package require struct::list}]}] + variable has_struct_set + set has_struct_set [expr {![catch {package require struct::set}]}] + variable has_punk_ansi + set has_punk_ansi [expr {![catch {package require punk::ansi}]}] + set has_twapi 0 + if {"windows" eq $::tcl_platform(platform)} { + set has_twapi [expr {![catch {package require twapi}]}] + } + #*** !doctools #[subsection {Namespace punk::lib}] @@ -614,7 +624,9 @@ namespace eval punk::lib { } proc pdict {args} { - if {[catch {package require punk::ansi} errM]} { + package require punk::args + variable has_punk_ansi + if {!$has_punk_ansi} { set sep " = " } else { #set sep " [a+ Web-seagreen]=[a] " @@ -691,14 +703,15 @@ namespace eval punk::lib { # - Copy proc and attempt rework so we can get back to this as a baseline for functionality proc showdict {args} { ;# analogous to parray (except that it takes the dict as a value) #set sep " [a+ Web-seagreen]=[a] " - if {[catch {package require punk::ansi} errM]} { - set sep " = " + variable has_punk_ansi + if {!$has_punk_ansi} { set RST "" + set sep " = " set sep_mismatch " mismatch " } else { - set sep " [punk::ansi::a+ Green]=[punk::ansi::a] " ;#stick to basic default colours for wider terminal support set RST [punk::ansi::a] - set sep_mismatch " [punk::ansi::a+ Brightred undercurly underline undt-white]mismatch[punk::ansi::a] " + set sep " [punk::ansi::a+ Green]=$RST " ;#stick to basic default colours for wider terminal support + set sep_mismatch " [punk::ansi::a+ Brightred undercurly underline undt-white]mismatch$RST " } package require punk ;#we need pipeline pattern matching features package require textblock @@ -836,7 +849,7 @@ namespace eval punk::lib { lappend keyset_structure dict } @* { - puts ---->HERE<---- + #puts "showdict ---->@*<----" dict set pattern_this_structure $p list set keys [punk::lib::range 0 [llength $dval]-1] lappend keyset {*}$keys @@ -1405,16 +1418,29 @@ namespace eval punk::lib { } proc is_list_all_in_list {small large} { - package require struct::list - package require struct::set set small_in_large [lsort [struct::set intersect [lsort -unique $small] $large ]] return [struct::list equal [lsort $small] $small_in_large] } + if {!$has_struct_list || !$has_struct_set} { + set body { + package require struct::list + package require struct::set + } + append body [info body is_list_all_in_list] + proc is_list_all_in_list {small large} $body + } + proc is_list_all_ni_list {a b} { - package require struct::set set i [struct::set intersect $a $b] return [expr {[llength $i] == 0}] } + if {!$has_struct_set} { + set body { + package require struct::list + } + append body [info body is_list_all_ni_list] + proc is_list_all_ni_list {a b} $body + } #somewhat like struct::set difference - but order preserving, and doesn't treat as a 'set' so preserves dupes in fromlist #struct::set difference may happen to preserve ordering when items are integers, but order can't be relied on, @@ -1465,18 +1491,22 @@ namespace eval punk::lib { return [array names tmp] } - package require struct::set - if {[struct::set equal [struct::set union {a a} {}] {a}]} { - proc lunique_unordered {list} { - struct::set union $list {} - } - } else { - puts stderr "WARNING: struct::set union no longer dedupes!" - #we could also test a sequence of: struct::set add - proc lunique_unordered {list} { - tailcall lunique $list + #default/fallback implementation + proc lunique_unordered {list} { + lunique $list + } + if {$has_struct_set} { + if {[struct::set equal [struct::set union {a a} {}] {a}]} { + proc lunique_unordered {list} { + struct::set union $list {} + } + } else { + puts stderr "WARNING: struct::set union no longer dedupes!" + #we could also test a sequence of: struct::set add } } + + #order-preserving proc lunique {list} { set new {} @@ -1863,14 +1893,14 @@ namespace eval punk::lib { set opt_empty [tcl::dict::get $opts -empty_as_hex] # -- --- --- --- - set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map [list _ ""] [string trim $h]}] + set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map {_ ""} [string trim $h]}] if {$opt_validate} { #Note appended F so that we accept list of empty strings as per the documentation if {![string is xdigit -strict [join $list_largeHex ""]F ]} { error "[namespace current]::hex2dec error: non-hex digits encountered after stripping underscores and leading/trailing whitespace for each element\n $list_largeHex" } } - if {![string is xdigit -strict [string map [list _ ""] $opt_empty]]} { + if {![string is xdigit -strict [string map {_ ""} $opt_empty]]} { #mapping empty string to a value destroys any advantage of -scanonly #todo - document that -scanonly has 2 restrictions - each element must be valid hex and less than 7 chars long #set list_largeHex [lmap v $list_largeHex[set list_largeHex {}] {expr {$v eq ""} ? {0} : {[set v]}}] @@ -1878,7 +1908,7 @@ namespace eval punk::lib { error "[namespace current]::hex2dec error: empty values in list cannot be mapped to non-hex $opt_empty" } } else { - set opt_empty [string trim [string map [list _ ""] $opt_empty]] + set opt_empty [string trim [string map {_ ""} $opt_empty]] if {[set first_empty [lsearch $list_largeHex ""]] >= 0} { #set list_largeHex [lmap v $list_largeHex[set list_largeHex {}] {expr {$v eq ""} ? {$opt_empty} : {$v}}] set nonempty_head [lrange $list_largeHex 0 $first_empty-1] @@ -1931,13 +1961,13 @@ namespace eval punk::lib { } set fmt "%${opt_width}.${opt_width}ll${spec}" - set list_decimals [lmap d $list_decimals[unset list_decimals] {string map [list _ ""] [string trim $d]}] - if {![string is digit -strict [string map [list _ ""] $opt_empty]]} { + set list_decimals [lmap d $list_decimals[unset list_decimals] {string map {_ ""} [string trim $d]}] + if {![string is digit -strict [string map {_ ""} $opt_empty]]} { if {[lsearch $list_decimals ""] >=0} { error "[namespace current]::dec2hex error: empty values in list cannot be mapped to non-decimal $opt_empty" } } else { - set opt_empty [string map [list _ ""] $opt_empty] + set opt_empty [string map {_ ""} $opt_empty] if {[set first_empty [lsearch $list_decimals ""]] >= 0} { set nonempty_head [lrange $list_decimals 0 $first_empty-1] set list_decimals [concat $nonempty_head [lmap v [lrange $list_decimals $first_empty end] {expr {$v eq ""} ? {$opt_empty} : {$v}}]] @@ -2402,13 +2432,14 @@ namespace eval punk::lib { # important for pipeline & match_assign # -line trimline|trimleft|trimright -block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty -commandprefix {string length} ? # -block trimming only trims completely empty lines. use -line trimming to remove whitespace e.g -line trimright will clear empty lines without affecting leading whitespace on other lines that aren't pure whitespace - proc linelist {args} { + + set linelist_body { set usage "linelist ?-line trimline|trimleft|trimright? ?-block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty? -commandprefix text" if {[llength $args] == 0} { error "linelist missing textchunk argument usage:$usage" } set text [lindex $args end] - set text [string map [list \r\n \n] $text] ;#review - option? + set text [string map {\r\n \n} $text] ;#review - option? set arglist [lrange $args 0 end-1] set opts [tcl::dict::create\ @@ -2441,10 +2472,10 @@ namespace eval punk::lib { } } #normalize certain combos - if {[set posn [lsearch $opt_block trimhead1]] >=0 && "trimhead" in $opt_block} { + if {"trimhead" in $opt_block && [set posn [lsearch $opt_block trimhead1]] >=0} { set opt_block [lreplace $opt_block $posn $posn] } - if {[set posn [lsearch $opt_block trimtail1]] >=0 && "trimtail" in $opt_block} { + if {"trimtail" in $opt_block && [set posn [lsearch $opt_block trimtail1]] >=0} { set opt_block [lreplace $opt_block $posn $posn] } if {"trimall" in $opt_block} { @@ -2594,9 +2625,10 @@ namespace eval punk::lib { #Each resulting line should have a reset of some type at start and a pure-reset at end to stop #see if we can find an ST sequence that most terminals will not display for marking sections? if {$opt_ansireplays} { - package require punk::ansi + #package require punk::ansi + if {$opt_ansiresets} { - set RST [punk::ansi::a] + set RST "\x1b\[0m" } else { set RST "" } @@ -2721,6 +2753,15 @@ namespace eval punk::lib { return $linelist } + if {$has_punk_ansi} { + #optimise linelist as much as possible + set linelist_body [string map { ""} $linelist_body] + } else { + #punk ansi not avail at time of package load. + #by putting in calls to punk::ansi the user will get appropriate error messages + set linelist_body [string map { "package require punk::ansi"} $linelist_body] + } + proc linelist {args} $linelist_body interp alias {} errortime {} punk::lib::errortime @@ -2846,6 +2887,133 @@ namespace eval punk::lib { proc temperature_c_to_f {deg_celsius} { return [expr {($deg_celsius * (9/5.0)) + 32}] } + + proc interp_sync_package_paths {interp} { + if {![interp exists $interp]} { + error "interp_sync_package_paths error. interp '$interp' not found. Create it first with \[interp create $interp\]" + } + interp eval $interp [list set ::auto_path $::auto_path] + interp eval $interp {tcl::tm::remove {*}[tcl::tm::list]} + interp eval $interp [list tcl::tm::add {*}[lreverse [tcl::tm::list]]] + } + + proc objclone {obj} { + append obj2 $obj {} + } + + + + proc format_number {numbers_or_commaformattednumbers {delim ""} {groupsize ""}} { + variable has_twapi + if {$has_twapi} { + if {$delim eq "" && $groupsize eq ""} { + set localeid [twapi::get_system_default_lcid] + } + } + + set results [list] + set nums [objclone $numbers_or_commaformattednumbers] ;#stops single num from getting internal rep of list + foreach inputnum $nums { + set number [objclone $inputnum] + #also handle tcl 8.7+ underscores in numbers + set number [string map [list _ "" , ""] $number] + #normalize e.g 2e4 -> 20000.0 + set number [expr {$number}] + + if {$has_twapi} { + if {$delim eq "" && $groupsize eq ""} { + lappend results [twapi::format_number $number $localeid -idigits -1] + continue + } else { + if {$delim eq ""} {set delim ","} + if {$groupsize eq ""} {set groupsize 3} + lappend results [twapi::format_number $number 0 -idigits -1 -sthousand $delim -sgrouping $groupsize] + continue + } + } + #todo - get configured user defaults + set delim "," + set groupsize 3 + + lappend results [delimit_number $number $delim $groupsize] + } + + if {[llength $results] == 1} { + #keep intrep as string rather than list + return [lindex $results 0] + } + return $results + } + + + #from wiki https://wiki.tcl-lang.org/page/Delimiting+Numberse + # Given a number represented as a string, insert delimiters to break it up for + # readability. Normally, the delimiter will be a comma which will be inserted every + # three digits. However, the delimiter and groupsize are optional arguments, + # permitting use in other locales. + # + # The string is assumed to consist of digits, possibly preceded by spaces, + # and possibly containing a decimal point, i.e.: [:space:]*[:digit:]*\.[:digit:]* + + proc delimit_number {unformattednumber {delim ","} {GroupSize 3}} { + set number [punk::objclone $unformattednumber] + set number [string map {_ ""} $number] + #normalize using expr - e.g 2e4 -> 20000.0 + set number [expr {$number}] + # First, extract right hand part of number, up to and including decimal point + set point [string last "." $number]; + if {$point >= 0} { + set PostDecimal [string range $number [expr $point + 1] end]; + set PostDecimalP 1; + } else { + set point [expr [string length $number] + 1] + set PostDecimal ""; + set PostDecimalP 0; + } + + # Now extract any leading spaces. review - regex for whitespace instead of just ascii space? + set ind 0; + while {[string equal [string index $number $ind] \u0020]} { + incr ind; + } + set FirstNonSpace $ind; + set LastSpace [expr $FirstNonSpace - 1]; + set LeadingSpaces [string range $number 0 $LastSpace]; + + # Now extract the non-fractional part of the number, omitting leading spaces. + set MainNumber [string range $number $FirstNonSpace [expr $point -1]]; + + # Insert commas into the non-fractional part. + set Length [string length $MainNumber]; + set Phase [expr $Length % $GroupSize] + set PhaseMinusOne [expr $Phase -1]; + set DelimitedMain ""; + + #First we deal with the extra stuff. + if {$Phase > 0} { + append DelimitedMain [string range $MainNumber 0 $PhaseMinusOne]; + } + set FirstInGroup $Phase; + set LastInGroup [expr $FirstInGroup + $GroupSize -1]; + while {$LastInGroup < $Length} { + if {$FirstInGroup > 0} { + append DelimitedMain $delim; + } + append DelimitedMain [string range $MainNumber $FirstInGroup $LastInGroup]; + incr FirstInGroup $GroupSize + incr LastInGroup $GroupSize + } + + # Reassemble the number. + if {$PostDecimalP} { + return [format "%s%s.%s" $LeadingSpaces $DelimitedMain $PostDecimal]; + } else { + return [format "%s%s" $LeadingSpaces $DelimitedMain]; + } + } + + + #*** !doctools #[list_end] [comment {--- end definitions namespace punk::lib ---}] } @@ -2998,7 +3166,9 @@ tcl::namespace::eval punk::lib::system { return [concat $smallfactors [lreverse $largefactors] $x] } - # incomplte - report which is the innermost bracket/quote etc awaiting completion for a Tcl command + + + # incomplete - report which is the innermost bracket/quote etc awaiting completion for a Tcl command #important - used by punk::repl proc incomplete {partial} { #we can apparently get away without concatenating current innerpartial to previous in list - REVIEW. diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm index 1e90b5ca..932c1db6 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/base-0.1.tm @@ -35,12 +35,14 @@ namespace eval punk::mix::base { } #puts stderr "punk::mix::base extension: [string trimleft $extension :]" if {![string length $extension]} { - #if still no extension - must have been called dirctly as punk::mix::base::_cli + #if still no extension - must have been called directly as punk::mix::base::_cli if {![llength $args]} { set args "help" } set extension [namespace current] } + #init usually used to load commandsets (and export their names) into the extension namespace/ensemble + ${extension}::_init if {![llength $args]} { if {[info exists ${extension}::default_command]} { tailcall $extension [set ${extension}::default_command] diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm index 5b1ec6da..cd6f3025 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/cli-0.3.1.tm @@ -31,47 +31,58 @@ namespace eval punk::mix::cli { namespace eval temp_import { } namespace ensemble create + variable initialised 0 - package require punk::overlay - catch { - punk::overlay::import_commandset module . ::punk::mix::commandset::module - } - punk::overlay::import_commandset debug . ::punk::mix::commandset::debug - punk::overlay::import_commandset repo . ::punk::mix::commandset::repo - punk::overlay::import_commandset lib . ::punk::mix::commandset::loadedlib - - catch { - package require punk::mix::commandset::project - punk::overlay::import_commandset project . ::punk::mix::commandset::project - punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection - } - if {[catch { - package require punk::mix::commandset::layout - punk::overlay::import_commandset project.layout . ::punk::mix::commandset::layout - punk::overlay::import_commandset project.layouts . ::punk::mix::commandset::layout::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::layout" - puts stderr $errM - } - if {[catch { - package require punk::mix::commandset::buildsuite - punk::overlay::import_commandset buildsuite . ::punk::mix::commandset::buildsuite - punk::overlay::import_commandset buildsuites . ::punk::mix::commandset::buildsuite::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::buildsuite" - puts stderr $errM - } - punk::overlay::import_commandset scriptwrap . ::punk::mix::commandset::scriptwrap - if {[catch { - package require punk::mix::commandset::doc - punk::overlay::import_commandset doc . ::punk::mix::commandset::doc - punk::overlay::import_commandset "" "" ::punk::mix::commandset::doc::collection - } errM]} { - puts stderr "error loading punk::mix::commandset::doc" - puts stderr $errM + #lazy _init - called by punk::mix::base::_cli when ensemble used + proc _init {args} { + variable initialised + if {$initialised} { + return + } + puts stderr "punk::mix::cli::init $args" + package require punk::overlay + namespace eval ::punk::mix::cli { + catch { + punk::overlay::import_commandset module . ::punk::mix::commandset::module + } + punk::overlay::import_commandset debug . ::punk::mix::commandset::debug + punk::overlay::import_commandset repo . ::punk::mix::commandset::repo + punk::overlay::import_commandset lib . ::punk::mix::commandset::loadedlib + + catch { + package require punk::mix::commandset::project + punk::overlay::import_commandset project . ::punk::mix::commandset::project + punk::overlay::import_commandset projects . ::punk::mix::commandset::project::collection + } + if {[catch { + package require punk::mix::commandset::layout + punk::overlay::import_commandset project.layout . ::punk::mix::commandset::layout + punk::overlay::import_commandset project.layouts . ::punk::mix::commandset::layout::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::layout" + puts stderr $errM + } + if {[catch { + package require punk::mix::commandset::buildsuite + punk::overlay::import_commandset buildsuite . ::punk::mix::commandset::buildsuite + punk::overlay::import_commandset buildsuites . ::punk::mix::commandset::buildsuite::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::buildsuite" + puts stderr $errM + } + punk::overlay::import_commandset scriptwrap . ::punk::mix::commandset::scriptwrap + if {[catch { + package require punk::mix::commandset::doc + punk::overlay::import_commandset doc . ::punk::mix::commandset::doc + punk::overlay::import_commandset "" "" ::punk::mix::commandset::doc::collection + } errM]} { + puts stderr "error loading punk::mix::commandset::doc" + puts stderr $errM + } + } + set initialised 1 } - proc help {args} { #set basehelp [punk::mix::base::help -extension [namespace current] {*}$args] set basehelp [punk::mix::base help {*}$args] @@ -210,11 +221,12 @@ namespace eval punk::mix::cli { proc validate_modulename {modulename args} { set opts [list\ -errorprefix validate_modulename\ + -strict 0\ ] if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} foreach {k v} $args { switch -- $k { - -errorprefix { + -errorprefix - -strict { dict set opts $k $v } default { @@ -223,8 +235,14 @@ namespace eval punk::mix::cli { } } # -- --- --- --- --- --- --- --- --- --- --- --- --- --- - set opt_errorprefix [dict get $opts -errorprefix] + set opt_errorprefix [dict get $opts -errorprefix] + set opt_strict [dict get $opts -strict] # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + if {$opt_strict} { + if {[regexp {[A-Z]} $modulename]} { + error "$opt_errorprefix '$modulename' contains uppercase which is not recommended as per tip 590, and option -strict is set to 1" + } + } validate_name_not_empty_or_spaced $modulename -errorprefix $opt_errorprefix set testname [string map {:: {}} $modulename] @@ -239,6 +257,56 @@ namespace eval punk::mix::cli { } return $modulename } + proc confirm_modulename {modulename} { + set finalised 0 + set aborted 0 + while {!$finalised && !$aborted} { + #first validate with -strict 0 to confirm acceptable while ignoring case issues. + #uppercase is generally valid but not recommended - so has separate prompting. + if {[catch {validate_modulename $modulename -strict 0} errM]} { + set msg "Chosen name didn't pass validation\n" + append msg "reason: $errM\n" + append msg "Please retype the modulename. You will be given a further prompt to confirm or abort." + set modulename [util::askuser $msg] + } elseif {[regexp {[A-Z]} $modulename]} { + set msg "module names containing uppercase are not recommended (see tip 590).\n" + append msg "Please retype the module name '$modulename' to proceed.\n" + append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" + append msg "Retype it all in lowercase to use recommended naming" + set answer [util::askuser $msg] + if {[regexp {[A-Z]} $answer]} { + if {$answer eq $modulename} { + #ok - user insists + set finalised 1 + } else { + #user supplied a different uppercase name - don't set finalised so we bug them again to type it two times the same way to proceed + puts stdout "A different uppercase name was supplied - reconfirmation required." + } + set modulename $answer + } else { + #user has resupplied modulename all as lowercase + if {$answer eq [string tolower $modulename]} { + set finalised 1 + } else { + #.. but it doesn't match original - require rerun + } + set modulename $answer + } + } else { + set answer [util::askuser "Proceed with the module name '$modulename'? Y to continue N to abort"] + if {[string tolower $answer] eq "y"} { + set finalised 1 + } else { + set aborted 1 + } + } + } + if {$aborted} { + return [dict create status error reason errmsg] + } else { + return [dict create status ok modulename $modulename] + } + } proc validate_projectname {projectname args} { set defaults [list\ diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm index fafc3cec..856c9340 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm @@ -165,7 +165,17 @@ namespace eval punk::mix::commandset::doc { cd $original_wd } - proc validate {} { + proc validate {args} { + set argd [punk::args::get_dict { + -- -type none -optional 1 -help "end of options marker --" + -individual -type boolean -default 1 + *values -min 0 -max -1 + patterns -default {*} -type any -multiple 1 + } $args] + set opt_individual [tcl::dict::get $argd opts -individual] + set patterns [tcl::dict::get $argd values patterns] + + #todo - run and validate punk::docgen output set projectdir [punk::repo::find_project] if {$projectdir eq ""} { @@ -180,7 +190,23 @@ namespace eval punk::mix::commandset::doc { set docroot $projectdir/src/doc cd $docroot - dtplite validate $docroot + if {!$opt_individual && "*" in $patterns} { + if {[catch { + dtplite validate $docroot + } errM]} { + puts stderr "commandset::doc::validate failed for projectdir '$projectdir'" + puts stderr "docroot '$docroot'" + puts stderr "dtplite error was: $errM" + } + } else { + foreach p $patterns { + set treefiles [punk::path::treefilenames $p] + foreach path $treefiles { + puts stdout "dtplite validate $path" + dtplite validate $path + } + } + } #punk::mix::cli::lib::kettle_call lib validate-doc diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm index bd0b5358..08d103ee 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm @@ -179,7 +179,16 @@ namespace eval punk::mix::commandset::loadedlib { return [join $loaded_libs \n] } - proc info {libname} { + proc info {args} { + set argspecs { + *values -min 1 + libname -help "library/package name" + } + set argd [punk::args::get_dict $argspecs $args] + set libname [dict get $argd values libname] + + + if {[catch {package require natsort}]} { set has_natsort 0 } else { diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm index 9955c53b..029be3ce 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm @@ -204,6 +204,30 @@ namespace eval punk::mix::commandset::module { set modulename $module } punk::mix::cli::lib::validate_modulename $modulename -errorprefix "punk::mix::commandset::module::new" + + if {[regexp {[A-Z]} $module]} { + set msg "module names containing uppercase are not recommended (see tip 590).\n" + append msg "Please retype the module name '$module' to proceed.\n" + append msg "If you type it exactly as it was you will be allowed to proceed with uppercase anyway\n" + append msg "Retype it all in lowercase to use recommended naming" + set answer [util::askuser $msg] + if {[regexp {[A-Z]} $answer]} { + if {$answer eq $module} { + #ok - user insists + } else { + + } + } else { + #user has resupplied modulename all as lowercase + if {$answer eq [string tolower $module]} { + set module $answer + } else { + #.. but it doesn't match original - require rerun + } + } + } + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #options # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm index aa630d36..9afc685c 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm @@ -165,7 +165,7 @@ namespace eval punk::mix::commandset::project { #user can use dev module.new manually or supply module name in -modules set opt_modules [list] } else { - set opt_modules [list $projectname] + set opt_modules [list [string tolower $projectname]] ;#default modules to lowercase as is the modern (tip 590) recommendation for Tcl } } # -- --- --- --- --- --- --- --- --- --- --- --- --- @@ -919,10 +919,18 @@ namespace eval punk::mix::commandset::project { if {[llength $col_states]} { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes s $col_states { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode] [overtype::left $col6 $s]" \n } } else { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode]" \n } } diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/overlay-0.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/overlay-0.1.tm index 5534dad3..73b8ef39 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/overlay-0.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/overlay-0.1.tm @@ -130,6 +130,7 @@ tcl::namespace::eval ::punk::overlay { }] set imported_commands [list] + set imported_tails [list] set nscaller [uplevel 1 [list tcl::namespace::current]] if {[catch { #review - noclobber? @@ -143,7 +144,10 @@ tcl::namespace::eval ::punk::overlay { } rename $cmd $import_as lappend imported_commands $import_as + lappend imported_tails [namespace tail $import_as] } + #make imported commands exported so they are available to the ensemble + tcl::namespace::eval ${nscaller} [list namespace export {*}$imported_tails] } errM]} { puts stderr "Error loading commandset $prefix $separator $cmdnamespace" puts stderr "err: $errM" diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm index 933ef860..2165c0fd 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm @@ -63,11 +63,11 @@ package require Tcl 8.6- # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # oo::class namespace # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ -namespace eval punk::path::class { +#namespace eval punk::path::class { #*** !doctools #[subsection {Namespace punk::path::class}] #[para] class definitions - if {[info commands [namespace current]::interface_sample1] eq ""} { + #if {[info commands [namespace current]::interface_sample1] eq ""} { #*** !doctools #[list_begin enumerated] @@ -89,8 +89,8 @@ namespace eval punk::path::class { #*** !doctools #[list_end] [comment {--- end class enumeration ---}] - } -} + #} +#} # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ @@ -105,6 +105,448 @@ namespace eval punk::path { #[para] Core API functions for punk::path #[list_begin definitions] + # -- --- + #punk::path::normjoin + # - simplify . and .. segments as far as possible whilst respecting specific types of root. + # -- --- + #a form of file normalize that supports //xxx to be treated as server path names + #(ie regardless of unices ignoring (generally) leading double slashes, and regardless of windows volumerelative path syntax) + #(sometimes //server.com used as a short form for urls - which doesn't seem too incompatible with this anyway) + # -- --- + #This is intended to be purely a string analysis - without reference to filesystem volumes or vfs or zipfs mountpoints etc + # + #TODO - option for caller to provide a -base below which we can't backtrack. + #This is preferable to setting policy here for example regarding forcing no trackback below //servername/share + #Our default is to allow trackback to: + # :// + # :/ + # //./ (dos device volume) + # //server (while normalizing //./UNC/server to same) + # / (ordinary unix root) + # ./../ - (track back indefinitely on relpath as we are not resolving to anything physical and can't fully simplify the leading backtracks) + # + #The caller should do the file/vfs operations to determine this - not us. + # -- --- + #simplify path with respect to /./ & /../ elements - independent of platform + #NOTE: "anomalies" in standard tcl processing on windows: + #e.g file normalize {//host} -> c:/host (or e.g d:/host if we happen to be on another volume) + #file normalize {//host/share} -> //host/share + #This is because //host is treated as volume-relative in cmd/powershell and Tcl quite reasonably follows suit. + #This prevents cwd and windows commandlines from pointing to the server (above the share) + #Explorer however does allow pointing to the //server level and seeing shares as if they are directory entries. + #we are more interested in supporting the explorer-like behaviour - as while volumerelative paths are also useful on windows - they are lesser known. + #REVIEW. + #To get back to some consistent cross platform behaviour - we will treat //something as a root/volume i.e we can't backtrack above it with ".." + #note too that file split on UNC paths doesn't give a clear indication of the root + # file split //./UNC/server/share/subpath -> //./UNC server share subpath + # file split //server/share/subpath -> //server/share subpath + #TODO - disallow all change of root or change from relative path to absolute result. + #e.g normjoin relpath/../d:/secret should not return d:/secret - but ./d:/secret + # ================ + #known issues: + #1) + # normjoin d://a//b//c -> d://a/b/c + # This is because we don't detect specific schemes. ie it's treated the same as https://a/b/c -> https://a/b/c + # Not considered a problem - just potentially surprising. + # To avoid it we would have to enumerate possible schemes. + # As it stands a unix system could define a 'scheme' that happens to match windows style driveletters. Consider a 'feature' ? review. + # won't fix? + #2) + # normjoin https:///real.com/../fake.com -> https:///fake.com + # The extra slash means effectively our servername is empty - this is potentially confusing but probably the right thing to do here. + # It's a concern only if upstream treats the tripple slash in this case as valid and maps it to https:// - which would probably be bad anyway. + # won't fix (review) + #3) + #similarly + # normjoin //./UNC//server/share/subpath -> ///server/share/subpath (when 2 or more slashes directly after UNC) + # normjoin ///server/share -> ///server/share + #This is effectively an empty servername in the input with 'server' being pushed one level down - and the output is consistent + # possibly won't fix - review + #4) inconsistency + # we return normalized //server/share for //./UNC/server share + # but other dos device paths are maintained + # e.g //./c:/etc + # This is because such paths could contain alternate segment names (windows shortnames) which we aren't in a position to resolve. + # caller should + # #as with 'case' below - caller will need to run a post 'file normalize' + #5) we don't normalize case like file normalize does on windows platform. + # This is intentional. It could only be done with reference to underlying filesystem which we don't want here. + # + # ================ + # + #relpaths all end up with leading . - while not always the simplest form, this is ok. (helps stop inadvertent conversions to absolutes) + # Tests - TODO + # normjoin /d:/..//vfs:/test -> /vfs:/test (good - not converted to //vfs:/test) + proc normjoin {args} { + set args [lmap a $args {string map "\\\\ /" $a}] + set path [plainjoin {*}$args] + switch -exact $path { + "" { + return "" + } + / - // { + #treated in unixlike manner - (but leading doubleslashes with subsequent data are server indication) + #// not considered a servername indicator - but /// (for consistency) is. (empty servername?) + return / + } + /// { + #if this is effectively //$emptyservername/ + #then for consistency we should trail //=3 + #todo - shortcircuit that here? + } + } + # /// + set doubleslash1_posn [string first // $path] + + # -- --- --- temp warning on windows only - no x-platform difference in result + #on windows //host is of type volumerelative + # whereas //host/share is of type absolute + if {"windows" eq $::tcl_platform(platform) && [file pathtype $path] eq "volumerelative"} { + #volumerelative probably only occurs on windows anyway + if {$doubleslash1_posn == 0} { + #e.g //something where no further slashes + #review - eventually get rid of this warning and require upstream to know the appropriate usecase + puts stderr "Warning - ambiguous path $path - treating as server path - not 'volumerelative'" + } else { + # /something/etc + # /mnt/c/stuff + #output will retain leading / as if on unix. + #on windows - the result would still be interpreted as volumerelative if the caller normalizes it + } + } + # -- --- --- + + set is_relpath 0 + + #set path [string map [list \\ /] $path] + set finalparts [list] + set is_nonunc_dosdevice 0 + if {[punk::winpath::is_dos_device_path $path]} { + #review + if {[string range $path 4 6] eq "UNC"} { + #convert to 'standard' //server/... path for processing + set path "/[string range $path 7 end]" ;# //server/... + } else { + #error "normjoin non-UNC dos device path '$path' not supported" + #first segment after //./ or //?/ represents the volume or drive. + #not applicable to unix - but unlikely to conflict with a genuine usecase there (review) + #we should pass through and stop navigation below //./vol + #!!! + #not anomaly in tcl (continues in tcl9) + #file exists //./c:/test -> 0 + #file exists //?/c:/test -> 1 + #file exists //./BootPartition/Windows -> 1 + #file exists //?/BootPartition/Windows -> 0 + set is_nonunc_dosdevice 1 + } + } + + if {$is_nonunc_dosdevice} { + #dosdevice prefix //./ or //?/ - preserve it (without trailing slash which will be put back in with join) + set prefix [string range $path 0 2] + set tail [string range $path 4 end] + set tailparts [split $tail /] + set parts [concat [list $prefix] $tailparts] + set rootindex 1 ;#disallow backtrack below //./ + } else { + #note use of ordinary ::split vs file split is deliberate. + if {$doubleslash1_posn == 0} { + #this is handled differently on different platforms as far as 'file split' is concerned. + #e.g for file split //sharehost/share/path/etc + #e.g on windows: -> //sharehost/share path + #e.g on freebsd: -> / sharehost share path etc + #however..also on windows: file split //sharehost -> / sharehost + #normalize by dropping leading slash before split - and then treating first 2 segments as a root + #set parts [file split [string range $path 1 end]] + set parts [split $path /] + #assert parts here has {} {} as first 2 entries + set rootindex 2 + #currently prefer can backtrack to the //zipfs:/ scheme (below the mountpoint - to browse other mounts) + #alternative handling for //zipfs:/path - don't go below mountpoint + #but we can't determine just from string if mountpoint is direct subpath or a lower one e.g //zipfs:/arbitraryname/actualmountpoint + #review - more generally //:/path ? + #todo - make an option for zipfs and others to determine the 'base' + #if {"zipfs:" eq [lindex $parts 2]} { + # set rootindex 3 + #} + } else { + #path may or may not begin with a single slash here. + #treat same on unix and windows + set rootindex 0 + #set parts [file split $path] + set parts [::split $path /] + #e.g /a/b/c -> {} a b c + #or relative path a/b/c -> a b c + #or c:/a/b/c -> c: a b c + if {[string match *: [lindex $parts 0]]} { + if {[lindex $parts 1] eq ""} { + #scheme://x splits to scheme: {} x + set parts [concat [list [lindex $parts 0]/] [lrange $parts 2 end]] + #e.g {scheme:/ x} + set rootindex 1 ;#disallow below first element of scheme + } else { + set rootindex 0 + } + } elseif {[lindex $parts 0] ne ""} { + #relpath a/b/c + set parts [linsert $parts 0 .] + set rootindex 0 + #allow backtracking arbitrarily for leading .. entries - simplify where possible + #also need to stop possible conversion to absolute path + set is_relpath 1 + } + } + } + set baseparts [lrange $parts 0 $rootindex] ;#base below which we can't retreat via ".." + #puts stderr "-->baseparts:$baseparts" + #ensure that if our rootindex already spans a dotted segment (after the first one) we remove it + #must maintain initial . for relpaths to stop them converting to absolute via backtrack + # + set finalparts [list [lindex $baseparts 0]] + foreach b [lrange $baseparts 1 end] { + if {$b ni {. ..}} { + lappend finalparts $b + } + } + set baselen [expr {$rootindex + 1}] + if {$is_relpath} { + set i [expr {$rootindex+1}] + foreach p [lrange $parts $i end] { + switch -exact -- $p { + . - "" {} + .. { + switch -exact -- [lindex $finalparts end] { + . - .. { + lappend finalparts .. + } + default { + lpop finalparts + } + } + } + default { + lappend finalparts $p + } + } + incr i + } + } else { + foreach p [lrange $parts $rootindex+1 end] { + if {[llength $finalparts] <= $baselen} { + if {$p ni {. .. ""}} { + lappend finalparts $p + } + } else { + switch -exact -- $p { + . - "" {} + .. { + lpop finalparts ;#uses punk::lib::compat::lpop if on < 8.7 + } + default { + lappend finalparts $p + } + } + } + } + } + puts "==>finalparts: '$finalparts'" + # using join - {"" "" server share} -> //server/share and {a b} -> a/b + if {[llength $finalparts] == 1 && [lindex $finalparts 0] eq ""} { + #backtracking on unix-style path can end up with empty string as only member of finalparts + #e.g /x/.. + return / + } + set result [::join $finalparts /] + #normalize volumes and mountschemes to have trailing slash if no subpath + #e.g c: -> c:/ + #//zipfs: -> //zipfs:/ + if {[set lastchar [string index $result end]] eq ":"} { + if {$result eq "//zipfs:"} { + set result "//zipfs:/" + } else { + if {[string first / $result] < 0} { + set result $result/ + } + } + } elseif {[string match //* $result]} { + if {![punk::winpath::is_dos_device_path $result]} { + #server + set tail [string range $result 2 end] + set tailparts [split $tail /] + if {[llength $tailparts] <=1} { + #empty // or //servername + append result / + } + } + } elseif {[llength $finalparts] == 2} { + if {[string range [lindex $finalparts 0] end-1 end] eq ":/"} { + #e.g https://server/ -> finalparts {https:/ server} + #e.g https:/// -> finalparts {https:/ ""} + #scheme based path should always return trailing slash after server component - even if server component empty. + lappend finalparts "" ;#force trailing / + return [join $finalparts /] + } + } + return $result + } + + proc trim_final_slash {str} { + if {[string index $str end] eq "/"} { + return [string range $str 0 end-1] + } + return $str + } + + + #x-platform - punk::path::pathtype - can be used in safe interps - different concept of pathtypes to 'file pathtype' + # - no volumerelative + # - no lookup of file volumes (volume is a windows concept - but with //zipfs:/ somewhat applicable to other platforms) + # - /* as absolute (covers also //zipfs:/ (volume), //server , //./etc , //./UNC) + # - xxx:// as absolute (scheme) + # - xxx:/ or x:/ as absolute + # - x: xxx: -> as absolute (volume-basic or volume-extended) + + #note also on windows - legacy name for COM devices + # COM1 = COM1: + # //./COM1 ?? review + + proc pathtype {str} { + set str [string map "\\\\ /" $str] + if {[string index $str 0] eq "/"} { + #todo - look for //xxx:/ prefix (generalisation of //zipfs:/) as a 'volume' specifically {volume mount} ?? - review + # look for //server prefix as {absolute server} + # look for //./UNC/server or //?/UNC/server as {absolute server UNC} ? + # look for //./ as {absolute dosdevice} + return absolute + } + + #only firstsegment with single colon at last position (after some non empty string) counts as volume or scheme - review + #e.g a:b:/.. or a::/.. or :/.. is not treated as volume/scheme whereas ab:/ is. + set firstslash [string first / $str] + if {$firstslash == -1} { + set firstsegment $str + } else { + set firstsegment [string range $str 0 $firstslash-1] + } + if {[set firstc [string first : $firstsegment]] > 0} { + set lhs_firstsegment [string range $firstsegment 0 $firstc-1] + set rhs_firstsegment [string range $firstsegment $firstc+1 end] ;#exclude a:b/ etc + if {$rhs_firstsegment eq ""} { + set rhs_entire_path [string range $str $firstc+1 end] + #assert lhs_firstsegment not empty since firstc > 0 + #count following / sequence + set i 0 + set slashes_after_firstsegment "" ;#run of slashes *directly* following first segment + while {$i < [string length $rhs_entire_path]} { + if {[string index $rhs_entire_path $i] eq "/"} { + append slashes_after_firstsegment / + } else { + break + } + incr i + } + switch -exact -- $slashes_after_firstsegment { + "" - / { + if {[string length $lhs_firstsegment] == 1} { + return {absolute volume basic} + } else { + return {absolute volume extended} + } + } + default { + #2 or more / + #this will return 'scheme' even for c:// - even though that may look like a windows volume - review + return {absolute scheme} + } + } + } + } + #assert first element of any return has been absolute or relative + return relative + } + + + proc plain {str} { + set str [string map "\\\\ /" $str] + set pathinfo [punk::path::pathtype $str] + if {[lindex $pathinfo 0] eq "relative" && ![string match ./* $str]} { + set str ./$str + } + if {[string index $str end] eq "/"} { + if {[string map {/ ""} $str] eq ""} { + #all slash segment + return $str + } else { + if {[lindex $pathinfo 1] ni {volume scheme}} { + return [string range $str 0 end-1] + } + } + } + return $str + } + #purely string based - no reference to filesystem knowledge + #unix-style forward slash only + proc plainjoin {args} { + set args [lmap a $args {string map "\\\\ /" $a}] + #if {[llength $args] == 1} { + # return [lindex $args 0] + #} + set out "" + foreach a $args { + if {![string length $out]} { + append out [plain $a] + } else { + set a [plain $a] + if {[string map {/ ""} $out] eq ""} { + set out [string range $out 0 end-1] + } + + if {[string map {/ ""} $a] eq ""} { + #all / segment + append out [string range $a 0 end-1] + } else { + if {[string length $a] > 2 && [string match "./*" $a]} { + set a [string range $a 2 end] + } + if {[string index $out end] eq "/"} { + append out $a + } else { + append out / $a + } + } + } + } + return $out + } + proc plainjoin1 {args} { + if {[llength $args] == 1} { + return [lindex $args 0] + } + set out [trim_final_slash [lindex $args 0]] + foreach a [lrange $args 1 end] { + set a [trim_final_slash $a] + append out / $a + } + return $out + } + + #intention? + #proc filepath_dotted_dirname {path} { + #} + + proc strip_prefixdepth {path prefix} { + if {$prefix eq ""} { + return [norm $path] + } + return [file join \ + {*}[lrange \ + [file split [norm $path]] \ + [llength [file split [norm $prefix]]] \ + end]] + } proc pathglob_as_re {pathglob} { #*** !doctools diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm index ee2384b4..2cb5fd1d 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm @@ -134,13 +134,30 @@ namespace eval punk::repo { } interp alias "" fossil "" punk::repo::fossil_proxy + # --- + # Calling auto_execok on an external tool can be too slow to do during package load (e.g could be 150ms) + #safe interps can't call auto_execok #At least let them load the package even though much of it may be unusable depending on the safe configuration - catch { - if {[auto_execok fossil] ne ""} { - interp alias "" FOSSIL "" {*}[auto_execok fossil] - } + #catch { + # if {[auto_execok fossil] ne ""} { + # interp alias "" FOSSIL "" {*}[auto_execok fossil] + # } + #} + # --- + # ---------- + # + + #uppercase FOSSIL to bypass fossil as alias to fossil_proxy + proc establish_FOSSIL {args} { + if {![info exists ::auto_execs(FOSSIL)]} { + set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp + } + interp alias "" FOSSIL "" ;#delete establishment alias + FOSSIL {*}$args } + interp alias "" FOSSIL "" punk::repo::establish_FOSSIL + # ---------- proc askuser {question} { if {![catch {package require punk::lib}]} { @@ -370,7 +387,16 @@ namespace eval punk::repo { } if {$repodir eq ""} { - error "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "args: $args" + dict set resultdict revision {} + dict set resultdict revision_iso8601 {} + dict set resultdict paths {} + dict set resultdict ahead "" + dict set resultdict behind "" + dict set resultdict error {reason "no_repo_found"} + dict set resultdict repotype none + return $resultdict } set subpath [punk::path::relative $repodir $abspath] if {$subpath eq "."} { @@ -644,6 +670,16 @@ namespace eval punk::repo { set path_count_fields [list unchanged changed new missing extra] set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601] set dresult [dict create] + if {[dict exists $repostate error]} { + foreach f $state_fields { + dict set dresult $f "" + } + foreach f $path_count_fields { + dict set dresult $f "" + } + #todo? + return $dresult + } foreach f $state_fields { dict set dresult $f [dict get $repostate $f] } diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm index b30133ba..6de745a8 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/winpath-0.1.0.tm @@ -30,7 +30,7 @@ namespace eval punk::winpath { #\\servername\share etc or \\?\UNC\servername\share etc. proc is_unc_path {path} { - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway) if {[string first "//" $strcopy_path] == 0} { #check for "Dos device path" syntax @@ -77,7 +77,7 @@ namespace eval punk::winpath { #dos device path syntax allows windows api to acces extended-length paths and filenames with illegal path characters such as trailing dots or whitespace #(can exist on server shares and on NTFS - but standard apps can't access without dos device syntax) proc is_dos_device_path {path} { - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway) if {[string range $strcopy_path 0 3] in {//?/ //./}} { return 1 @@ -87,7 +87,7 @@ namespace eval punk::winpath { } proc strip_dos_device_prefix {path} { #it's unlikely to be valid to strip only //?/ from a //?/UNC path so check for it here and diver to strip that. - #(review.. or raise error because a //?/UNC path isn't *strictly* a UNC path? ) + #(review.. or raise error because a //?/UNC path isn't an ordinary dos device path? ) if {[is_unc_path $path]} { return [strip_unc_path_prefix $path] } @@ -98,18 +98,18 @@ namespace eval punk::winpath { } } proc strip_unc_path_prefix {path} { - if {[is_unc_path $path]} { - #//?/UNC/server/etc - set strcopy_path [punk::objclone $path] - set trimmedpath [string range $strcopy_path 7 end] - file pathtype $trimmedpath ;#shimmer it to path rep - return $trimmedpath - } elseif {is_unc_path_plain $path} { + if {[is_unc_path_plain $path]} { #plain unc //server - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] set trimmedpath [string range $strcopy_path 2 end] file pathtype $trimmedpath return $trimmedpath + } elseif {is_unc_path $path} { + #//?/UNC/server/subpath or //./UNC/server/subpath + set strcopy_path [punk::winpath::system::objclone $path] + set trimmedpath [string range $strcopy_path 7 end] + file pathtype $trimmedpath ;#shimmer it to path rep + return $trimmedpath } else { return $path } @@ -153,7 +153,7 @@ namespace eval punk::winpath { error $err } - set strcopy_path [punk::objclone $path] + set strcopy_path [punk::winpath::system::objclone $path] #Note: path could still have leading double slash if it is a Dos device path: e.g. //?/c:/etc @@ -225,27 +225,124 @@ namespace eval punk::winpath { return 0 } - proc test_ntfs_tunneling {f1 f2 args} { - file mkdir $f1 - puts stderr "waiting 15secs..." - after 5000 {puts -nonewline stderr .} - after 5000 {puts -nonewline stderr .} - after 5000 {puts -nonewline stderr .} - after 500 {puts stderr \n} - file mkdir $f2 - puts stdout "$f1 [file stat $f1]" - puts stdout "$f2 [file stat $f2]" - file delete $f1 - puts stdout "renaming $f2 to $f1" - file rename $f2 $f1 - puts stdout "$f1 [file stat $f1]" - + proc shortname {path} { + set shortname "NA" + if {[catch { + set shortname [dict get [file attributes $path] -shortname] + } errM]} { + puts stderr "Failed to get shortname for '$path'" + } + return $shortname + } + proc test_ntfs_tunneling {prefix args} { + puts stderr "We are looking for whether any of the final $prefix files or dirs took over the ctime attribute of the original $prefix files or dirs" + puts stderr "We expect the ino values to get potentially reassigned depending on order of deletion/creation so matches are coincidental and not material" + puts stderr "The shortnames are similarly allocated as they come - so presumably match by coincidence" + puts stderr "However - if we record a file's shortname, then delete it. Recreating it by shortname within the tunneling timeframe will magically reassociate the longname" + puts stderr "use test_ntfs_tunneling2 to test shortname tunneling" + file mkdir $prefix-dir-rename + file mkdir $prefix-dir-recreate + set fd [open $prefix-file-recreate.txt w] + puts $fd "original for recreate" + close $fd + set fd [open $prefix-file-rename.txt w] + puts $fd "original for rename" + close $fd + puts stdout "ORIGINAL files/dirs" + puts stdout "$prefix-dir-rename [file stat $prefix-dir-rename] " + puts stdout "$prefix-dir-recreate [file stat $prefix-dir-recreate]" + puts stdout "$prefix-file-recreate.txt [file stat $prefix-file-recreate.txt] short:[shortname $prefix-file-recreate.txt]" + puts stdout "$prefix-file-rename.txt [file stat $prefix-file-rename.txt] short:[shortname $prefix-file-rename.txt]" + puts stderr "waiting 10secs (to have discernable ctime differences)" + after 5000 + puts -nonewline stderr . + after 5000 + puts -nonewline stderr . + after 500 + + #-- + #seems to make no diff whether created or copied - no tunneling seen with dirs + #file mkdir $prefix-dir-rename-temp + file copy $prefix-dir-rename $prefix-dir-rename-temp + #-- + puts stderr \n + puts stdout "$prefix-dir-rename-temp [file stat $prefix-dir-rename-temp] (temp to rename into place)" + puts stderr "deleting $prefix-dir-rename" + file delete $prefix-dir-rename + puts stdout "renaming $prefix-dir-rename-temp to $prefix-dir-rename" + file rename $prefix-dir-rename-temp $prefix-dir-rename + + puts stderr "deleting $prefix-dir-recreate" + file delete $prefix-dir-recreate + puts stdout "re-creating $prefix-dir-recreate" + file mkdir $prefix-dir-recreate + + puts stderr "deleting $prefix-file-recreate.txt" + file delete $prefix-file-recreate.txt + puts stderr "Recreating $prefix-file-recreate.txt" + set fd [open $prefix-file-recreate.txt w] + puts $fd "replacement" + close $fd + + puts stderr "copying $prefix-file-rename.txt to $prefix-file-rename-temp.txt" + file copy $prefix-file-rename.txt $prefix-file-rename-temp.txt + puts stdout "$prefix-file-rename-temp.txt [file stat $prefix-file-rename-temp.txt] short:[shortname $prefix-file-rename-temp.txt] (status of initial temp copy)" + puts stderr "modifying temp copy before deletion of original.. (append)" + set fd [open $prefix-file-rename-temp.txt a] + puts $fd "added to file" + close $fd + puts stdout "$prefix-file-rename-temp.txt [file stat $prefix-file-rename-temp.txt] short:[shortname $prefix-file-rename-temp.txt] (status of appended temp copy)" + puts stderr "deleting $prefix-file-rename.txt" + file delete $prefix-file-rename.txt + puts stderr "renaming temp file $prefix-file-rename-temp.txt to original $prefix-file-rename.txt" + file rename $prefix-file-rename-temp.txt $prefix-file-rename.txt + + puts stdout "Final files/dirs" + puts stdout "$prefix-dir-rename [file stat $prefix-dir-rename]" + puts stdout "$prefix-dir-recreate [file stat $prefix-dir-recreate]" + puts stdout "$prefix-file-recreate.txt [file stat $prefix-file-recreate.txt] short:[shortname $prefix-file-recreate.txt]" + puts stdout "$prefix-file-rename.txt [file stat $prefix-file-rename.txt] short:[shortname $prefix-file-rename.txt]" + } + proc test_ntfs_tunneling2 {prefix {waitms 15000}} { + #shortname -> longname tunneling + puts stderr "Tunneling only happens if we delete via shortname? review" + set f1 $prefix-longname-file1.txt + set f2 $prefix-longname-file2.txt + + set fd [open $f1 w];close $fd + set shortname1 [shortname $f1] + puts stderr "longname:$f1 has shortname:$shortname1" + set fd [open $f2 w];close $fd + set shortname2 [shortname $f2] + puts stderr "longname:$f2 has shortname:$shortname2" + + puts stderr "deleting $f1 via name $shortname1" + file delete $shortname1 + puts stdout "immediately recreating $shortname1 - should retain longname $f1 via tunneling" + set fd [open $shortname1 w];close $fd + set f1_exists [file exists $f1] + puts stdout "file exists $f1 = $f1_exists" + + puts stderr "deleting $f2 via name $shortname2" + file delete $shortname2 + puts stderr "Waiting [expr {$waitms / 1000}] seconds.. (standard tunneling timeframe is 15 seconds if registry hasn't been tweaked)" + after $waitms + puts stdout "recreating $shortname2 after wait of $waitms ms - longname lost?" + set fd [open $shortname2 w];close $fd + set f2_exists [file exists $f2] + puts stdout "file exists $f2 = $f2_exists" + + puts stdout -done- } - } - +namespace eval punk::winpath::system { + #get a copy of the item without affecting internal rep + proc objclone {obj} { + append obj2 $obj {} + } +} diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.1.tm b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.1.tm index 94af61ba..5d127a38 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.1.tm +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.1.tm @@ -12,25 +12,97 @@ # Meta license # @@ Meta End +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_textblock 0 0.1.1] +#[copyright "2024"] +#[titledesc {punk textblock functions}] [comment {-- Name section and table of contents description --}] +#[moddesc {punk textblock}] [comment {-- Description at end of page heading --}] +#[require textblock] +#[keywords module utility lib] +#[description] +#[para] Ansi-aware terminal textblock manipulation + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[section Overview] +#[para] overview of textblock +#[subsection Concepts] +#[para] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements -##e.g package require frobz +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by textblock +#[list_begin itemized] + +#*** !doctools +#[item] [package {Tcl 8.6-}] +#[item] [package {punk::args}] +#[item] [package {punk::char}] +#[item] [package {punk::ansi}] +#[item] [package {punk::lib}] +#[item] [package {overtype}] +#[item] [package {term::ansi::code::macros}] +#[item] [package {textutil}] + +## Requirements +package require Tcl 8.6- package require punk::args package require punk::char package require punk::ansi package require punk::lib catch {package require patternpunk} package require overtype + +#safebase interps as at 2024-08 can't access deeper paths - even though they are below the supposed safe list. package require term::ansi::code::macros ;#required for frame if old ansi g0 used - review - make package optional? package require textutil + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + tcl::namespace::eval textblock { #review - what about ansi off in punk::console? tcl::namespace::import ::punk::ansi::a ::punk::ansi::a+ tcl::namespace::export block frame frame_cache framedef frametypes gcross height width widthtopline join join_basic list_as_table pad testblock - + variable use_md5 ;#framecache + set use_md5 1 + if {[catch {package require md5}]} { + set use_md5 0 + } + proc use_md5 {{yes_no ""}} { + variable use_md5 + if {$yes_no eq ""} { + return $use_md5 + } + if {![string is boolean -strict $yes_no]} { + error "textblock::use_md5 requires a boolean (or empty string to query)" + } + if {$yes_no} { + package require md5 + set use_md5 1 + } else { + set use_md5 0 + } + return $use_md5 + } tcl::namespace::eval class { variable opts_table_defaults set opts_table_defaults [tcl::dict::create\ @@ -228,6 +300,7 @@ tcl::namespace::eval textblock { } return $map } + if {[tcl::info::commands [tcl::namespace::current]::table] eq ""} { #*** !doctools #[subsection {Namespace textblock::class}] @@ -249,7 +322,7 @@ tcl::namespace::eval textblock { oo::class create [tcl::namespace::current]::table [tcl::string::map [list %topt_keys% $topt_keys %topt_switchkeys% $switch_keys_valid_topts %copt_keys% $copt_keys %copt_switchkeys% $switch_keys_valid_copts] { #*** !doctools - #[enum] CLASS [class interface_caphandler.registry] + #[enum] CLASS [class textblock::class::table] #[list_begin definitions] # [para] [emph METHODS] variable o_opts_table ;#options as configured by user (with exception of -ansireset) @@ -3986,7 +4059,7 @@ tcl::namespace::eval textblock { if append is chosen the new values will always start at the first column" -columns -default "" -type integer -help "Number of table columns Will default to 2 if not using an existing -table object" - *values + *values -min 0 -max 1 datalist -default {} -help "flat list of table cell values which will be wrapped based on -columns value" }] $args] set opts [dict get $argd opts] @@ -4337,6 +4410,14 @@ tcl::namespace::eval textblock { return [tcl::dict::create width $width height $height] ;#maintain order in 'image processing' standard width then height - caller may use lassign [tcl::dict::values [blocksize ]] width height } + proc size_as_opts {textblock} { + set sz [size $textblock] + return [dict create -width [dict get $sz width] -height [dict get $sz height]] + } + proc size_as_list {textblock} { + set sz [size $textblock] + return [list [dict get $sz width] [dict get $sz height]] + } #must be able to handle block as string with or without newlines #if no newlines - attempt to treat as a list #must handle whitespace-only string,list elements, and/or lines. @@ -5061,6 +5142,7 @@ tcl::namespace::eval textblock { [punk::lib::list_as_lines -- [lrepeat 8 " | "]] } proc table {args} { + #todo - use punk::args upvar ::textblock::class::opts_table_defaults toptdefaults set defaults [tcl::dict::create\ -rows [list]\ @@ -5112,7 +5194,7 @@ tcl::namespace::eval textblock { } variable frametypes - set frametypes [list light heavy arc double block block1 block2 ascii altg] + set frametypes [list light heavy arc double block block1 block2 block2hack ascii altg] #class::table needs to be able to determine valid frametypes proc frametypes {} { variable frametypes @@ -5121,7 +5203,7 @@ tcl::namespace::eval textblock { proc frametype {f} { #set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] switch -- $f { - light - heavy - arc - double - block - block1 - block2 - ascii - altg { + light - heavy - arc - double - block - block1 - block2 - block2hack - ascii - altg { return [tcl::dict::create category predefined type $f] } default { @@ -5142,7 +5224,7 @@ tcl::namespace::eval textblock { set is_custom_dict_ok 0 } if {!$is_custom_dict_ok} { - error "frame option -type must be one of known types: $textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" + error "frame option -type must be one of known types: $::textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" } set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] set custom_frame [tcl::dict::merge $default_custom $f] @@ -6252,9 +6334,12 @@ tcl::namespace::eval textblock { set vlr \u2595 ;# right one eighth block set vll \u258f ;# left one eighth block + #some terminals (on windows as at 2024) miscount width of these single-width blocks internally + #resulting in extra spacing that is sometimes well removed from the character itself (e.g at next ansi reset) + #This was fixed in windows-terminal based systems (2021) but persists in others. + #https://github.com/microsoft/terminal/issues/11694 set tlc \U1fb7d ;#legacy block set trc \U1fb7e ;#legacy block - set blc \U1fb7c ;#legacy block set brc \U1fb7f ;#legacy block @@ -6265,6 +6350,42 @@ tcl::namespace::eval textblock { set vlrj $vlr } + block2hack { + #the resultant table will have text appear towards top of each box + #with 'legacy' computing unicode block - hopefully these become more widely supported - as they are useful and fill in some gaps + set hlt \u2594 ;# upper one eighth block + set hlb \u2581 ;# lower one eighth block + set vlr \u2595 ;# right one eighth block + set vll \u258f ;# left one eighth block + + #see comments in block2 regarding the problems in some terminals that this *may* hack around to some extent. + #the caller probably only needs block2hack if block2 doesn't work + + #1) + #review - this hack looks sort of promising - but overtype::renderline needs fixing ? + #set tlc \U1fb7d\b ;#legacy block + #set trc \U1fb7e\b ;#legacy block + #set blc \U1fb7c\b ;#legacy block + #set brc \U1fb7f\b ;#legacy block + + #2) - works on cmd.exe and some others + # a 'privacy message' is 'probably' also not supported on the old terminal but is on newer ones + #known exception - conemu on windows - displays junk for various ansi codes - (and slow terminal anyway) + #this hack has a reasonable chance of working + #except that the punk overtype library does recognise PMs + #A single backspace however is an unlikely and generally unuseful PM - so there is a corresponding hack in the renderline system to pass this PM through! + #ugly - in that we don't know the application specifics of what the PM data contains and where it's going. + set tlc \U1fb7d\x1b^\b\x1b\\ ;#legacy block + set trc \U1fb7e\x1b^\b\x1b\\ ;#legacy block + set blc \U1fb7c\x1b^\b\x1b\\ ;#legacy block + set brc \U1fb7f\x1b^\b\x1b\\ ;#legacy block + + #horizontal and vertical bar joins + set hltj $hlt + set hlbj $hlb + set vllj $vll + set vlrj $vlr + } block { set hlt \u2580 ;#upper half set hlb \u2584 ;#lower half @@ -6286,7 +6407,7 @@ tcl::namespace::eval textblock { set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] ;#only default the general types - these form defaults for more specific types if they're missing if {[llength $f] % 2 != 0} { #todo - retrieve usage from punk::args - error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $textblock::frametypes and does not appear to be a dictionary for a custom frametype" + error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $::textblock::frametypes and does not appear to be a dictionary for a custom frametype" } #unknown order of keys specified by user - validate before creating vars as we need more general elements to be available as defaults dict for {k v} $f { @@ -6388,7 +6509,7 @@ tcl::namespace::eval textblock { #options before content argument - which is allowed to be absent - #frame performance (noticeable with complex tables even of modest size) is improved significantly by frame_cache - but is still (2024) a fairly expensive operation. + #frame performance (noticeable with complex tables even of modest size) is improved somewhat by frame_cache - but is still (2024) a fairly expensive operation. # #consider if we can use -sticky nsew instead of -blockalign (as per Tk grid -sticky option) # This would require some sort of expand equivalent e.g for -sticky ew or -sticky ns - for which we have to decide a meaning for text.. e.g ansi padding? @@ -6397,6 +6518,7 @@ tcl::namespace::eval textblock { # - but we would need to maintain support for the rendered-string based operations too. proc frame {args} { variable frametypes + variable use_md5 #counterintuitively - in-proc dict create each time is generally slightly faster than linked namespace var set opts [tcl::dict::create\ @@ -6416,7 +6538,11 @@ tcl::namespace::eval textblock { -ellipsis 1\ -usecache 1\ -buildcache 1\ + -pad 1\ + -crm_mode 0\ ] + #-pad 1 is default so that simple 'textblock::frame "[a+ Red]a \nbbb[a]" extends the bg colour on the short ragged lines (and empty lines) + # for ansi art - -pad 0 is likely to be preferable set expect_optval 0 set argposn 0 @@ -6455,7 +6581,12 @@ tcl::namespace::eval textblock { #use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache foreach {k v} $arglist { switch -- $k { - -etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache { + -etabs - -type - -boxlimits - -boxmap - -joins + - -title - -subtitle - -width - -height + - -ansiborder - -ansibase + - -blockalign - -textalign - -ellipsis + - -crm_mode + - -usecache - -buildcache - -pad { tcl::dict::set opts $k $v } default { @@ -6471,11 +6602,13 @@ tcl::namespace::eval textblock { set opt_boxmap [tcl::dict::get $opts -boxmap] set opt_usecache [tcl::dict::get $opts -usecache] set opt_buildcache [tcl::dict::get $opts -buildcache] + set opt_pad [tcl::dict::get $opts -pad] + set opt_crm_mode [tcl::dict::get $opts -crm_mode] set usecache $opt_usecache ;#may need to override set buildcache $opt_buildcache set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] - set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable + set known_frametypes $frametypes ;# light, heavey etc as defined in the ::textblock::frametypes variable set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] lassign [textblock::frametype $opt_type] _cat category _type ftype @@ -6614,6 +6747,19 @@ tcl::namespace::eval textblock { } } set contents [tcl::string::map [list \r\n \n] $contents] + if {$opt_crm_mode} { + if {$opt_height eq ""} { + set h [textblock::height $contents] + } else { + set h [expr {$opt_height -2}] + } + if {$opt_width eq ""} { + set w [textblock::width $contents] + } else { + set w [expr {$opt_width -2}] + } + set contents [overtype::renderspace -crm_mode 1 -wrap 1 -width $w -height $h "" $contents] + } set actual_contentwidth [textblock::width $contents] ;#length of longest line in contents (contents can be ragged) set actual_contentheight [textblock::height $contents] } else { @@ -6652,9 +6798,14 @@ tcl::namespace::eval textblock { #review - custom frame affects frame_inner_width - exclude from caching? #set cache_key [concat $arglist $frame_inner_width $frame_inner_height] set hashables [concat $arglist $frame_inner_width $frame_inner_height] - package require md5 - #set hash $hashables - set hash [md5::md5 -hex [encoding convertto utf-8 $hashables]] ;#need fast and unique to content - not cryptographic - review + + if {$use_md5} { + #package require md5 ;#already required at package load + set hash [md5::md5 -hex [encoding convertto utf-8 $hashables]] ;#need fast and unique to content - not cryptographic - review + } else { + set hash $hashables + } + set cache_key "$hash-$frame_inner_width-$frame_inner_height-actualcontentwidth:$actual_contentwidth" #should be in a unicode private range different to that used in table construction #e.g BMP PUA U+E000 -> U+F8FF - although this is commonly used for example by nerdfonts @@ -7057,15 +7208,22 @@ tcl::namespace::eval textblock { append contents [::join [lrepeat $diff \n] ""] } - set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) - set paddedwidth [textblock::widthtopline $paddedcontents] - - #review - horizontal truncation - if {$paddedwidth > $cache_patternwidth} { - set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + if {$opt_pad} { + set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) + set paddedwidth [textblock::widthtopline $paddedcontents] + #review - horizontal truncation + if {$paddedwidth > $cache_patternwidth} { + set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + } + #important to supply end of opts -- to textblock::join - particularly here with arbitrary data + set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays + } else { + set cwidth [textblock::width $contents] + if {$cwidth > $cache_patternwidth} { + set contents [overtype::renderspace -width $cache_patternwidth "" $contents] + } + set contentblock [textblock::join -- $contents] } - #important to supply end of opts -- to textblock::join - particularly here with arbitrary data - set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays set tlines [split $template \n] @@ -7183,7 +7341,6 @@ tcl::namespace::eval textblock { #fastest to do row first then columns - because textblock::join must do line by line if {$crosscount > 1} { - package require textblock set row [textblock::join -- {*}[lrepeat $crosscount $onecross]] set rows [lrepeat $crosscount $row] set out [::join $rows \n] @@ -7223,4 +7380,8 @@ package provide textblock [tcl::namespace::eval textblock { variable version set version 0.1.1 }] -return \ No newline at end of file +return + +#*** !doctools +#[manpage_end] + diff --git a/src/project_layouts/custom/_project/punk.shell-0.1/src/make.tcl b/src/project_layouts/custom/_project/punk.shell-0.1/src/make.tcl index 1cf07c5b..9edd90b0 100644 --- a/src/project_layouts/custom/_project/punk.shell-0.1/src/make.tcl +++ b/src/project_layouts/custom/_project/punk.shell-0.1/src/make.tcl @@ -1212,8 +1212,9 @@ foreach vfstail $vfs_tails { set rtmountpoint //zipfs:/rtmounts/$runtime_fullname set changed_unchanged [$vfs_event targetset_source_changes] + set vfs_or_runtime_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]}] - if {[llength [dict get $changed_unchanged changed]] || [llength [$vfs_event get_targets_exist]] < [llength [$vfs_event get_targets]]} { + if {$vfs_or_runtime_changed} { #source .vfs folder has changes $vfs_event targetset_started # -- --- --- --- --- --- @@ -1283,6 +1284,7 @@ foreach vfstail $vfs_tails { puts stderr "RUNTIME capabilities unknown. Unsure if zip supported. trying anyway.." } } + #note - as at 2024-08 - there is some discussion about the interface to mkimg - it is considered unstable (may change to -option value syntax) puts stderr "calling: tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs \"\" $buildfolder/build_$runtime_fullname" tcl::zipfs::mkimg $buildfolder/$vfsname.new $wrapvfs $wrapvfs "" $buildfolder/build_$runtime_fullname } result ]} { @@ -1352,9 +1354,10 @@ foreach vfstail $vfs_tails { if {![catch { exec $pscmd | grep $targetkit } still_running]} { - - puts stdout "found $targetkit instances still running\n" + set still_running_lines [split [string trim $still_running] \n] + puts stdout "found ([llength $still_running_lines]) $targetkit instances still running\n" set count_killed 0 + set num_to_kill [llength $still_running_lines] foreach ln [split $still_running \n] { puts stdout " $ln" @@ -1387,9 +1390,6 @@ foreach vfstail $vfs_tails { #review - *no running instance* works with windows taskkill - "*No such process*" works with kill -9 on FreeBSD and linux - other platforms? if {![string match "*no running instance*" $errMsg] && ![string match "*No such process*" $errMsg]} { lappend failed_kits [list kit $targetkit reason "could not kill running process for $targetkit (using '$killcmd')"] - $vfs_event targetset_end FAILED - $vfs_event destroy - $vfs_installer destroy continue } } else { @@ -1397,10 +1397,15 @@ foreach vfstail $vfs_tails { incr count_killed } } - if {$count_killed > 0} { - puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" - after 1000 + if {$count_killed < $num_to_kill} { + $vfs_event targetset_end FAILED + $vfs_event destroy + $vfs_installer destroy + continue } + + puts stderr "\nKilled $count_killed processes. Waiting a short time before attempting to delete executable" + after 1000 } else { puts stderr "Ok.. no running '$targetkit' processes found" } @@ -1426,22 +1431,35 @@ foreach vfstail $vfs_tails { # -- --- --- --- --- --- $vfs_event targetset_end OK + } else { + set skipped_vfs_build 1 + puts stderr "." + puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" + $vfs_event targetset_end SKIPPED + } + $vfs_event destroy + $vfs_installer destroy - after 200 - set deployment_folder [file dirname $sourcefolder]/bin - file mkdir $deployment_folder + after 200 + set deployment_folder [file dirname $sourcefolder]/bin + file mkdir $deployment_folder - # -- ---------- - set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] - $bin_installer set_source_target $buildfolder $deployment_folder - set bin_event [$bin_installer start_event {-make-step final_kit_install}] - $bin_event targetset_init INSTALL $deployment_folder/$targetkit - #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) - #set last_completion [$bin_event targetset_last_complete] - - $bin_event targetset_addsource $buildfolder/$targetkit - $bin_event targetset_started - # -- ---------- + # -- ---------- + set bin_installer [punkcheck::installtrack new "make.tcl" $deployment_folder/.punkcheck] + $bin_installer set_source_target $buildfolder $deployment_folder + set bin_event [$bin_installer start_event {-make-step final_kit_install}] + $bin_event targetset_init INSTALL $deployment_folder/$targetkit + #todo - move final deployment step outside of the build vfs loop? (final deployment can fail and then isn't rerun even though _build and deployed versions differ, unless .vfs modified again) + #set last_completion [$bin_event targetset_last_complete] + + $bin_event targetset_addsource $deployment_folder/$targetkit ;#add target as a source of metadata for change detection + $bin_event targetset_addsource $buildfolder/$targetkit + $bin_event targetset_started + # -- ---------- + + set changed_unchanged [$bin_event targetset_source_changes] + set built_or_installed_kit_changed [expr {[llength [dict get $changed_unchanged changed]] || [llength [$bin_event get_targets_exist]] < [llength [$bin_event get_targets]]}] + if {$built_or_installed_kit_changed} { if {[file exists $deployment_folder/$targetkit]} { puts stderr "deleting existing deployed at $deployment_folder/$targetkit" @@ -1467,19 +1485,16 @@ foreach vfstail $vfs_tails { # -- ---------- $bin_event targetset_end OK # -- ---------- - $bin_event destroy - $bin_installer destroy - } else { - set skipped_vfs_build 1 + set skipped_kit_install 1 puts stderr "." - puts stdout "Skipping build for vfs $vfstail with runtime $rtname - no change detected" - $vfs_event targetset_end SKIPPED + puts stdout "Skipping kit install for $targetkit with vfs $vfstail runtime $rtname - no change detected" + $bin_event targetset_end SKIPPED } + $bin_event destroy + $bin_installer destroy - $vfs_event destroy - $vfs_installer destroy } ;#end foreach targetkit } ;#end foreach rtname in runtimes diff --git a/src/runtime/mapvfs.config b/src/runtime/mapvfs.config index 83204502..74876865 100644 --- a/src/runtime/mapvfs.config +++ b/src/runtime/mapvfs.config @@ -12,22 +12,32 @@ #e.g #- myproject.vfs #- punk86.vfs -tclkit86bi.exe {punk8win.vfs punkbi kit} +tclkit86bi.exe {punk8win.vfs punkbi kit} + +#c:\tcl.bawt tcl 8.6.13 bawt +tclkit-win64-dyn.exe {punk86bawt.vfs punkbawt kit} + #magicsplat tclkit - no Tk ##tclkit8613.exe punk86.vfs #magicsplat modified tclkit - added tk, changed icon -tclkit8613punk.exe punk86.vfs {punk.vfs punk86b} +tclkit8613punk.exe punk86.vfs {punk8win.vfs punk86} #tclkit8613punk.head.exe {punk8_statictwapi.vfs punk86head} -#tclkit87a5.exe {punk86.vfs punk87} {punk.vfs punkmain} -tclkit87a5.exe {punk8win.vfs punk87} +#tclkit87a5.exe punk86.vfs punk87} {punk.vfs punkmain} +tclkit87a5.exe {punk8win.vfs punk87} + + +################################## +#TCL9 +tclsh90b2 {punk9win.vfs punk90b2 zip} +tclsh90b4_piperepl.exe {punk9win.vfs punk90b4 zip} {critcl.vfs critcl9 zip} +################################## + -#experimental -tclsh90zip.exe {punk9win.vfs punk90zip zip} ##tclkit87a5bawt.exe punk86.vfs ##tclkit86bi.exe vfs_windows/punk86win.vfs @@ -35,7 +45,5 @@ tclsh90zip.exe {punk9win.vfs punk90zip zip} #temp hack - todo fix .exe for x-platform #linux tclsh90 (zip) built with zig.build x-compile on windows -#tclsh90linux.exe {punk9linux.vfs punk90linux zip} +#tclsh90linux.exe {punk9linux.vfs punk90linux zip} -#c:\tcl.bawt tcl 8.6.13 bawt -tclkit-win64-dyn.exe {punk86bawt.vfs punkbawt kit} \ No newline at end of file diff --git a/src/vendormodules/overtype-1.6.5.tm b/src/vendormodules/overtype-1.6.5.tm index 143794fb..38ce71c2 100644 --- a/src/vendormodules/overtype-1.6.5.tm +++ b/src/vendormodules/overtype-1.6.5.tm @@ -163,22 +163,23 @@ proc overtype::string_columns {text} { tcl::namespace::eval overtype::priv { } -#could return larger than colwidth +#could return larger than renderwidth proc _get_row_append_column {row} { + #obsolete? upvar outputlines outputlines set idx [expr {$row -1}] if {$row <= 1 || $row > [llength $outputlines]} { return 1 } else { - upvar opt_overflow opt_overflow - upvar colwidth colwidth + upvar opt_expand_right expand_right + upvar renderwidth renderwidth set existinglen [punk::ansi::printing_length [lindex $outputlines $idx]] set endpos [expr {$existinglen +1}] - if {$opt_overflow} { + if {$expand_right} { return $endpos } else { - if {$endpos > $colwidth} { - return $colwidth + 1 + if {$endpos > $renderwidth} { + return $renderwidth + 1 } else { return $endpos } @@ -204,38 +205,70 @@ tcl::namespace::eval overtype { proc renderspace {args} { #*** !doctools #[call [fun overtype::renderspace] [arg args] ] - #[para] usage: ?-transparent [lb]0|1[rb]? ?-overflow [lb]1|0[rb]? ?-ellipsis [lb]1|0[rb]? ?-ellipsistext ...? undertext overtext + #[para] usage: ?-transparent [lb]0|1[rb]? ?-expand_right [lb]1|0[rb]? ?-ellipsis [lb]1|0[rb]? ?-ellipsistext ...? undertext overtext # @c overtype starting at left (overstrike) # @c can/should we use something like this?: 'format "%-*s" $len $overtext variable default_ellipsis_horizontal if {[llength $args] < 2} { - error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} + error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-expand_right [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} + } + set optargs [lrange $args 0 end-2] + if {[llength $optargs] % 2 == 0} { + lassign [lrange $args end-1 end] underblock overblock + set argsflags [lrange $args 0 end-2] + } else { + set optargs [lrange $args 0 end-1] + if {[llength $optargs] %2 == 0} { + set overblock [lindex $args end] + set underblock "" + set argsflags [lrange $args 0 end-1] + } else { + error "renderspace expects opt-val pairs followed by: or just " + } } - lassign [lrange $args end-1 end] underblock overblock set opts [tcl::dict::create\ - -bias ignored\ - -width \uFFEF\ - -height \uFFEF\ + -bias ignored\ + -width \uFFEF\ + -height \uFFEF\ -startcolumn 1\ - -wrap 0\ - -ellipsis 0\ + -wrap 0\ + -ellipsis 0\ -ellipsistext $default_ellipsis_horizontal\ -ellipsiswhitespace 0\ - -overflow 0\ - -appendlines 1\ - -transparent 0\ - -exposed1 \uFFFD\ - -exposed2 \uFFFD\ - -experimental 0\ - -looplimit \uFFEF\ + -expand_right 0\ + -appendlines 1\ + -transparent 0\ + -exposed1 \uFFFD\ + -exposed2 \uFFFD\ + -experimental 0\ + -cp437 1\ + -looplimit \uFFEF\ + -crm_mode 0\ + -reverse_mode 0\ + -insert_mode 0\ + -console {stdin stdout stderr}\ ] + #expand_right is perhaps consistent with the idea of the page_size being allowed to grow horizontally.. + # it does not necessarily mean the viewport grows. (which further implies need for horizontal scrolling) + # - it does need to be within some concept of terminal width - as columns must be addressable by ansi sequences. + # - This implies the -width option value must grow if it is tied to the concept of renderspace terminal width! REVIEW. + # - further implication is that if expand_right grows the virtual renderspace terminal width - + # then some sort of reflow/rerender needs to be done for preceeding lines? + # possibly not - as expand_right is distinct from a normal terminal-width change event, + # expand_right being primarily to support other operations such as textblock::table + + #todo - viewport width/height as separate concept to terminal width/height? #-ellipsis args not used if -wrap is true - set argsflags [lrange $args 0 end-2] foreach {k v} $argsflags { switch -- $k { - -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental { + -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace + - -transparent - -exposed1 - -exposed2 - -experimental + - -expand_right - -appendlines + - -reverse_mode - -crm_mode - -insert_mode + - -cp437 + - -console { tcl::dict::set opts $k $v } default { @@ -245,7 +278,8 @@ tcl::namespace::eval overtype { } #set opts [tcl::dict::merge $defaults $argsflags] # -- --- --- --- --- --- - set opt_overflow [tcl::dict::get $opts -overflow] + #review - expand_left for RTL text? + set opt_expand_right [tcl::dict::get $opts -expand_right] ##### # review -wrap should map onto DECAWM terminal mode - the wrap 2 idea may not fit in with this?. set opt_wrap [tcl::dict::get $opts -wrap] ;#wrap 1 is hard wrap cutting word at exact column, or 1 column early for 2w-glyph, wrap 2 is for language-based word-wrap algorithm (todo) @@ -261,23 +295,33 @@ tcl::namespace::eval overtype { set opt_exposed1 [tcl::dict::get $opts -exposed1] ;#widechar_exposed_left - todo set opt_exposed2 [tcl::dict::get $opts -exposed2] ;#widechar_exposed_right - todo # -- --- --- --- --- --- + set opt_crm_mode [tcl::dict::get $opts -crm_mode] + set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] + set opt_insert_mode [tcl::dict::get $opts -insert_mode] + # -- --- --- --- --- --- + set opt_cp437 [tcl::dict::get $opts -cp437] + + + #initial state for renderspace 'terminal' reset + set initial_state [dict create\ + -width $opt_width\ + -height $opt_height\ + -crm_mode $opt_crm_mode\ + -reverse_mode $opt_reverse_mode\ + -insert_mode $opt_insert_mode\ + -cp437 $opt_cp437\ + ] # ---------------------------- # -experimental dev flag to set flags etc # ---------------------------- set data_mode 0 - set test_mode 1 set info_mode 0 set edit_mode 0 set opt_experimental [tcl::dict::get $opts -experimental] foreach o $opt_experimental { switch -- $o { - test_mode { - set test_mode 1 - set info_mode 1 - } old_mode { - set test_mode 0 set info_mode 1 } data_mode { @@ -291,13 +335,13 @@ tcl::namespace::eval overtype { } } } - set test_mode 1 ;#try to eliminate # ---------------------------- #modes - set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l - set autowrap_mode $opt_wrap - set reverse_mode 0 + set insert_mode $opt_insert_mode ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l + set autowrap_mode $opt_wrap + set reverse_mode $opt_reverse_mode + set crm_mode $opt_crm_mode set underblock [tcl::string::map {\r\n \n} $underblock] @@ -307,33 +351,35 @@ tcl::namespace::eval overtype { #set underlines [split $underblock \n] #underblock is a 'rendered' block - so width height make sense - #colwidth & colheight were originally named with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. - #The naming is now confusing. It should be something like renderwidth renderheight ?? review + #only non-cursor affecting and non-width occupying ANSI codes should be present. + #ie SGR codes and perhaps things such as PM - although generally those should have been pushed to the application already + #renderwidth & renderheight were originally used with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. if {$opt_width eq "\uFFEF" || $opt_height eq "\uFFEF"} { - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } if {$opt_height ne "\uFFEF"} { - set colheight $opt_height + set renderheight $opt_height } } else { - set colwidth $opt_width - set colheight $opt_height + set renderwidth $opt_width + set renderheight $opt_height } # -- --- --- --- #REVIEW - do we need ansi resets in the underblock? if {$underblock eq ""} { - set underlines [lrepeat $colheight ""] + set underlines [lrepeat $renderheight ""] } else { + set underblock [textblock::join_basic -- $underblock] ;#ensure properly rendered - ansi per-line resets & replays set underlines [split $underblock \n] } #if {$underblock eq ""} { # set blank "\x1b\[0m\x1b\[0m" # #set underlines [list "\x1b\[0m\x1b\[0m"] - # set underlines [lrepeat $colheight $blank] + # set underlines [lrepeat $renderheight $blank] #} else { # #lines_as_list -ansiresets 1 will do nothing if -ansiresets 1 isn't specified - REVIEW # set underlines [lines_as_list -ansiresets 1 $underblock] @@ -341,7 +387,7 @@ tcl::namespace::eval overtype { # -- --- --- --- #todo - reconsider the 'line' as the natural chunking mechanism for the overlay. - #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth + #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output renderwidth #In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time. #(in cases where there are interline moves or cursor jumps anyway) #This works - but doesn't seem efficient. @@ -356,49 +402,45 @@ tcl::namespace::eval overtype { set looplimit [expr {[tcl::string::length $overblock] + 10}] } - if {!$test_mode} { - set inputchunks [split $overblock \n] - } else { - set scheme 3 - switch -- $scheme { - 0 { - #one big chunk - set inputchunks [list $overblock] + set scheme 3 + switch -- $scheme { + 0 { + #one big chunk + set inputchunks [list $overblock] + } + 1 { + set inputchunks [punk::ansi::ta::split_codes $overblock] + } + 2 { + + #split into lines if possible first - then into plaintext/ansi-sequence chunks ? + set inputchunks [list ""] ;#put an empty plaintext split in for starters + set i 1 + set lines [split $overblock \n] + foreach ln $lines { + if {$i < [llength $lines]} { + append ln \n + } + set sequence_split [punk::ansi::ta::split_codes_single $ln] ;#use split_codes Not split_codes_single? + set lastpt [lindex $inputchunks end] + lset inputchunks end [tcl::string::cat $lastpt [lindex $sequence_split 0]] + lappend inputchunks {*}[lrange $sequence_split 1 end] + incr i } - 1 { - set inputchunks [punk::ansi::ta::split_codes $overblock] + } + 3 { + #it turns out line based chunks are faster than the above.. probably because some of those end up doing the regex splitting twice + set lflines [list] + set inputchunks [split $overblock \n] + foreach ln $inputchunks { + append ln \n + lappend lflines $ln } - 2 { - - #split into lines if possible first - then into plaintext/ansi-sequence chunks ? - set inputchunks [list ""] ;#put an empty plaintext split in for starters - set i 1 - set lines [split $overblock \n] - foreach ln $lines { - if {$i < [llength $lines]} { - append ln \n - } - set sequence_split [punk::ansi::ta::split_codes_single $ln] ;#use split_codes Not split_codes_single? - set lastpt [lindex $inputchunks end] - lset inputchunks end [tcl::string::cat $lastpt [lindex $sequence_split 0]] - lappend inputchunks {*}[lrange $sequence_split 1 end] - incr i - } + if {[llength $lflines]} { + lset lflines end [tcl::string::range [lindex $lflines end] 0 end-1] } - 3 { - #it turns out line based chunks are faster than the above.. probably because some of those end up doing the regex splitting twice - set lflines [list] - set inputchunks [split $overblock \n] - foreach ln $inputchunks { - append ln \n - lappend lflines $ln - } - if {[llength $lflines]} { - lset lflines end [tcl::string::range [lindex $lflines end] 0 end-1] - } - set inputchunks $lflines[unset lflines] + set inputchunks $lflines[unset lflines] - } } } @@ -409,7 +451,7 @@ tcl::namespace::eval overtype { set replay_codes_underlay [tcl::dict::create 1 ""] #lappend replay_codes_overlay "" - set replay_codes_overlay "" + set replay_codes_overlay "[punk::ansi::a]" set unapplied "" set cursor_saved_position [tcl::dict::create] set cursor_saved_attributes "" @@ -420,11 +462,11 @@ tcl::namespace::eval overtype { #underlines are not necessarily processed in order - depending on cursor-moves applied from overtext set row 1 - if {$data_mode} { - set col [_get_row_append_column $row] - } else { + #if {$data_mode} { + # set col [_get_row_append_column $row] + #} else { set col $opt_startcolumn - } + #} set instruction_stats [tcl::dict::create] @@ -452,26 +494,34 @@ tcl::namespace::eval overtype { } #review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary - #but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l - set LASTCALL [list -info 1 -insert_mode $insert_mode -autowrap_mode $autowrap_mode -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] - set rinfo [renderline -experimental $opt_experimental\ + set renderargs [list -experimental $opt_experimental\ + -cp437 $opt_cp437\ -info 1\ + -crm_mode $crm_mode\ -insert_mode $insert_mode\ - -cursor_restore_attributes $cursor_saved_attributes\ -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -cursor_restore_attributes $cursor_saved_attributes\ -transparent $opt_transparent\ - -width $colwidth\ + -width $renderwidth\ -exposed1 $opt_exposed1\ -exposed2 $opt_exposed2\ - -overflow $opt_overflow\ + -expand_right $opt_expand_right\ -cursor_column $col\ -cursor_row $row\ $undertext\ $overtext\ - ] + ] + set LASTCALL $renderargs + set rinfo [renderline {*}$renderargs] + set instruction [tcl::dict::get $rinfo instruction] set insert_mode [tcl::dict::get $rinfo insert_mode] set autowrap_mode [tcl::dict::get $rinfo autowrap_mode] ;# - #set reverse_mode [tcl::dict::get $rinfo reverse_mode];#how to support in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + set reverse_mode [tcl::dict::get $rinfo reverse_mode] + #how to support reverse_mode in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + # - review - the answer is probably that we don't need to - it is set/reset only during application of overtext + set crm_mode [tcl::dict::get $rinfo crm_mode] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] set overflow_right_column [tcl::dict::get $rinfo overflow_right_column] @@ -486,7 +536,37 @@ tcl::namespace::eval overtype { set insert_lines_below [tcl::dict::get $rinfo insert_lines_below] tcl::dict::set replay_codes_underlay [expr {$renderedrow+1}] [tcl::dict::get $rinfo replay_codes_underlay] #lset replay_codes_overlay [expr $overidx+1] [tcl::dict::get $rinfo replay_codes_overlay] - set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + if {0 && $reverse_mode} { + #test branch - todo - prune + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + #review + #JMN3 + set existing_reverse_state 0 + #split_codes_single is single esc sequence - but could have multiple sgr codes within one esc sequence + #e.g \x1b\[0;31;7m has a reset,colour red and reverse + set codeinfo [punk::ansi::codetype::sgr_merge [list $replay_codes_overlay] -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + } @@ -515,29 +595,17 @@ tcl::namespace::eval overtype { #keeping separate branches for debugging - review and merge as appropriate when stable tcl::dict::incr instruction_stats $instruction switch -- $instruction { - {} { - if {$test_mode == 0} { - incr row - if {$data_mode} { - set col [_get_row_append_column $row] - if {$col > $colwidth} { + reset { + #reset the 'renderspace terminal' (not underlying terminal) + set row 1 + set col 1 - } - } else { - set col 1 - } - } else { - #lf included in data - set row $post_render_row - set col $post_render_col - #set col 1 - #if {$post_render_row != $renderedrow} { - # set col 1 - #} else { - # set col $post_render_col - #} - } + } + {} { + #lf included in data + set row $post_render_row + set col $post_render_col } up { @@ -563,10 +631,10 @@ tcl::namespace::eval overtype { #we need renderline to return the number of the maximum column filled (or min if we ever do r-to-l) set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -601,10 +669,10 @@ tcl::namespace::eval overtype { } set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -640,9 +708,16 @@ tcl::namespace::eval overtype { puts stdout ">>>[a+ red bold]overflow_right during restore_cursor[a]" - set sub_info [overtype::renderline -info 1 -width $colwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] + set sub_info [overtype::renderline -info 1\ + -width $renderwidth\ + -insert_mode $insert_mode\ + -autowrap_mode $autowrap_mode\ + -expand_right [tcl::dict::get $opts -opt_expand_right]\ + ""\ + $overflow_right\ + ] set foldline [tcl::dict::get $sub_info result] - set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed.. + set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed..? set autowrap_mode [tcl::dict::get $sub_info autowrap_mode] ;#nor this.. linsert outputlines $renderedrow $foldline #review - row & col set by restore - but not if there was no save.. @@ -671,7 +746,7 @@ tcl::namespace::eval overtype { #overflow + unapplied? } lf_start { - #raw newlines - must be test_mode + #raw newlines # ---------------------- #test with fruit.ans #test - treating as newline below... @@ -687,48 +762,58 @@ tcl::namespace::eval overtype { } lf_mid { - if 0 { - #set rhswidth [punk::ansi::printing_length $overflow_right] - #only show debug when we have overflow? - set lhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -nul 1 -lf 1 -vt 1 $rendered]] - set lhs [textblock::frame -title "rendered $visualwidth cols" -subtitle "row-$renderedrow" $lhs] - - set rhs "" - if {$overflow_right ne ""} { - set rhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -nul 1 -lf 1 -vt 1 $overflow_right]] - set rhs [textblock::frame -title overflow_right $rhs] - } - puts [textblock::join $lhs " $post_render_col " $rhs] - } - - if {!$test_mode} { - #rendered - append rendered $overflow_right - #set replay_codes_overlay "" + set edit_mode 0 + if {$edit_mode} { + set inputchunks [linsert $inputchunks 0 $overflow_right$unapplied] set overflow_right "" - - - set row $renderedrow - + set unapplied "" + set row $post_render_row + #set col $post_render_col set col $opt_startcolumn - incr row - #only add newline if we're at the bottom if {$row > [llength $outputlines]} { lappend outputlines {*}[lrepeat 1 ""] } } else { - set edit_mode 0 - if {$edit_mode} { - set inputchunks [linsert $inputchunks 0 $overflow_right$unapplied] - set overflow_right "" - set unapplied "" + if 1 { + if {$overflow_right ne ""} { + if {$opt_expand_right} { + append rendered $overflow_right + set overflow_right "" + } else { + set overflow_width [punk::ansi::printing_length $overflow_right] + if {$visualwidth + $overflow_width <= $renderwidth} { + append rendered $overflow_right + set overflow_right "" + } else { + if {$visualwidth < $renderwidth} { + set graphemes [punk::char::grapheme_split $overflow_width] + set add "" + set addlen $visualwidth + set remaining_overflow $graphemes + foreach g $graphemes { + set w [overtype::grapheme_width_cached] + if {$addlen + $w <= $renderwidth} { + append add $g + incr addlen $w + lpop remaining_overflow + } else { + break + } + } + append rendered $add + set overflow_right [join $remaining_overflow ""] + } + } + } + } set row $post_render_row - #set col $post_render_col set col $opt_startcolumn if {$row > [llength $outputlines]} { lappend outputlines {*}[lrepeat 1 ""] } } else { + #old version - known to work with various ansi graphics - e.g fruit.ans + # - but fails to limit lines to renderwidth when expand_right == 0 append rendered $overflow_right set overflow_right "" set row $post_render_row @@ -740,7 +825,7 @@ tcl::namespace::eval overtype { } } lf_overflow { - #linefeed after colwidth e.g at column 81 for an 80 col width + #linefeed after renderwidth e.g at column 81 for an 80 col width #we may also have other control sequences that came after col 80 e.g cursor save if 0 { @@ -787,38 +872,28 @@ tcl::namespace::eval overtype { set row $post_render_row set col $post_render_col if {$insert_lines_below == 1} { - if {$test_mode == 0} { - set row $renderedrow - set outputlines [linsert $outputlines [expr {$renderedrow }] {*}[lrepeat $insert_lines_below ""]] ;#note - linsert can add to end too - incr row $insert_lines_below - set col $opt_startcolumn - } else { - #set lhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $rendered]] - #set lhs [textblock::frame -title rendered -subtitle "row-$renderedrow" $lhs] - #set rhs "" - #if {$overflow_right ne ""} { - # set rhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $overflow_right]] - # set rhs [textblock::frame -title overflow_right $rhs] - #} - #puts [textblock::join $lhs $rhs] - - #rendered - append rendered $overflow_right - # - - - set overflow_right "" - set row $renderedrow - #only add newline if we're at the bottom - if {$row > [llength $outputlines]} { - lappend outputlines {*}[lrepeat $insert_lines_below ""] - } - incr row $insert_lines_below - set col $opt_startcolumn + #set lhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $rendered]] + #set lhs [textblock::frame -title rendered -subtitle "row-$renderedrow" $lhs] + #set rhs "" + #if {$overflow_right ne ""} { + # set rhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $overflow_right]] + # set rhs [textblock::frame -title overflow_right $rhs] + #} + #puts [textblock::join $lhs $rhs] + #rendered + append rendered $overflow_right + # + set overflow_right "" + set row $renderedrow + #only add newline if we're at the bottom + if {$row > [llength $outputlines]} { + lappend outputlines {*}[lrepeat $insert_lines_below ""] } + incr row $insert_lines_below + set col $opt_startcolumn } } else { set row $post_render_row @@ -833,10 +908,10 @@ tcl::namespace::eval overtype { } else { set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } } @@ -845,12 +920,12 @@ tcl::namespace::eval overtype { #doesn't seem to be used by fruit.ans testfile #used by dzds.ans #note that cursor_forward may move deep into the next line - or even span multiple lines !TODO - set c $colwidth + set c $renderwidth set r $post_render_row - if {$post_render_col > $colwidth} { + if {$post_render_col > $renderwidth} { set i $c while {$i <= $post_render_col} { - if {$c == $colwidth+1} { + if {$c == $renderwidth+1} { incr r if {$opt_appendlines} { if {$r < [llength $outputlines]} { @@ -874,7 +949,7 @@ tcl::namespace::eval overtype { set col $c } wrapmovebackward { - set c $colwidth + set c $renderwidth set r $post_render_row if {$post_render_col < 1} { set c 1 @@ -883,7 +958,7 @@ tcl::namespace::eval overtype { if {$c == 0} { if {$r > 1} { incr r -1 - set c $colwidth + set c $renderwidth } else { #leave r at 1 set c 1 #testfile besthpav.ans first line top left border alignment @@ -910,7 +985,6 @@ tcl::namespace::eval overtype { incr row set col $opt_startcolumn ;#whether wrap or not - next data is at column 1 ?? } else { - #this works for test_mode (which should become the default) - but could give a bad result otherwise - review - add tests fix. set col $post_render_col #set unapplied "" ;#this seems wrong? #set unapplied [tcl::string::range $unapplied 1 end] @@ -941,7 +1015,7 @@ tcl::namespace::eval overtype { #2nd half of grapheme would overflow - treggering grapheme is returned in unapplied. There may also be overflow_right from earlier inserts #todo - consider various options .. re-render a single trailing space or placeholder on same output line, etc if {$autowrap_mode} { - if {$colwidth < 2} { + if {$renderwidth < 2} { #edge case of rendering to a single column output - any 2w char will just cause a loop if we don't substitute with something, or drop the character set idx 0 set triggering_grapheme_index -1 @@ -960,7 +1034,7 @@ tcl::namespace::eval overtype { } else { set overflow_handled 1 #handled by dropping entire overflow if any - if {$colwidth < 2} { + if {$renderwidth < 2} { set idx 0 set triggering_grapheme_index -1 foreach u $unapplied_list { @@ -988,7 +1062,7 @@ tcl::namespace::eval overtype { } - if {!$opt_overflow && !$autowrap_mode} { + if {!$opt_expand_right && !$autowrap_mode} { #not allowed to overflow column or wrap therefore we get overflow data to truncate if {[tcl::dict::get $opts -ellipsis]} { set show_ellipsis 1 @@ -1066,7 +1140,6 @@ tcl::namespace::eval overtype { set debugmsg "" append debugmsg "${Y}${sep_header}${RST}" \n append debugmsg "looplimit $looplimit reached\n" - append debugmsg "test_mode:$test_mode\n" append debugmsg "data_mode:$data_mode\n" append debugmsg "opt_appendlines:$opt_appendlines\n" append debugmsg "prev_row :[tcl::dict::get $LASTCALL -cursor_row]\n" @@ -1141,12 +1214,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + #set renderwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] - #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {$colwidth - $overblock_width}] + set under_exposed_max [expr {$renderwidth - $overblock_width}] if {$under_exposed_max > 0} { #background block is wider if {$under_exposed_max % 2 == 0} { @@ -1176,14 +1248,14 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] set undertext "$undertext[string repeat { } $udiff]" } set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] #review - right-to-left langs should elide on left! - extra option required if {$overflowlength > 0} { @@ -1196,8 +1268,8 @@ tcl::namespace::eval overtype { #overlay line data is wider - trim if overflow not specified in opts - and overtype an ellipsis at right if it was specified if {![tcl::dict::get $opts -overflow]} { - #lappend outputlines [tcl::string::range $overtext 0 [expr {$colwidth - 1}]] - #set overtext [tcl::string::range $overtext 0 $colwidth-1 ] + #lappend outputlines [tcl::string::range $overtext 0 [expr {$renderwidth - 1}]] + #set overtext [tcl::string::range $overtext 0 $renderwidth-1 ] if {$opt_ellipsis} { set show_ellipsis 1 if {!$opt_ellipsiswhitespace} { @@ -1286,12 +1358,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] set left_exposed $under_exposed_max @@ -1307,8 +1378,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1336,10 +1407,17 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline\ + -info 1\ + -insert_mode 0\ + -transparent $opt_transparent\ + -exposed1 $opt_exposed1 -exposed2 $opt_exposed2\ + -overflow $opt_overflow\ + -startcolumn [expr {1 + $startoffset}]\ + $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] if {!$opt_overflow} { @@ -1364,7 +1442,7 @@ tcl::namespace::eval overtype { #padded overtext #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -expand_right $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] lappend outputlines [tcl::dict::get $rinfo result] } set replay_codes [tcl::dict::get $rinfo replay_codes] @@ -1433,12 +1511,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] switch -- $opt_blockalign { left { @@ -1484,8 +1561,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1513,10 +1590,10 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -expand_right $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] @@ -1564,8 +1641,9 @@ tcl::namespace::eval overtype { } else { #padded overtext #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] - #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #Note - we still need expand_right here - as although the overtext is short - it may oveflow due to the startoffset + set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -expand_right $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #puts stderr "--> [ansistring VIEW -lf 1 -nul 1 $rinfo] <--" set overflow_right [tcl::dict::get $rinfo overflow_right] set unapplied [tcl::dict::get $rinfo unapplied] lappend outputlines [tcl::dict::get $rinfo result] @@ -1586,7 +1664,8 @@ tcl::namespace::eval overtype { #-returnextra enables returning of overflow and length #review - use punk::ansi::ta::detect to short-circuit processing and do simpler string calcs as an optimisation? #review - DECSWL/DECDWL double width line codes - very difficult/impossible to align and compose with other elements - #(could render it by faking it with sixels and a lot of work - find/make a sixel font and ensure it's exactly 2 cols per char) + #(could render it by faking it with sixels and a lot of work - find/make a sixel font and ensure it's exactly 2 cols per char? + # This would probably be impractical to support for different fonts) #todo - review transparency issues with single/double width characters #bidi - need a base direction and concept of directional runs for RTL vs LTR - may be best handled at another layer? proc renderline {args} { @@ -1608,8 +1687,10 @@ tcl::namespace::eval overtype { #[para] The main 3 are the result, overflow_right, and unapplied. #[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation. + #puts stderr "renderline '$args'" + if {[llength $args] < 2} { - error {usage: ?-info 0|1? ?-startcolumn ? ?-cursor_column ? ?-cursor_row |""? ?-transparent [0|1|]? ?-overflow [1|0]? undertext overtext} + error {usage: ?-info 0|1? ?-startcolumn ? ?-cursor_column ? ?-cursor_row |""? ?-transparent [0|1|]? ?-expand_right [1|0]? undertext overtext} } lassign [lrange $args end-1 end] under over if {[string first \n $under] >= 0} { @@ -1623,12 +1704,13 @@ tcl::namespace::eval overtype { set opts [tcl::dict::create\ -etabs 0\ -width \uFFEF\ - -overflow 0\ + -expand_right 0\ -transparent 0\ -startcolumn 1\ -cursor_column 1\ -cursor_row ""\ -insert_mode 1\ + -crm_mode 0\ -autowrap_mode 1\ -reverse_mode 0\ -info 0\ @@ -1643,13 +1725,15 @@ tcl::namespace::eval overtype { #cursor_row, when numeric will allow detection of certain row moves that are still within our row - allowing us to avoid an early return #An empty string for cursor_row tells us we have no info about our own row context, and to return with an unapplied string if any row move occurs - #exposed1 and exposed2 for first and second col of underying 2wide char which is truncated by transparency or overflow + #exposed1 and exposed2 for first and second col of underying 2wide char which is truncated by transparency, currsor movements to 2nd charcol, or overflow/expand_right #todo - return info about such grapheme 'cuts' in -info structure and/or create option to raise an error set argsflags [lrange $args 0 end-2] tcl::dict::for {k v} $argsflags { switch -- $k { - -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -autowrap_mode - -reverse_mode - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { + -experimental - -cp437 - -width - -expand_right - -transparent - -startcolumn - -cursor_column - -cursor_row + - -crm_mode - -insert_mode - -autowrap_mode - -reverse_mode + - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { tcl::dict::set opts $k $v } default { @@ -1660,7 +1744,7 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_width [tcl::dict::get $opts -width] set opt_etabs [tcl::dict::get $opts -etabs] - set opt_overflow [tcl::dict::get $opts -overflow] + set opt_expand_right [tcl::dict::get $opts -expand_right] set opt_colstart [tcl::dict::get $opts -startcolumn] ;#lhs limit for overlay - an offset to cursor_column - first visible column is 1. 0 or < 0 are before the start of the underlay set opt_colcursor [tcl::dict::get $opts -cursor_column];#start cursor column relative to overlay set opt_row_context [tcl::dict::get $opts -cursor_row] @@ -1676,20 +1760,11 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_autowrap_mode [tcl::dict::get $opts -autowrap_mode] ;#DECAWM - char or movement can go beyond leftmost/rightmost col to prev/next line set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] ;#DECSNM + set opt_crm_mode [tcl::dict::get $opts -crm_mode];# CRM - show control character mode # -- --- --- --- --- --- --- --- --- --- --- --- set temp_cursor_saved [tcl::dict::get $opts -cursor_restore_attributes] - set test_mode 0 set cp437_glyphs [tcl::dict::get $opts -cp437] - foreach e [tcl::dict::get $opts -experimental] { - switch -- $e { - test_mode { - set test_mode 1 - set cp437_glyphs 1 - } - } - } - set test_mode 1 ;#try to elminate set cp437_map [tcl::dict::create] if {$cp437_glyphs} { set cp437_map [set ::punk::ansi::cp437_map] @@ -1721,6 +1796,10 @@ tcl::namespace::eval overtype { set cursor_row $opt_row_context } + set insert_mode $opt_insert_mode ;#default 1 + set autowrap_mode $opt_autowrap_mode ;#default 1 + set crm_mode $opt_crm_mode ;#default 0 (Show Control Character mode) + set reverse_mode $opt_reverse_mode #----- # @@ -1768,13 +1847,14 @@ tcl::namespace::eval overtype { } set understacks [list] set understacks_gx [list] + set pm_list [list] set i_u -1 ;#underlay may legitimately be empty set undercols [list] set u_codestack [list] #u_gx_stack probably isn't really a stack - I don't know if g0 g1 can stack or not - for now we support only g0 anyway set u_gx_stack [list] ;#separate stack for g0 (g1 g2 g3?) graphics on and off (DEC special graphics) - #set pt_underchars "" ;#for string_columns length calculation for overflow 0 truncation + #set pt_underchars "" ;#for string_columns length calculation for expand_right 0 truncation set remainder [list] ;#for returnextra foreach {pt code} $undermap { #pt = plain text @@ -1834,6 +1914,7 @@ tcl::namespace::eval overtype { #underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc + #keep any remaining PMs in place if {$code ne ""} { set c1c2 [tcl::string::range $code 0 1] @@ -1841,6 +1922,8 @@ tcl::namespace::eval overtype { \x1b\[ 7CSI\ \x9b 8CSI\ \x1b\( 7GFX\ + \x1b^ 7PMX\ + \x1bX 7SOS\ ] $c1c2] 0 3];# leadernorm is 1st 2 chars mapped to normalised indicator - or is original 2 chars switch -- $leadernorm { @@ -1875,6 +1958,26 @@ tcl::namespace::eval overtype { } } } + 7PMX - 7SOS { + #we can have PMs or SOS (start of string) in the underlay - though mostly the PMs should have been processed.. + #attach the PM/SOS (entire ANSI sequence) to the previous grapheme! + #It should not affect the size - but terminal display may get thrown out if terminal doesn't support them. + + #note that there may in theory already be ANSI stored - we don't assume it was a pure grapheme string + set graphemeplus [lindex $undercols end] + if {$graphemeplus ne "\0"} { + append graphemeplus $code + } else { + set graphemeplus $code + } + lset undercols end $graphemeplus + #The grapheme_width_cached function will be called on this later - and doesn't account for ansi. + #we need to manually cache the item with it's proper width + variable grapheme_widths + #stripped and plus version keys pointing to same length + dict set grapheme_widths $graphemeplus [grapheme_width_cached [::punk::ansi::ansistrip $graphemeplus]] + + } default { } @@ -1895,51 +1998,29 @@ tcl::namespace::eval overtype { #consider also if there are other codes that should be stacked..? } - if {!$test_mode} { - #fill columns to width with spaces, and carry over stacks - we will have to keep track of where the underlying data ends manually - TODO - #Specifying a width is suitable for terminal-like applications and text-blocks - if {$opt_width ne "\uFFEF"} { - if {[llength $understacks]} { - set cs $u_codestack - set gs $u_gx_stack - } else { - set cs [list] - set gs [list] - } - if {[llength $undercols]< $opt_width} { - set diff [expr {$opt_width- [llength $undercols]}] - if {$diff > 0} { - lappend undercols {*}[lrepeat $diff " "] - lappend understacks {*}[lrepeat $diff $cs] - lappend understacks_gx {*}[lrepeat $diff $gs] - } - } + #NULL empty cell indicator + if {$opt_width ne "\uFFEF"} { + if {[llength $understacks]} { + set cs $u_codestack + set gs $u_gx_stack + } else { + set cs [list] + set gs [list] } - } else { - #NULL empty cell indicator - if {$opt_width ne "\uFFEF"} { - if {[llength $understacks]} { - set cs $u_codestack - set gs $u_gx_stack - } else { - set cs [list] - set gs [list] - } - if {[llength $undercols]< $opt_width} { - set diff [expr {$opt_width- [llength $undercols]}] - if {$diff > 0} { - lappend undercols {*}[lrepeat $diff "\u0000"] - lappend understacks {*}[lrepeat $diff $cs] - lappend understacks_gx {*}[lrepeat $diff $gs] - } + if {[llength $undercols]< $opt_width} { + set diff [expr {$opt_width- [llength $undercols]}] + if {$diff > 0} { + lappend undercols {*}[lrepeat $diff "\u0000"] + lappend understacks {*}[lrepeat $diff $cs] + lappend understacks_gx {*}[lrepeat $diff $gs] } } - } + if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } else { - set colwidth [llength $undercols] + set renderwidth [llength $undercols] } @@ -2017,12 +2098,34 @@ tcl::namespace::eval overtype { } append pt_overchars $pt #will get empty pt between adjacent codes - foreach grapheme [punk::char::grapheme_split $pt] { - lappend overstacks $o_codestack - lappend overstacks_gx $o_gxstack - incr i_o - lappend overlay_grapheme_control_list [list g $grapheme] - lappend overlay_grapheme_control_stacks $o_codestack + if {!$crm_mode} { + foreach grapheme [punk::char::grapheme_split $pt] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } else { + set tsbegin [clock micros] + foreach grapheme_original [punk::char::grapheme_split $pt] { + set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original] + #puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm" + foreach grapheme [punk::char::grapheme_split $pt_crm] { + if {$grapheme eq "\n"} { + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"] + } else { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + } + set elapsed [expr {[clock micros] - $tsbegin}] + puts stderr "ptlen [string length $pt] elapsedus:$elapsed" } #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc @@ -2030,40 +2133,91 @@ tcl::namespace::eval overtype { # that pure resets are fairly common - more so than leading resets with other info # that non-sgr codes are not that common, so ok to check for resets before verifying it is actually SGR at all. if {$code ne ""} { - lappend overlay_grapheme_control_stacks $o_codestack - #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) - if {[punk::ansi::codetype::is_sgr_reset $code]} { - set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set o_codestack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #basic simplification first - remove straight dupes - set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars - set o_codestack [lremove $o_codestack {*}$dup_posns] - lappend o_codestack $code - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[regexp {\x1b7|\x1b\[s} $code]} { - #experiment - #cursor_save - for the replays review. - #jmn - #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] - lappend overlay_grapheme_control_list [list other $code] - } elseif {[regexp {\x1b8|\x1b\[u} $code]} { - #experiment - #cursor_restore - for the replays - set o_codestack [list $temp_cursor_saved] - lappend overlay_grapheme_control_list [list other $code] + #we need to immediately set crm_mode here if \x1b\[3h received + if {$code eq "\x1b\[3h"} { + set crm_mode 1 + } elseif {$code eq "\x1b\[3l"} { + set crm_mode 0 + } + #else crm_mode could be set either way from options + if {$crm_mode && $code ne "\x1b\[00001E"} { + #treat the code as type 'g' like above - only allow through codes to reset mode REVIEW for now just \x1b\[3l ? + #we need to somehow convert further \n in the graphical rep to an instruction for newline that will bypass further crm_mode processing or we would loop. + set code_as_pt [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $code] + #split using standard split for first foreach loop - grapheme based split when processing 2nd foreach loop + set chars [split $code_as_pt ""] + set codeparts [list] ;#list of 2-el lists each element {crmcontrol } or {g } + foreach c $chars { + if {$c eq "\n"} { + #use CNL (cursor next line) \x1b\[00001E ;#leading zeroes ok for this processor - used as debugging aid to distinguish + lappend codeparts [list crmcontrol "\x1b\[00001E"] + } else { + if {[llength $codeparts] > 0 && [lindex $codeparts end 0] eq "g"} { + set existing [lindex $codeparts end 1] + lset codeparts end [list g [string cat $existing $c]] + } else { + lappend codeparts [list g $c] + } + } + } + + set partidx 0 + foreach record $codeparts { + lassign $record rtype rval + switch -exact -- $rtype { + g { + append pt_overchars $rval + foreach grapheme [punk::char::grapheme_split $rval] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + crmcontrol { + #leave o_codestack + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol $rval] + } + } + } } else { - if {[punk::ansi::codetype::is_gx_open $code]} { - set o_gxstack [list "gx0_on"] - lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } elseif {[punk::ansi::codetype::is_gx_close $code]} { - set o_gxstack [list] - lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } else { + lappend overlay_grapheme_control_stacks $o_codestack + #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) + if {[punk::ansi::codetype::is_sgr_reset $code]} { + set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set o_codestack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #basic simplification first - remove straight dupes + set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars + set o_codestack [lremove $o_codestack {*}$dup_posns] + lappend o_codestack $code + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[regexp {\x1b7|\x1b\[s} $code]} { + #experiment + #cursor_save - for the replays review. + #jmn + #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] + lappend overlay_grapheme_control_list [list other $code] + } elseif {[regexp {\x1b8|\x1b\[u} $code]} { + #experiment + #cursor_restore - for the replays + set o_codestack [list $temp_cursor_saved] lappend overlay_grapheme_control_list [list other $code] + } else { + if {[punk::ansi::codetype::is_gx_open $code]} { + set o_gxstack [list "gx0_on"] + lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } elseif {[punk::ansi::codetype::is_gx_close $code]} { + set o_gxstack [list] + lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } else { + lappend overlay_grapheme_control_list [list other $code] + } } } } @@ -2089,11 +2243,12 @@ tcl::namespace::eval overtype { # -- --- --- #we need to initialise overflow_idx before any potential row-movements - as they need to perform a loop break and force in_excess to 1 - if {$opt_overflow} { - #somewhat counterintuitively - overflow true means we can have lines as long as we want, but either way there can be excess data that needs to be thrown back to the calling loop. + if {$opt_expand_right} { + #expand_right true means we can have lines as long as we want, but either way there can be excess data that needs to be thrown back to the calling loop. + #we currently only support horizontal expansion to the right (review regarding RTL text!) set overflow_idx -1 } else { - #overflow zero - we can't grow beyond our column width - so we get ellipsis or truncation + #expand_right zero - we can't grow beyond our column width - so we get ellipsis or truncation if {$opt_width ne "\uFFEF"} { set overflow_idx [expr {$opt_width}] } else { @@ -2134,10 +2289,7 @@ tcl::namespace::eval overtype { #movements only occur within the overlay range. #an underlay is however not necessary.. e.g - #renderline -overflow 1 "" data - #foreach {pt code} $overmap {} - set insert_mode $opt_insert_mode ;#default 1 - set autowrap_mode $opt_autowrap_mode ;#default 1 + #renderline -expand_right 1 "" data #set re_mode {\x1b\[\?([0-9]*)(h|l)} ;#e.g DECAWM #set re_col_move {\x1b\[([0-9]*)(C|D|G)$} @@ -2163,13 +2315,28 @@ tcl::namespace::eval overtype { switch -- $type { g { set ch $item + #crm_mode affects both graphic and control + if {0 && $crm_mode} { + set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $ch] + set chars [string map [list \n "\x1b\[00001E"] $chars] + if {[llength [split $chars ""]] > 1} { + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + #incr idx_over + break + } else { + set ch $chars + } + } incr idx_over; #idx_over (until unapplied reached anyway) is per *grapheme* in the overlay - not per col. if {($idx < ($opt_colstart -1))} { incr idx [grapheme_width_cached $ch] continue } #set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our active data width - set within_undercols [expr {$idx <= $colwidth-1}] + set within_undercols [expr {$idx <= $renderwidth-1}] #https://www.enigma.com/resources/blog/the-secret-world-of-newline-characters #\x85 NEL in the c1 control set is treated by some terminal emulators (e.g Hyper) as a newline, @@ -2194,7 +2361,7 @@ tcl::namespace::eval overtype { #linefeed after final column #puts "---c at overflow_idx=$overflow_idx" incr cursor_row - set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2 + set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to expand_right = 1 set instruction lf_overflow ;#only special treatment is to give it it's own instruction in case caller needs to handle differently priv::render_unapplied $overlay_grapheme_control_list $gci break @@ -2202,7 +2369,10 @@ tcl::namespace::eval overtype { #linefeed occurred in middle or at end of text #puts "---mid-or-end-text-linefeed idx:$idx overflow_idx:$overflow_idx" incr cursor_row - set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2 + if {$idx == -1 || $overflow_idx > $idx} { + #don't set overflow_idx higher if it's already set lower and we're adding graphemes to overflow + set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to expand_right = 1 + } set instruction lf_mid priv::render_unapplied $overlay_grapheme_control_list $gci break @@ -2284,23 +2454,35 @@ tcl::namespace::eval overtype { #tab of some length dependent on tabstops/elastic tabstop settings? } } elseif {$idx >= $overflow_idx} { - #jmn? - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci-1]] - #set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #don't incr idx beyond the overflow_idx - #idx_over already incremented - decrement so current overlay grapheme stacks go to unapplied - incr idx_over -1 - #priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#back one index here too - priv::render_this_unapplied $overlay_grapheme_control_list $gci ;# - set instruction overflow - break + #REVIEW + set next_gc [lindex $overlay_grapheme_control_list $gci+1] ;#next grapheme or control + lassign $next_gc next_type next_item + if {$autowrap_mode || $next_type ne "g"} { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci-1]] + #set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #don't incr idx beyond the overflow_idx + #idx_over already incremented - decrement so current overlay grapheme stacks go to unapplied + incr idx_over -1 + #priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#back one index here too + priv::render_this_unapplied $overlay_grapheme_control_list $gci ;# + set instruction overflow + break + } else { + #no point throwing back to caller for each grapheme that is overflowing + #without this branch - renderline would be called with overtext reducing only by one grapheme per call + #processing a potentially long overtext each time (ie - very slow) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #JMN4 + + } } } else { #review. - #This corresponds to opt_overflow being true (at least until overflow_idx is in some cases forced to a value when throwing back to calling loop) + #overflow_idx = -1 + #This corresponds to expand_right being true (at least until overflow_idx is in some cases forced to a value when throwing back to calling loop) } - if {($do_transparency && [regexp $opt_transparent $ch])} { + if {($do_transparency && [regexp $opt_transparent $ch])} { #pre opt_colstart is effectively transparent (we have applied padding of required number of columns to left of overlay) if {$idx > [llength $outcols]-1} { lappend outcols " " @@ -2311,6 +2493,7 @@ tcl::namespace::eval overtype { } else { #todo - punk::char::char_width set g [lindex $outcols $idx] + #JMN set uwidth [grapheme_width_cached $g] if {[lindex $outcols $idx] eq ""} { #2nd col of 2-wide char in underlay @@ -2438,7 +2621,7 @@ tcl::namespace::eval overtype { } incr idx } - if {($cursor_column < [llength $outcols]) || $overflow_idx == -1 || $test_mode} { + if {($cursor_column < [llength $outcols]) || $overflow_idx == -1} { incr cursor_column } } elseif {$uwidth > 1} { @@ -2472,12 +2655,6 @@ tcl::namespace::eval overtype { priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode incr idx incr cursor_column - if {$overflow_idx !=-1 && !$test_mode} { - #overflow - if {$cursor_column > [llength $outcols]} { - set cursor_column [llength $outcols] - } - } } } } @@ -2485,13 +2662,29 @@ tcl::namespace::eval overtype { } - other { + other - crmcontrol { + if {$crm_mode && $type ne "crmcontrol" && $item ne "\x1b\[00001E"} { + if {$item eq "\x1b\[3l"} { + set crm_mode 0 + } else { + #When our initial overlay split was done - we weren't in crm_mode - so there are codes that weren't mapped to unicode control character representations + #set within_undercols [expr {$idx <= $renderwidth-1}] + #set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $item] + set chars [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $item] + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + + break + } + } + #todo - consider CSI s DECSLRM vs ansi.sys \x1b\[s - we need \x1b\[s for oldschool ansi art - but may have to enable only for that. - #we should probably therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore + #we should possibly therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore? set code [tcl::string::map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $item] #since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied' - set matchinfo [list] #remap of DEC cursor_save/cursor_restore from ESC sequence to equivalent CSI #probably not ideal - consider putting cursor_save/cursor_restore in functions so they can be called from the appropriate switch branch instead of using this mapping @@ -2501,15 +2694,16 @@ tcl::namespace::eval overtype { set c1c2c3 [tcl::string::range $code 0 2] #set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)} #tcl 8.7 - faster to use inline list than to store it in a local var outside of loop. - #(surprising - but presumably ) + #(somewhat surprising) set leadernorm [tcl::string::range [tcl::string::map [list\ \x1b\[< 1006\ \x1b\[ 7CSI\ + \x1bP 7DCS\ \x9b 8CSI\ \x1b\] 7OSC\ \x9d 8OSC\ \x1b 7ESC\ - ] $c1c2c3] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars + ] $c1c2c3] 0 3] ;#leadernorm is 1st 1,2 or 3 chars mapped to 4char normalised indicator - or is original first chars (1,2 or 3 len) #we leave the tail of the code unmapped for now switch -- $leadernorm { @@ -2521,6 +2715,11 @@ tcl::namespace::eval overtype { 7CSI - 7OSC { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]] } + 7DCS { + #ESC P + #Device Control String https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Controls-beginning-with-ESC:ESC-F.C74 + set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]] + } 7ESC { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } @@ -2528,7 +2727,10 @@ tcl::namespace::eval overtype { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } default { + puts stderr "Sequence detected as ANSI, but not handled in leadernorm switch. code: [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" #we haven't made a mapping for this + #could in theory be 1,2 or 3 in len + #although we shouldn't be getting here if the regexp for ansi codes is kept in sync with our switch branches set codenorm $code } } @@ -2551,44 +2753,44 @@ tcl::namespace::eval overtype { {7CSI} - {8CSI} { set param [tcl::string::range $codenorm 4 end-1] #puts stdout "--> CSI [tcl::string::index $leadernorm 0] bit param:$param" - switch -- [tcl::string::index $codenorm end] { - D { - #Col move - #puts stdout "<-back" - #cursor back - #left-arrow/move-back when ltr mode + set code_end [tcl::string::index $codenorm end] ;#used for e.g h|l set/unset mode + switch -exact -- $code_end { + A { + #Row move - up + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set num $param if {$num eq ""} {set num 1} + incr cursor_row -$num - set version 2 - if {$version eq "2"} { - #todo - startcolumn offset! - if {$cursor_column - $num >= 1} { - incr idx -$num - incr cursor_column -$num - } else { - if {!$autowrap_mode} { - set cursor_column 1 - set idx 0 - } else { - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - incr cursor_column -$num - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction wrapmovebackward - break - } - } - } else { - incr idx -$num - incr cursor_column -$num - if {$idx < $opt_colstart-1} { - #wrap to previous line and position cursor at end of data - set idx [expr {$opt_colstart-1}] - set cursor_column $opt_colstart - } + if {$cursor_row < 1} { + set cursor_row 1 } + + #ensure rest of *overlay* is emitted to remainder + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction up + #retain cursor_column + break + } + B { + #CUD - Cursor Down + #Row move - down + set num $param + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #move down + if {$num eq ""} {set num 1} + incr cursor_row $num + + + incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction down + #retain cursor_column + break } C { + #CUF - Cursor Forward #Col move #puts stdout "->forward" #todo - consider right-to-left cursor mode (e.g Hebrew).. some day. @@ -2610,7 +2812,7 @@ tcl::namespace::eval overtype { if {$overflow_idx == -1} { incr max } - if {$test_mode && $cursor_column == $max+1} { + if {$cursor_column == $max+1} { #move_forward while in overflow incr cursor_column -1 } @@ -2627,7 +2829,7 @@ tcl::namespace::eval overtype { } #horizontal movement beyond line extent needs to wrap - throw back to caller - #we may have both overflow_rightand unapplied data + #we may have both overflow_right and unapplied data #(can have overflow_right if we were in insert_mode and processed chars prior to this movement) #leave row as is - caller will need to determine how many rows the column-movement has consumed incr cursor_column $num ;#give our caller the necessary info as columns from start of row @@ -2642,7 +2844,8 @@ tcl::namespace::eval overtype { } } } else { - if {!$opt_overflow || ($cursor_column + $num) <= [llength $outcols+1]} { + #review - dead branch + if {!$expand_right || ($cursor_column + $num) <= [llength $outcols+1]} { incr idx $num incr cursor_column $num } else { @@ -2692,85 +2895,294 @@ tcl::namespace::eval overtype { } } } - G { + D { #Col move - #move absolute column - #adjust to colstart - as column 1 is within overlay - #??? - set idx [expr {$param + $opt_colstart -1}] - set cursor_column $param - error "renderline absolute col move ESC G unimplemented" - } - A { - #Row move - up - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #puts stdout "<-back" + #cursor back + #left-arrow/move-back when ltr mode set num $param if {$num eq ""} {set num 1} - incr cursor_row -$num - if {$cursor_row < 1} { - set cursor_row 1 + set version 2 + if {$version eq "2"} { + #todo - startcolumn offset! + if {$cursor_column - $num >= 1} { + incr idx -$num + incr cursor_column -$num + } else { + if {!$autowrap_mode} { + set cursor_column 1 + set idx 0 + } else { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr cursor_column -$num + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction wrapmovebackward + break + } + } + } else { + incr idx -$num + incr cursor_column -$num + if {$idx < $opt_colstart-1} { + #wrap to previous line and position cursor at end of data + set idx [expr {$opt_colstart-1}] + set cursor_column $opt_colstart + } } - - #ensure rest of *overlay* is emitted to remainder + } + E { + #CNL - Cursor Next Line + if {$param eq ""} { + set downmove 1 + } else { + set downmove [expr {$param}] + } + puts stderr "renderline CNL down-by-$downmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row + $downmove}] + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction up - #retain cursor_column - break + set instruction move + break + } - B { - #Row move - down - set num $param + F { + #CPL - Cursor Previous Line + if {$param eq ""} { + set upmove 1 + } else { + set upmove [expr {$param}] + } + puts stderr "renderline CPL up-by-$upmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row -$upmove}] + if {$cursor_row < 1} { + set cursor_row 1 + } + set idx [expr {$cursor_column - 1}] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #move down - if {$num eq ""} {set num 1} - incr cursor_row $num - - - incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction down - #retain cursor_column - break + set instruction move + break + + } + G { + #CHA - Cursor Horizontal Absolute (move to absolute column no) + if {$param eq ""} { + set targetcol 1 + } else { + set targetcol $param + if {![string is integer -strict $targetcol]} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Unrecognised parameter '$param'" + } + set targetcol [expr {$param}] + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$targetcol > $max} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Param '$param' > max: $max" + set targetcol $max + } + } + #adjust to colstart - as column 1 is within overlay + #??? REVIEW + set idx [expr {($targetcol -1) + $opt_colstart -1}] + + + set cursor_column $targetcol + #puts stderr "renderline absolute col move ESC G (TEST)" } H - f { - #$re_both_move - lassign [split $param {;}] row col - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #lassign $matchinfo _match row col + #CSI n;m H - CUP - Cursor Position - if {$col eq ""} {set col 1} - set max [llength $outcols] - if {$overflow_idx == -1} { - incr max - } - if {$col > $max} { - set cursor_column $max + #CSI n;m f - HVP - Horizontal Vertical Position REVIEW - same as CUP with differences (what?) in some terminal modes + # - 'counts as effector format function (like CR or LF) rather than an editor function (like CUD or CNL)' + # - REVIEW + #see Annex A at: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf + + #test e.g ansicat face_2.ans + #$re_both_move + lassign [split $param {;}] paramrow paramcol + #missing defaults to 1 + #CSI ;5H = CSI 1;5H -> row 1 col 5 + #CSI 17;H = CSI 17H = CSI 17;1H -> row 17 col 1 + + if {$paramcol eq ""} {set paramcol 1} + if {$paramrow eq ""} {set paramrow 1} + if {![string is integer -strict $paramcol] || ![string is integer -strict $paramrow]} { + puts stderr "renderline CUP (CSI H) unrecognised param $param" + #ignore? } else { - set cursor_column $col + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$paramcol > $max} { + set target_column $max + } else { + set target_column [expr {$paramcol}] + } + + + if {$paramrow < 1} { + puts stderr "renderline CUP (CSI H) bad row target 0. Assuming 1" + set target_row 1 + } else { + set target_row [expr {$paramrow}] + } + if {$target_row == $cursor_row} { + #col move only - no need for break and move + #puts stderr "renderline CUP col move only to col $target_column param:$param" + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + } else { + set cursor_row $target_row + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } } - set idx [expr {$cursor_column -1}] + } + J { + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? + switch -exact -- $modegroup { + ? { + #CSI ? Pn J - selective erase + puts stderr "overtype::renderline ED - SELECTIVE ERASE IN DISPLAY (UNIMPLEMENTED) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + default { + puts stderr "overtype::renderline ED - ERASE IN DISPLAY (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of screen + } + 1 { + #clear from cursor to beginning of screen + } + 2 { + #clear entire screen + #ansi.sys - move cursor to upper left REVIEW + set cursor_row 1 + set cursor_column 1 + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } + 3 { + #clear entire screen. presumably cursor doesn't move - otherwise it would be same as 2J ? - if {$row eq ""} {set row 1} - set cursor_row $row - if {$cursor_row < 1} { - set cursor_row 1 + } + default { + } + } + + } } + } + K { + #see DECECM regarding background colour + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? + switch -exact -- $modegroup { + ? { + puts stderr "overtype::renderline DECSEL - SELECTIVE ERASE IN LINE (UNIMPLEMENTED) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + set param [string range $param 1 end] ;#chop qmark + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line - depending on DECSCA + } + 1 { + #clear from cursor to beginning of line - depending on DECSCA - incr idx_over - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction move - break + } + 2 { + #clear entire line - depending on DECSCA + } + default { + puts stderr "overtype::renderline DECSEL - SELECTIVE ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line + } + 1 { + #clear from cursor to beginning of line + + } + 2 { + #clear entire line + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + } + } + } + L { + puts stderr "overtype::renderline IL - Insert Line - not implemented [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + M { + #CSI Pn M - DL - Delete Line + puts stderr "overtype::renderline DL - Delete Line - not implemented [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" } X { - puts stderr "X - $param" + puts stderr "overtype::renderline X ECH ERASE CHARACTER - $param" #ECH - erase character if {$param eq "" || $param eq "0"} {set param 1}; #param=count of chars to erase priv::render_erasechar $idx $param #cursor position doesn't change. } + q { + set code_secondlast [tcl::string::index $codenorm end-1] + switch -exact -- $code_secondlast { + {"} { + #DECSCA - Select Character Protection Attribute + #(for use with selective erase: DECSED and DECSEL) + set param [tcl::string::range $codenorm 4 end-2] + if {$param eq ""} {set param 0} + #TODO - store like SGR in stacks - replays? + switch -exact -- $param { + 0 - 2 { + #canerase + puts stderr "overtype::renderline - DECSCA canerase not implemented - [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + 1 { + #cannoterase + puts stderr "overtype::renderline - DECSCA cannoterase not implemented - [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + default { + puts stderr "overtype::renderline DECSCA param '$param' not understood [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + + } + default { + puts stderr "overtype::renderline - CSI ... q not implemented - [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + + } r { #$re_decstbm #https://www.vt100.net/docs/vt510-rm/DECSTBM.html @@ -2789,78 +3201,119 @@ tcl::namespace::eval overtype { break } s { - # - todo - make ansi.sys CSI s cursor save only apply for certain cases? - may need to support DECSLRM instead which uses same code - - #$re_cursor_save - #cursor save could come after last column - if {$overflow_idx != -1 && $idx == $overflow_idx} { - #bartman2.ans test file - fixes misalignment at bottom of dialog bubble - #incr cursor_row - #set cursor_column 1 - #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) - set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] - } else { - set cursor_saved_position [list row $cursor_row column $cursor_column] - } - #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. - #we need the SGR and gx overlay codes prior to the cursor_save + #code conflict between ansi emulation and DECSLRM - REVIEW + #ANSISYSSC (when no parameters) - like other terminals - essentially treat same as DECSC + # todo - when parameters - support DECSLRM instead + + if {$param ne ""} { + #DECSLRM - should only be recognised if DECLRMM is set (vertical split screen mode) + lassign [split $param {;} margin_left margin_right + puts stderr "overtype DECSLRM not yet supported - got [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$margin_left eq ""} { + set margin_left 1 + } + set columns_per_page 80 ;#todo - set to 'page width (DECSCPP set columns per page)' - could be 132 or?? + if {$margin_right eq ""} { + set margin_right $columns_per_page + } + puts stderr "DECSLRM margin left: $margin_left margin right: $margin_right" + if {![string is integer -strict $margin_left] || $margin_left < 0} { + puts stderr "DECSLRM invalid margin_left" + } + if {![string is integer -strict $margin_right] || $margin_right < 0} { + puts stderr "DECSLRM invalid margin_right" + } + set scrolling_region_size [expr {$margin_right - $margin_left}] + if {$scrolling_region_size < 2 || $scrolling_region_size > $columns_per_page} { + puts stderr "DECSLRM region size '$scrolling_regsion_size' must be between 1 and $columns_per_page" + } + #todo - #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. - #set sgr_stack [lindex $understacks $idx] - #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) - - set sgr_stack [list] - set gx_stack [list] - - #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. - #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. - - foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { - lassign $gc type code - #types g other sgr gx0 - switch -- $type { - gx0 { - #code is actually a stand-in for the graphics on/off code - not the raw code - #It is either gx0_on or gx0_off - set gx_stack [list $code] - } - sgr { - #code is the raw code - if {[punk::ansi::codetype::is_sgr_reset $code]} { - #jmn - set sgr_stack [list "\x1b\[m"] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set sgr_stack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #often we don't get resets - and codes just pile up. - #as a first step to simplifying - at least remove earlier straight up dupes - set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) - set sgr_stack [lremove $sgr_stack {*}$dup_posns] - lappend sgr_stack $code + + } else { + #DECSC + #//notes on expected behaviour: + #DECSC - saves following items in terminal's memory + #cursor position + #character attributes set by the SGR command + #character sets (G0,G1,G2 or G3) currently in GL and GR + #Wrap flag (autowrap or no autowrap) + #State of origin mode (DECOM) + #selective erase attribute + #any single shift 2 (SS2) or single shift 3(SSD) functions sent + + #$re_cursor_save + #cursor save could come after last column + if {$overflow_idx != -1 && $idx == $overflow_idx} { + #bartman2.ans test file - fixes misalignment at bottom of dialog bubble + #incr cursor_row + #set cursor_column 1 + #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) + set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] + } else { + set cursor_saved_position [list row $cursor_row column $cursor_column] + } + #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. + #we need the SGR and gx overlay codes prior to the cursor_save + + #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. + #set sgr_stack [lindex $understacks $idx] + #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) + + set sgr_stack [list] + set gx_stack [list] + + #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. + #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. + + foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { + lassign $gc type code + #types g other sgr gx0 + switch -- $type { + gx0 { + #code is actually a stand-in for the graphics on/off code - not the raw code + #It is either gx0_on or gx0_off + set gx_stack [list $code] + } + sgr { + #code is the raw code + if {[punk::ansi::codetype::is_sgr_reset $code]} { + #jmn + set sgr_stack [list "\x1b\[m"] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set sgr_stack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #often we don't get resets - and codes just pile up. + #as a first step to simplifying - at least remove earlier straight up dupes + set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) + set sgr_stack [lremove $sgr_stack {*}$dup_posns] + lappend sgr_stack $code + } } } } - } - set cursor_saved_attributes "" - switch -- [lindex $gx_stack 0] { - gx0_on { - append cursor_saved_attributes "\x1b(0" - } - gx0_off { - append cursor_saved_attributes "\x1b(B" + set cursor_saved_attributes "" + switch -- [lindex $gx_stack 0] { + gx0_on { + append cursor_saved_attributes "\x1b(0" + } + gx0_off { + append cursor_saved_attributes "\x1b(B" + } } - } - #append cursor_saved_attributes [join $sgr_stack ""] - append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] + #append cursor_saved_attributes [join $sgr_stack ""] + append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] - #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. + #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. - #don't incr index - or the save will cause cursor to move to the right - #carry on - + #don't incr index - or the save will cause cursor to move to the right + #carry on + } } u { + #ANSISYSRC save cursor (when no parameters) (DECSC) + #$re_cursor_restore #we are going to jump somewhere.. for now we will assume another line, and process accordingly. #The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line) @@ -2901,135 +3354,260 @@ tcl::namespace::eval overtype { set instruction restore_cursor break } + "{" { + + puts stderr "renderline warning - CSI.. - unimplemented [ansistring VIEW -lf 1 -nul 1 $code]" + } + "}" { + set code_secondlast [tcl::string::index $codenorm end-1] + switch -exact -- $code_secondlast { + ' { + puts stderr "renderline warning - DECIC - Insert Column - CSI...' - unimplemented [ansistring VIEW -lf 1 -nul 1 $code]" + } + default { + puts stderr "renderline warning - CSI.. - unimplemented [ansistring VIEW -lf 1 -nul 1 $code]" + } + } + } ~ { - #$re_vt_sequence - #lassign $matchinfo _match key mod - lassign [split $param {;}] key mod - - #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ - # - #e.g esc \[2~ insert esc \[2;2~ shift-insert - #mod - subtract 1, and then use bitmask - #shift = 1, (left)Alt = 2, control=4, meta=8 (meta seems to do nothing on many terminals on windows? Intercepted by windows?) - #puts stderr "vt key:$key mod:$mod code:[ansistring VIEW $code]" - if {$key eq "1"} { - #home - } elseif {$key eq "2"} { - #Insert - if {$mod eq ""} { - #no modifier key - set insert_mode [expr {!$insert_mode}] - #rather than set the cursor - we return the insert mode state so the caller can decide + set code_secondlast [tcl::string::index $codenorm end-1] ;#used for e.g CSI x '~ + switch -exact -- $code_secondlast { + ' { + #DECDC - editing sequence - Delete Column + puts stderr "renderline warning - DECDC - unimplemented" } - } elseif {$key eq "3"} { - #Delete - presumably this shifts other chars in the line, with empty cells coming in from the end - switch -- $mod { - "" { - priv::render_delchar $idx - } - "5" { - #ctrl-del - delete to end of word (pwsh) - possibly word on next line if current line empty(?) + default { + #$re_vt_sequence + lassign [split $param {;}] key mod + + #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ + # + #e.g esc \[2~ insert esc \[2;2~ shift-insert + #mod - subtract 1, and then use bitmask + #shift = 1, (left)Alt = 2, control=4, meta=8 (meta seems to do nothing on many terminals on windows? Intercepted by windows?) + #puts stderr "vt key:$key mod:$mod code:[ansistring VIEW $code]" + if {$key eq "1"} { + #home + } elseif {$key eq "2"} { + #Insert + if {$mod eq ""} { + #no modifier key + set insert_mode [expr {!$insert_mode}] + #rather than set the cursor - we return the insert mode state so the caller can decide + } + } elseif {$key eq "3"} { + #Delete - presumably this shifts other chars in the line, with empty cells coming in from the end + switch -- $mod { + "" { + priv::render_delchar $idx + } + "5" { + #ctrl-del - delete to end of word (pwsh) - possibly word on next line if current line empty(?) + } + } + } elseif {$key eq "4"} { + #End + } elseif {$key eq "5"} { + #pgup + } elseif {$key eq "6"} { + #pgDn + } elseif {$key eq "7"} { + #Home + #?? + set idx [expr {$opt_colstart -1}] + set cursor_column 1 + } elseif {$key eq "8"} { + #End + } elseif {$key eq "11"} { + #F1 - or ESCOP or e.g shift F1 ESC\[1;2P + } elseif {$key eq "12"} { + #F2 - or ESCOQ + } elseif {$key eq "13"} { + #F3 - or ESCOR + } elseif {$key eq "14"} { + #F4 - or ESCOS + } elseif {$key eq "15"} { + #F5 or shift F5 ESC\[15;2~ + } elseif {$key eq "17"} { + #F6 + } elseif {$key eq "18"} { + #F7 + } elseif {$key eq "19"} { + #F8 + } elseif {$key eq "20"} { + #F9 + } elseif {$key eq "21"} { + #F10 + } elseif {$key eq "23"} { + #F11 + } elseif {$key eq "24"} { + #F12 } + } - } elseif {$key eq "4"} { - #End - } elseif {$key eq "5"} { - #pgup - } elseif {$key eq "6"} { - #pgDn - } elseif {$key eq "7"} { - #Home - #?? - set idx [expr {$opt_colstart -1}] - set cursor_column 1 - } elseif {$key eq "8"} { - #End - } elseif {$key eq "11"} { - #F1 - or ESCOP or e.g shift F1 ESC\[1;2P - } elseif {$key eq "12"} { - #F2 - or ESCOQ - } elseif {$key eq "13"} { - #F3 - or ESCOR - } elseif {$key eq "14"} { - #F4 - or ESCOS - } elseif {$key eq "15"} { - #F5 or shift F5 ESC\[15;2~ - } elseif {$key eq "17"} { - #F6 - } elseif {$key eq "18"} { - #F7 - } elseif {$key eq "19"} { - #F8 - } elseif {$key eq "20"} { - #F9 - } elseif {$key eq "21"} { - #F10 - } elseif {$key eq "23"} { - #F11 - } elseif {$key eq "24"} { - #F12 } } h - l { + #set mode unset mode #we are matching only last char to get to this arm - but are there other sequences ending in h|l we need to handle? #$re_mode if first after CSI is "?" #some docs mention ESC=h|l - not seen on windows terminals.. review #e.g https://www2.math.upenn.edu/~kazdan/210/computer/ansi.html - if {[tcl::string::index $codenorm 4] eq "?"} { - set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l - #lassign $matchinfo _match num type - switch -- $num { - 5 { - #DECSNM - reverse video - #How we simulate this to render within a block of text is an open question. - #track all SGR stacks and constantly flip based on the current SGR reverse state? - #It is the job of the calling loop to do this - so at this stage we'll just set the states - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set reverse_mode 1 - } else { - #reset (disable) - set reverse_mode 0 - } + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? = + switch -exact -- $modegroup { + ? { + set smparams [tcl::string::range $codenorm 5 end-1] ;#params between ? and h|l + #one or more modes can be set + set smparam_list [split $smparams {;}] + foreach num $smparam_list { + switch -- $num { + "" { + #ignore empties e.g extra/trailing semicolon in params + } + 5 { + #DECSNM - reverse video + #How we simulate this to render within a block of text is an open question. + #track all SGR stacks and constantly flip based on the current SGR reverse state? + #It is the job of the calling loop to do this - so at this stage we'll just set the states + + if {$code_end eq "h"} { + #set (enable) + set reverse_mode 1 + } else { + #reset (disable) + set reverse_mode 0 + } + + } + 7 { + #DECAWM autowrap + if {$code_end eq "h"} { + #set (enable) + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } + #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? + # presume not usually - but sanity check with warning for now. + if {$idx >= $overflow_idx} { + puts stderr "renderline warning - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + } else { + #reset (disable) + set autowrap_mode 0 + #REVIEW! + set overflow_idx -1 + } + } + 25 { + if {$code_end eq "h"} { + #visible cursor + + } else { + #invisible cursor + } + } + 117 { + #DECECM - Erase Color Mode + #https://invisible-island.net/ncurses/ncurses.faq.html + #The Erase color selection controls the background color used when text is erased or new + #text is scrolled on to the screen. Screen background causes newly erased areas or + #scrolled text to be written using color index zero, the screen background. This is VT + #and DECterm compatible. Text background causes erased areas or scrolled text to be + #written using the current text background color. This is PC console compatible and is + #the factory default. + + #see also: https://unix.stackexchange.com/questions/251726/clear-to-end-of-line-uses-the-wrong-background-color-in-screen + } + } } - 7 { - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set autowrap_mode 1 - if {$opt_width ne "\uFFEF"} { - set overflow_idx $opt_width + } + = { + set num [tcl::string::range $codenorm 5 end-1] ;#param between = and h|l + puts stderr "overtype::renderline CSI=...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + #e.g CSI 4 h + set num [tcl::string::range $codenorm 4 end-1] ;#param before h|l + switch -exact -- $num { + 3 { + puts stderr "CRM MODE $code_end" + #CRM - Show control character mode + # 'No control functions are executed except LF,FF and VT which are represented in the CRM FONT before a CRLF(new line) is executed' + # + #use ansistring VIEW -nul 1 -lf 2 -ff 2 -vt 2 + #https://vt100.net/docs/vt510-rm/CRM.html + #NOTE - vt100 CRM always does auto-wrap at right margin. + #disabling auto-wrap in set-up or by sequence is disabled. + #We should default to turning off auto-wrap when crm_mode enabled.. but + #displaying truncated (on rhs) crm can still be very useful - and we have optimisation in overflow to avoid excess renderline calls (per grapheme) + #we therefore could reasonably put in an exception to allow auto_wrap to be disabled after crm_mode is engaged, + #although this would be potentially an annoying difference to some.. REVIEW + if {$code_end eq "h"} { + set crm_mode 1 + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } } else { - #review - this is also the cursor position when adding a char at end of line? - set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + set crm_mode 0 } - #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. - if {$idx >= $overflow_idx} { - puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + 4 { + #IRM - Insert/Replace Mode + if {$code_end eq "h"} { + #CSI 4 h + set insert_mode 1 + } else { + #CSI 4 l + #replace mode + set insert_mode 0 } - } else { - #reset (disable) - set autowrap_mode 0 - set overflow_idx -1 } + default { + puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + } + } + } + } + | { + switch -- [tcl::string::index $codenorm end-1] { + {$} { + #CSI ... $ | DECSCPP set columns per page- (recommended in vt510 docs as preferable to DECCOLM) + #real terminals generally only supported 80/132 + #some other virtuals support any where from 2 to 65,536? + #we will allow arbitrary widths >= 2 .. to some as yet undetermined limit. + #CSI $ | + #empty or 0 param is 80 for compatibility - other numbers > 2 accepted + set page_width -1 ;#flag as unset + if {$param eq ""} { + set page_width 80 + } elseif {[string is integer -strict $param] && $param >=2 0} { + set page_width [expr {$param}] ;#we should allow leading zeros in the number - but lets normalize using expr + } else { + puts stderr "overtype::renderline unacceptable DECSPP value '$param'" } - 25 { - if {$type eq "h"} { - #visible cursor - } else { - #invisible cursor + if {$page_width > 2} { + puts stderr "overtype::renderline DECSCPP - not implemented - but selected width '$page_width' looks ok" + #if cursor already beyond new page_width - will move to right colum - otherwise no cursor movement - } } - } - } else { - puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + puts stderr "overtype::renderline unrecognised CSI code ending in pipe (|) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } } } default { @@ -3038,24 +3616,49 @@ tcl::namespace::eval overtype { } } 7ESC { - #$re_other_single - switch -- [tcl::string::index $codenorm end] { + # + #re_other_single {\x1b(D|M|E)$} + #also PM \x1b^...(ST) + switch -- [tcl::string::index $codenorm 4] { + c { + #RIS - reset terminal to initial state - where 'terminal' in this case is the renderspace - not the underlying terminal! + puts stderr "renderline reset" + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction reset + break + } D { #\x84 #index (IND) #vt102-docs: "Moves cursor down one line in same column. If cursor is at bottom margin, screen performs a scroll-up" - puts stderr "ESC D not fully implemented" + puts stderr "renderline ESC D not fully implemented" incr cursor_row priv::render_unapplied $overlay_grapheme_control_list $gci set instruction down #retain cursor_column break } + E { + #\x85 + #review - is behaviour different to lf? + #todo - possibly(?) same logic as handling above. i.e return instruction depends on where column_cursor is at the time we get NEL + #leave implementation until logic for is set in stone... still under review + #It's arguable NEL is a pure cursor movement as opposed to the semantic meaning of crlf or lf in a file. + # + #Next Line (NEL) "Move the cursor to the left margin on the next line. If the cursor is at the bottom margin, scroll the page up" + puts stderr "overtype::renderline ESC E unimplemented" + + } + H { + #\x88 + #Tab Set + puts stderr "overtype::renderline ESC H tab set unimplemented" + } M { #\x8D #Reverse Index (RI) #vt102-docs: "Moves cursor up one line in same column. If cursor is at top margin, screen performs a scroll-down" - puts stderr "ESC M not fully implemented" + puts stderr "overtype::renderline ESC M not fully implemented" set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] #move up @@ -3069,31 +3672,89 @@ tcl::namespace::eval overtype { #retain cursor_column break } - E { - #\x85 - #review - is behaviour different to lf? - #todo - possibly(?) same logic as handling above. i.e return instruction depends on where column_cursor is at the time we get NEL - #leave implementation until logic for is set in stone... still under review - #It's arguable NEL is a pure cursor movement as opposed to the semantic meaning of crlf or lf in a file. - # - #Next Line (NEL) "Move the cursor to the left margin on the next line. If the cursor is at the bottom margin, scroll the page up" - puts stderr "ESC E unimplemented" + N { + #\x8e - affects next character only + puts stderr "overtype::renderline single shift select G2 command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + O { + #\x8f - affects next character only + puts stderr "overtype::renderline single shift select G3 command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + P { + #\x90 + #DCS - shouldn't get here - handled in 7DCS branch + #similarly \] OSC (\x9d) and \\ (\x9c) ST + } + V { + #\x96 } + W { + #\x97 + } + X { + #\x98 + #SOS + if {[string index $code end] eq "\007"} { + set sos_content [string range $code 2 end-1] ;#ST is \007 + } else { + set sos_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #return in some useful form to the caller + #TODO! + lappend sos_list [list string $sos_content row $cursor_row column $cursor_column] + puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + ^ { + #puts stderr "renderline PM" + #Privacy Message. + if {[string index $code end] eq "\007"} { + set pm_content [string range $code 2 end-1] ;#ST is \007 + } else { + set pm_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #We don't want to render it - but we need to make it available to the application + #see the textblock library in punk, for the exception we make here for single backspace. + #It is unlikely to be encountered as a useful PM - so we hack to pass it through as a fix + #for spacing issues on old terminals which miscalculate the single-width 'Symbols for Legacy Computing' + if {$pm_content eq "\b"} { + #puts stderr "renderline PM sole backspace special handling for \U1FB00 - \U1FBFF" + #esc^\b\007 or esc^\besc\\ + #HACKY pass-through - targeting terminals that both mis-space legacy symbols *and* don't support PMs + #The result is repair of the extra space. If the terminal is a modern one and does support PM - the \b should be hidden anyway. + #If the terminal has the space problem AND does support PMs - then this just won't fix it. + #The fix relies on the symbol-supplier to cooperate by appending esc^\b\esc\\ to the problematic symbols. + + #priv::render_addchar $idx $code [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode + #idx has been incremented after last grapheme added + priv::render_append_to_char [expr {$idx -1}] $code + } + #lappend to a dict element in the result for application-specific processing + lappend pm_list $pm_content + } + _ { + #APC Application Program Command + #just warn for now.. + puts stderr "overtype::renderline ESC_ APC command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } default { - puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented codenorm:[ansistring VIEW -lf 1 -vt 1 -nul 1 $codenorm]" } } } + 7DCS { + puts stderr "overtype::renderline DCS - DEVICE CONTROL STRING command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + # + + } + 7OSC - 8OSC { + + } + default { + } } - #switch -regexp -matchvar matchinfo -- $code\ - #$re_mode { - #}\ - #default { - # puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" - #} } default { @@ -3104,7 +3765,7 @@ tcl::namespace::eval overtype { } #-------- - if {$opt_overflow == 0} { + if {$opt_expand_right == 0} { #need to truncate to the width of the original undertext #review - string_width vs printing_length here. undertext requirement to be already rendered therefore punk::char::string_width ok? #set num_under_columns [punk::char::string_width $pt_underchars] ;#plaintext underchars @@ -3275,20 +3936,24 @@ tcl::namespace::eval overtype { overflow_right $overflow_right\ unapplied $unapplied\ unapplied_list $unapplied_list\ - insert_mode $insert_mode\ - autowrap_mode $autowrap_mode\ + insert_mode $insert_mode\ + autowrap_mode $autowrap_mode\ + crm_mode $crm_mode\ + reverse_mode $reverse_mode\ insert_lines_above $insert_lines_above\ insert_lines_below $insert_lines_below\ cursor_saved_position $cursor_saved_position\ cursor_saved_attributes $cursor_saved_attributes\ cursor_column $cursor_column\ cursor_row $cursor_row\ - opt_overflow $opt_overflow\ + expand_right $opt_expand_right\ replay_codes $replay_codes\ replay_codes_underlay $replay_codes_underlay\ replay_codes_overlay $replay_codes_overlay\ + pm_list $pm_list\ ] if {$opt_returnextra == 1} { + #puts stderr "renderline: $result" return $result } else { #human/debug - map special chars to visual glyphs @@ -3313,6 +3978,7 @@ tcl::namespace::eval overtype { return $result } } else { + #puts stderr "renderline returning: result $outstring instruction $instruction unapplied $unapplied overflow_right $overflow_right" return $outstring } #return [join $out ""] @@ -3370,8 +4036,9 @@ tcl::namespace::eval overtype::piper { } interp alias "" piper_renderline "" overtype::piper::renderline -#intended for single grapheme - but will work for multiple -#cannot contain ansi or newlines +#intended primarily for single grapheme - but will work for multiple +#WARNING: query CAN contain ansi or newlines - but if cache was not already set manually,the answer will be incorrect! +#We deliberately allow this for PM/SOS attached within a column #(a cache of ansifreestring_width calls - as these are quite regex heavy) proc overtype::grapheme_width_cached {ch} { variable grapheme_widths @@ -3439,6 +4106,7 @@ tcl::namespace::eval overtype::priv { tcl::dict::set cache_is_sgr $code $answer return $answer } + # better named render_to_unapplied? proc render_unapplied {overlay_grapheme_control_list gci} { upvar idx_over idx_over upvar unapplied unapplied @@ -3532,7 +4200,7 @@ tcl::namespace::eval overtype::priv { set ustacks [lreplace $ustacks $i $i] set gxstacks [lreplace $gxstacks $i $i] } else { - + puts stderr "render_delchar - attempt to delchar at index $i >= number of outcols $nxt - shouldn't happen" } } proc render_erasechar {i count} { @@ -3563,21 +4231,68 @@ tcl::namespace::eval overtype::priv { upvar outcols o lset o $i $c } + + #Initial usecase is for old-terminal hack to add PM-wrapped \b + #review - can be used for other multibyte sequences that occupy one column? + #combiners? diacritics? + proc render_append_to_char {i c} { + upvar outcols o + if {$i > [llength $o]-1} { + error "render_append_to_char cannot append [ansistring VIEW -lf 1 -nul 1 $c] to existing char at index $i while $i >= llength outcols [llength $o]" + } + set existing [lindex $o $i] + if {$existing eq "\0"} { + lset o $i $c + } else { + lset o $i [string cat $existing $c] + } + } #is actually addgrapheme? proc render_addchar {i c sgrstack gx0stack {insert_mode 0}} { upvar outcols o upvar understacks ustacks upvar understacks_gx gxstacks - if 0 { - if {$c eq "c"} { - puts "i:$i c:$c sgrstack:[ansistring VIEW $sgrstack]" - puts "understacks:[ansistring VIEW $ustacks]" - upvar overstacks overstacks - puts "overstacks:[ansistring VIEW $overstacks]" - puts "info level 0:[info level 0]" - } + # -- --- --- + #this is somewhat of a hack.. probably not really the equivalent of proper reverse video? review + #we should ideally be able to reverse the video of a sequence that already includes SGR reverse/noreverse attributes + upvar reverse_mode do_reverse + #if {$do_reverse} { + # lappend sgrstack [a+ reverse] + #} else { + # lappend sgrstack [a+ noreverse] + #} + + #JMN3 + if {$do_reverse} { + #note we can't just look for \x1b\[7m or \x1b\[27m + # it may be a more complex sequence like \x1b\[0\;\;7\;31m etc + + set existing_reverse_state 0 + set codeinfo [punk::ansi::codetype::sgr_merge $sgrstack -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set sgrstack [list [dict get $codeinfo mergeresult] $rflip] + #set sgrstack [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] } + + # -- --- --- set nxt [llength $o] if {!$insert_mode} { diff --git a/src/vendormodules/test/tomlish-1.1.1.tm b/src/vendormodules/test/tomlish-1.1.1.tm index e5909c53..885c56a1 100644 Binary files a/src/vendormodules/test/tomlish-1.1.1.tm and b/src/vendormodules/test/tomlish-1.1.1.tm differ diff --git a/src/vfs/_vfscommon/modules/overtype-1.6.5.tm b/src/vfs/_vfscommon/modules/overtype-1.6.5.tm index 143794fb..38ce71c2 100644 --- a/src/vfs/_vfscommon/modules/overtype-1.6.5.tm +++ b/src/vfs/_vfscommon/modules/overtype-1.6.5.tm @@ -163,22 +163,23 @@ proc overtype::string_columns {text} { tcl::namespace::eval overtype::priv { } -#could return larger than colwidth +#could return larger than renderwidth proc _get_row_append_column {row} { + #obsolete? upvar outputlines outputlines set idx [expr {$row -1}] if {$row <= 1 || $row > [llength $outputlines]} { return 1 } else { - upvar opt_overflow opt_overflow - upvar colwidth colwidth + upvar opt_expand_right expand_right + upvar renderwidth renderwidth set existinglen [punk::ansi::printing_length [lindex $outputlines $idx]] set endpos [expr {$existinglen +1}] - if {$opt_overflow} { + if {$expand_right} { return $endpos } else { - if {$endpos > $colwidth} { - return $colwidth + 1 + if {$endpos > $renderwidth} { + return $renderwidth + 1 } else { return $endpos } @@ -204,38 +205,70 @@ tcl::namespace::eval overtype { proc renderspace {args} { #*** !doctools #[call [fun overtype::renderspace] [arg args] ] - #[para] usage: ?-transparent [lb]0|1[rb]? ?-overflow [lb]1|0[rb]? ?-ellipsis [lb]1|0[rb]? ?-ellipsistext ...? undertext overtext + #[para] usage: ?-transparent [lb]0|1[rb]? ?-expand_right [lb]1|0[rb]? ?-ellipsis [lb]1|0[rb]? ?-ellipsistext ...? undertext overtext # @c overtype starting at left (overstrike) # @c can/should we use something like this?: 'format "%-*s" $len $overtext variable default_ellipsis_horizontal if {[llength $args] < 2} { - error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} + error {usage: ?-width ? ?-startcolumn ? ?-transparent [0|1|]? ?-expand_right [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext} + } + set optargs [lrange $args 0 end-2] + if {[llength $optargs] % 2 == 0} { + lassign [lrange $args end-1 end] underblock overblock + set argsflags [lrange $args 0 end-2] + } else { + set optargs [lrange $args 0 end-1] + if {[llength $optargs] %2 == 0} { + set overblock [lindex $args end] + set underblock "" + set argsflags [lrange $args 0 end-1] + } else { + error "renderspace expects opt-val pairs followed by: or just " + } } - lassign [lrange $args end-1 end] underblock overblock set opts [tcl::dict::create\ - -bias ignored\ - -width \uFFEF\ - -height \uFFEF\ + -bias ignored\ + -width \uFFEF\ + -height \uFFEF\ -startcolumn 1\ - -wrap 0\ - -ellipsis 0\ + -wrap 0\ + -ellipsis 0\ -ellipsistext $default_ellipsis_horizontal\ -ellipsiswhitespace 0\ - -overflow 0\ - -appendlines 1\ - -transparent 0\ - -exposed1 \uFFFD\ - -exposed2 \uFFFD\ - -experimental 0\ - -looplimit \uFFEF\ + -expand_right 0\ + -appendlines 1\ + -transparent 0\ + -exposed1 \uFFFD\ + -exposed2 \uFFFD\ + -experimental 0\ + -cp437 1\ + -looplimit \uFFEF\ + -crm_mode 0\ + -reverse_mode 0\ + -insert_mode 0\ + -console {stdin stdout stderr}\ ] + #expand_right is perhaps consistent with the idea of the page_size being allowed to grow horizontally.. + # it does not necessarily mean the viewport grows. (which further implies need for horizontal scrolling) + # - it does need to be within some concept of terminal width - as columns must be addressable by ansi sequences. + # - This implies the -width option value must grow if it is tied to the concept of renderspace terminal width! REVIEW. + # - further implication is that if expand_right grows the virtual renderspace terminal width - + # then some sort of reflow/rerender needs to be done for preceeding lines? + # possibly not - as expand_right is distinct from a normal terminal-width change event, + # expand_right being primarily to support other operations such as textblock::table + + #todo - viewport width/height as separate concept to terminal width/height? #-ellipsis args not used if -wrap is true - set argsflags [lrange $args 0 end-2] foreach {k v} $argsflags { switch -- $k { - -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental { + -looplimit - -width - -height - -startcolumn - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace + - -transparent - -exposed1 - -exposed2 - -experimental + - -expand_right - -appendlines + - -reverse_mode - -crm_mode - -insert_mode + - -cp437 + - -console { tcl::dict::set opts $k $v } default { @@ -245,7 +278,8 @@ tcl::namespace::eval overtype { } #set opts [tcl::dict::merge $defaults $argsflags] # -- --- --- --- --- --- - set opt_overflow [tcl::dict::get $opts -overflow] + #review - expand_left for RTL text? + set opt_expand_right [tcl::dict::get $opts -expand_right] ##### # review -wrap should map onto DECAWM terminal mode - the wrap 2 idea may not fit in with this?. set opt_wrap [tcl::dict::get $opts -wrap] ;#wrap 1 is hard wrap cutting word at exact column, or 1 column early for 2w-glyph, wrap 2 is for language-based word-wrap algorithm (todo) @@ -261,23 +295,33 @@ tcl::namespace::eval overtype { set opt_exposed1 [tcl::dict::get $opts -exposed1] ;#widechar_exposed_left - todo set opt_exposed2 [tcl::dict::get $opts -exposed2] ;#widechar_exposed_right - todo # -- --- --- --- --- --- + set opt_crm_mode [tcl::dict::get $opts -crm_mode] + set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] + set opt_insert_mode [tcl::dict::get $opts -insert_mode] + # -- --- --- --- --- --- + set opt_cp437 [tcl::dict::get $opts -cp437] + + + #initial state for renderspace 'terminal' reset + set initial_state [dict create\ + -width $opt_width\ + -height $opt_height\ + -crm_mode $opt_crm_mode\ + -reverse_mode $opt_reverse_mode\ + -insert_mode $opt_insert_mode\ + -cp437 $opt_cp437\ + ] # ---------------------------- # -experimental dev flag to set flags etc # ---------------------------- set data_mode 0 - set test_mode 1 set info_mode 0 set edit_mode 0 set opt_experimental [tcl::dict::get $opts -experimental] foreach o $opt_experimental { switch -- $o { - test_mode { - set test_mode 1 - set info_mode 1 - } old_mode { - set test_mode 0 set info_mode 1 } data_mode { @@ -291,13 +335,13 @@ tcl::namespace::eval overtype { } } } - set test_mode 1 ;#try to eliminate # ---------------------------- #modes - set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l - set autowrap_mode $opt_wrap - set reverse_mode 0 + set insert_mode $opt_insert_mode ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l + set autowrap_mode $opt_wrap + set reverse_mode $opt_reverse_mode + set crm_mode $opt_crm_mode set underblock [tcl::string::map {\r\n \n} $underblock] @@ -307,33 +351,35 @@ tcl::namespace::eval overtype { #set underlines [split $underblock \n] #underblock is a 'rendered' block - so width height make sense - #colwidth & colheight were originally named with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. - #The naming is now confusing. It should be something like renderwidth renderheight ?? review + #only non-cursor affecting and non-width occupying ANSI codes should be present. + #ie SGR codes and perhaps things such as PM - although generally those should have been pushed to the application already + #renderwidth & renderheight were originally used with reference to rendering into a 'column' of output e.g a table column - before cursor row/col was implemented. if {$opt_width eq "\uFFEF" || $opt_height eq "\uFFEF"} { - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } if {$opt_height ne "\uFFEF"} { - set colheight $opt_height + set renderheight $opt_height } } else { - set colwidth $opt_width - set colheight $opt_height + set renderwidth $opt_width + set renderheight $opt_height } # -- --- --- --- #REVIEW - do we need ansi resets in the underblock? if {$underblock eq ""} { - set underlines [lrepeat $colheight ""] + set underlines [lrepeat $renderheight ""] } else { + set underblock [textblock::join_basic -- $underblock] ;#ensure properly rendered - ansi per-line resets & replays set underlines [split $underblock \n] } #if {$underblock eq ""} { # set blank "\x1b\[0m\x1b\[0m" # #set underlines [list "\x1b\[0m\x1b\[0m"] - # set underlines [lrepeat $colheight $blank] + # set underlines [lrepeat $renderheight $blank] #} else { # #lines_as_list -ansiresets 1 will do nothing if -ansiresets 1 isn't specified - REVIEW # set underlines [lines_as_list -ansiresets 1 $underblock] @@ -341,7 +387,7 @@ tcl::namespace::eval overtype { # -- --- --- --- #todo - reconsider the 'line' as the natural chunking mechanism for the overlay. - #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth + #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output renderwidth #In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time. #(in cases where there are interline moves or cursor jumps anyway) #This works - but doesn't seem efficient. @@ -356,49 +402,45 @@ tcl::namespace::eval overtype { set looplimit [expr {[tcl::string::length $overblock] + 10}] } - if {!$test_mode} { - set inputchunks [split $overblock \n] - } else { - set scheme 3 - switch -- $scheme { - 0 { - #one big chunk - set inputchunks [list $overblock] + set scheme 3 + switch -- $scheme { + 0 { + #one big chunk + set inputchunks [list $overblock] + } + 1 { + set inputchunks [punk::ansi::ta::split_codes $overblock] + } + 2 { + + #split into lines if possible first - then into plaintext/ansi-sequence chunks ? + set inputchunks [list ""] ;#put an empty plaintext split in for starters + set i 1 + set lines [split $overblock \n] + foreach ln $lines { + if {$i < [llength $lines]} { + append ln \n + } + set sequence_split [punk::ansi::ta::split_codes_single $ln] ;#use split_codes Not split_codes_single? + set lastpt [lindex $inputchunks end] + lset inputchunks end [tcl::string::cat $lastpt [lindex $sequence_split 0]] + lappend inputchunks {*}[lrange $sequence_split 1 end] + incr i } - 1 { - set inputchunks [punk::ansi::ta::split_codes $overblock] + } + 3 { + #it turns out line based chunks are faster than the above.. probably because some of those end up doing the regex splitting twice + set lflines [list] + set inputchunks [split $overblock \n] + foreach ln $inputchunks { + append ln \n + lappend lflines $ln } - 2 { - - #split into lines if possible first - then into plaintext/ansi-sequence chunks ? - set inputchunks [list ""] ;#put an empty plaintext split in for starters - set i 1 - set lines [split $overblock \n] - foreach ln $lines { - if {$i < [llength $lines]} { - append ln \n - } - set sequence_split [punk::ansi::ta::split_codes_single $ln] ;#use split_codes Not split_codes_single? - set lastpt [lindex $inputchunks end] - lset inputchunks end [tcl::string::cat $lastpt [lindex $sequence_split 0]] - lappend inputchunks {*}[lrange $sequence_split 1 end] - incr i - } + if {[llength $lflines]} { + lset lflines end [tcl::string::range [lindex $lflines end] 0 end-1] } - 3 { - #it turns out line based chunks are faster than the above.. probably because some of those end up doing the regex splitting twice - set lflines [list] - set inputchunks [split $overblock \n] - foreach ln $inputchunks { - append ln \n - lappend lflines $ln - } - if {[llength $lflines]} { - lset lflines end [tcl::string::range [lindex $lflines end] 0 end-1] - } - set inputchunks $lflines[unset lflines] + set inputchunks $lflines[unset lflines] - } } } @@ -409,7 +451,7 @@ tcl::namespace::eval overtype { set replay_codes_underlay [tcl::dict::create 1 ""] #lappend replay_codes_overlay "" - set replay_codes_overlay "" + set replay_codes_overlay "[punk::ansi::a]" set unapplied "" set cursor_saved_position [tcl::dict::create] set cursor_saved_attributes "" @@ -420,11 +462,11 @@ tcl::namespace::eval overtype { #underlines are not necessarily processed in order - depending on cursor-moves applied from overtext set row 1 - if {$data_mode} { - set col [_get_row_append_column $row] - } else { + #if {$data_mode} { + # set col [_get_row_append_column $row] + #} else { set col $opt_startcolumn - } + #} set instruction_stats [tcl::dict::create] @@ -452,26 +494,34 @@ tcl::namespace::eval overtype { } #review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary - #but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l - set LASTCALL [list -info 1 -insert_mode $insert_mode -autowrap_mode $autowrap_mode -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] - set rinfo [renderline -experimental $opt_experimental\ + set renderargs [list -experimental $opt_experimental\ + -cp437 $opt_cp437\ -info 1\ + -crm_mode $crm_mode\ -insert_mode $insert_mode\ - -cursor_restore_attributes $cursor_saved_attributes\ -autowrap_mode $autowrap_mode\ + -reverse_mode $reverse_mode\ + -cursor_restore_attributes $cursor_saved_attributes\ -transparent $opt_transparent\ - -width $colwidth\ + -width $renderwidth\ -exposed1 $opt_exposed1\ -exposed2 $opt_exposed2\ - -overflow $opt_overflow\ + -expand_right $opt_expand_right\ -cursor_column $col\ -cursor_row $row\ $undertext\ $overtext\ - ] + ] + set LASTCALL $renderargs + set rinfo [renderline {*}$renderargs] + set instruction [tcl::dict::get $rinfo instruction] set insert_mode [tcl::dict::get $rinfo insert_mode] set autowrap_mode [tcl::dict::get $rinfo autowrap_mode] ;# - #set reverse_mode [tcl::dict::get $rinfo reverse_mode];#how to support in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + set reverse_mode [tcl::dict::get $rinfo reverse_mode] + #how to support reverse_mode in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack? + # - review - the answer is probably that we don't need to - it is set/reset only during application of overtext + set crm_mode [tcl::dict::get $rinfo crm_mode] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] set overflow_right_column [tcl::dict::get $rinfo overflow_right_column] @@ -486,7 +536,37 @@ tcl::namespace::eval overtype { set insert_lines_below [tcl::dict::get $rinfo insert_lines_below] tcl::dict::set replay_codes_underlay [expr {$renderedrow+1}] [tcl::dict::get $rinfo replay_codes_underlay] #lset replay_codes_overlay [expr $overidx+1] [tcl::dict::get $rinfo replay_codes_overlay] - set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + set replay_codes_overlay [tcl::dict::get $rinfo replay_codes_overlay] + if {0 && $reverse_mode} { + #test branch - todo - prune + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + #review + #JMN3 + set existing_reverse_state 0 + #split_codes_single is single esc sequence - but could have multiple sgr codes within one esc sequence + #e.g \x1b\[0;31;7m has a reset,colour red and reverse + set codeinfo [punk::ansi::codetype::sgr_merge [list $replay_codes_overlay] -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] + puts stderr "---->[ansistring VIEW $replay_codes_overlay] rendered: $rendered" + } @@ -515,29 +595,17 @@ tcl::namespace::eval overtype { #keeping separate branches for debugging - review and merge as appropriate when stable tcl::dict::incr instruction_stats $instruction switch -- $instruction { - {} { - if {$test_mode == 0} { - incr row - if {$data_mode} { - set col [_get_row_append_column $row] - if {$col > $colwidth} { + reset { + #reset the 'renderspace terminal' (not underlying terminal) + set row 1 + set col 1 - } - } else { - set col 1 - } - } else { - #lf included in data - set row $post_render_row - set col $post_render_col - #set col 1 - #if {$post_render_row != $renderedrow} { - # set col 1 - #} else { - # set col $post_render_col - #} - } + } + {} { + #lf included in data + set row $post_render_row + set col $post_render_col } up { @@ -563,10 +631,10 @@ tcl::namespace::eval overtype { #we need renderline to return the number of the maximum column filled (or min if we ever do r-to-l) set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -601,10 +669,10 @@ tcl::namespace::eval overtype { } set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } @@ -640,9 +708,16 @@ tcl::namespace::eval overtype { puts stdout ">>>[a+ red bold]overflow_right during restore_cursor[a]" - set sub_info [overtype::renderline -info 1 -width $colwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [tcl::dict::get $opts -overflow] "" $overflow_right] + set sub_info [overtype::renderline -info 1\ + -width $renderwidth\ + -insert_mode $insert_mode\ + -autowrap_mode $autowrap_mode\ + -expand_right [tcl::dict::get $opts -opt_expand_right]\ + ""\ + $overflow_right\ + ] set foldline [tcl::dict::get $sub_info result] - set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed.. + set insert_mode [tcl::dict::get $sub_info insert_mode] ;#probably not needed..? set autowrap_mode [tcl::dict::get $sub_info autowrap_mode] ;#nor this.. linsert outputlines $renderedrow $foldline #review - row & col set by restore - but not if there was no save.. @@ -671,7 +746,7 @@ tcl::namespace::eval overtype { #overflow + unapplied? } lf_start { - #raw newlines - must be test_mode + #raw newlines # ---------------------- #test with fruit.ans #test - treating as newline below... @@ -687,48 +762,58 @@ tcl::namespace::eval overtype { } lf_mid { - if 0 { - #set rhswidth [punk::ansi::printing_length $overflow_right] - #only show debug when we have overflow? - set lhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -nul 1 -lf 1 -vt 1 $rendered]] - set lhs [textblock::frame -title "rendered $visualwidth cols" -subtitle "row-$renderedrow" $lhs] - - set rhs "" - if {$overflow_right ne ""} { - set rhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -nul 1 -lf 1 -vt 1 $overflow_right]] - set rhs [textblock::frame -title overflow_right $rhs] - } - puts [textblock::join $lhs " $post_render_col " $rhs] - } - - if {!$test_mode} { - #rendered - append rendered $overflow_right - #set replay_codes_overlay "" + set edit_mode 0 + if {$edit_mode} { + set inputchunks [linsert $inputchunks 0 $overflow_right$unapplied] set overflow_right "" - - - set row $renderedrow - + set unapplied "" + set row $post_render_row + #set col $post_render_col set col $opt_startcolumn - incr row - #only add newline if we're at the bottom if {$row > [llength $outputlines]} { lappend outputlines {*}[lrepeat 1 ""] } } else { - set edit_mode 0 - if {$edit_mode} { - set inputchunks [linsert $inputchunks 0 $overflow_right$unapplied] - set overflow_right "" - set unapplied "" + if 1 { + if {$overflow_right ne ""} { + if {$opt_expand_right} { + append rendered $overflow_right + set overflow_right "" + } else { + set overflow_width [punk::ansi::printing_length $overflow_right] + if {$visualwidth + $overflow_width <= $renderwidth} { + append rendered $overflow_right + set overflow_right "" + } else { + if {$visualwidth < $renderwidth} { + set graphemes [punk::char::grapheme_split $overflow_width] + set add "" + set addlen $visualwidth + set remaining_overflow $graphemes + foreach g $graphemes { + set w [overtype::grapheme_width_cached] + if {$addlen + $w <= $renderwidth} { + append add $g + incr addlen $w + lpop remaining_overflow + } else { + break + } + } + append rendered $add + set overflow_right [join $remaining_overflow ""] + } + } + } + } set row $post_render_row - #set col $post_render_col set col $opt_startcolumn if {$row > [llength $outputlines]} { lappend outputlines {*}[lrepeat 1 ""] } } else { + #old version - known to work with various ansi graphics - e.g fruit.ans + # - but fails to limit lines to renderwidth when expand_right == 0 append rendered $overflow_right set overflow_right "" set row $post_render_row @@ -740,7 +825,7 @@ tcl::namespace::eval overtype { } } lf_overflow { - #linefeed after colwidth e.g at column 81 for an 80 col width + #linefeed after renderwidth e.g at column 81 for an 80 col width #we may also have other control sequences that came after col 80 e.g cursor save if 0 { @@ -787,38 +872,28 @@ tcl::namespace::eval overtype { set row $post_render_row set col $post_render_col if {$insert_lines_below == 1} { - if {$test_mode == 0} { - set row $renderedrow - set outputlines [linsert $outputlines [expr {$renderedrow }] {*}[lrepeat $insert_lines_below ""]] ;#note - linsert can add to end too - incr row $insert_lines_below - set col $opt_startcolumn - } else { - #set lhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $rendered]] - #set lhs [textblock::frame -title rendered -subtitle "row-$renderedrow" $lhs] - #set rhs "" - #if {$overflow_right ne ""} { - # set rhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $overflow_right]] - # set rhs [textblock::frame -title overflow_right $rhs] - #} - #puts [textblock::join $lhs $rhs] - - #rendered - append rendered $overflow_right - # - - - set overflow_right "" - set row $renderedrow - #only add newline if we're at the bottom - if {$row > [llength $outputlines]} { - lappend outputlines {*}[lrepeat $insert_lines_below ""] - } - incr row $insert_lines_below - set col $opt_startcolumn + #set lhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $rendered]] + #set lhs [textblock::frame -title rendered -subtitle "row-$renderedrow" $lhs] + #set rhs "" + #if {$overflow_right ne ""} { + # set rhs [overtype::left -width 40 -wrap 1 "" [ansistring VIEWSTYLE -lf 1 -vt 1 $overflow_right]] + # set rhs [textblock::frame -title overflow_right $rhs] + #} + #puts [textblock::join $lhs $rhs] + #rendered + append rendered $overflow_right + # + set overflow_right "" + set row $renderedrow + #only add newline if we're at the bottom + if {$row > [llength $outputlines]} { + lappend outputlines {*}[lrepeat $insert_lines_below ""] } + incr row $insert_lines_below + set col $opt_startcolumn } } else { set row $post_render_row @@ -833,10 +908,10 @@ tcl::namespace::eval overtype { } else { set existingdata [lindex $outputlines [expr {$post_render_row -1}]] set lastdatacol [punk::ansi::printing_length $existingdata] - if {$lastdatacol < $colwidth} { + if {$lastdatacol < $renderwidth} { set col [expr {$lastdatacol+1}] } else { - set col $colwidth + set col $renderwidth } } } @@ -845,12 +920,12 @@ tcl::namespace::eval overtype { #doesn't seem to be used by fruit.ans testfile #used by dzds.ans #note that cursor_forward may move deep into the next line - or even span multiple lines !TODO - set c $colwidth + set c $renderwidth set r $post_render_row - if {$post_render_col > $colwidth} { + if {$post_render_col > $renderwidth} { set i $c while {$i <= $post_render_col} { - if {$c == $colwidth+1} { + if {$c == $renderwidth+1} { incr r if {$opt_appendlines} { if {$r < [llength $outputlines]} { @@ -874,7 +949,7 @@ tcl::namespace::eval overtype { set col $c } wrapmovebackward { - set c $colwidth + set c $renderwidth set r $post_render_row if {$post_render_col < 1} { set c 1 @@ -883,7 +958,7 @@ tcl::namespace::eval overtype { if {$c == 0} { if {$r > 1} { incr r -1 - set c $colwidth + set c $renderwidth } else { #leave r at 1 set c 1 #testfile besthpav.ans first line top left border alignment @@ -910,7 +985,6 @@ tcl::namespace::eval overtype { incr row set col $opt_startcolumn ;#whether wrap or not - next data is at column 1 ?? } else { - #this works for test_mode (which should become the default) - but could give a bad result otherwise - review - add tests fix. set col $post_render_col #set unapplied "" ;#this seems wrong? #set unapplied [tcl::string::range $unapplied 1 end] @@ -941,7 +1015,7 @@ tcl::namespace::eval overtype { #2nd half of grapheme would overflow - treggering grapheme is returned in unapplied. There may also be overflow_right from earlier inserts #todo - consider various options .. re-render a single trailing space or placeholder on same output line, etc if {$autowrap_mode} { - if {$colwidth < 2} { + if {$renderwidth < 2} { #edge case of rendering to a single column output - any 2w char will just cause a loop if we don't substitute with something, or drop the character set idx 0 set triggering_grapheme_index -1 @@ -960,7 +1034,7 @@ tcl::namespace::eval overtype { } else { set overflow_handled 1 #handled by dropping entire overflow if any - if {$colwidth < 2} { + if {$renderwidth < 2} { set idx 0 set triggering_grapheme_index -1 foreach u $unapplied_list { @@ -988,7 +1062,7 @@ tcl::namespace::eval overtype { } - if {!$opt_overflow && !$autowrap_mode} { + if {!$opt_expand_right && !$autowrap_mode} { #not allowed to overflow column or wrap therefore we get overflow data to truncate if {[tcl::dict::get $opts -ellipsis]} { set show_ellipsis 1 @@ -1066,7 +1140,6 @@ tcl::namespace::eval overtype { set debugmsg "" append debugmsg "${Y}${sep_header}${RST}" \n append debugmsg "looplimit $looplimit reached\n" - append debugmsg "test_mode:$test_mode\n" append debugmsg "data_mode:$data_mode\n" append debugmsg "opt_appendlines:$opt_appendlines\n" append debugmsg "prev_row :[tcl::dict::get $LASTCALL -cursor_row]\n" @@ -1141,12 +1214,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + #set renderwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] - #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {$colwidth - $overblock_width}] + set under_exposed_max [expr {$renderwidth - $overblock_width}] if {$under_exposed_max > 0} { #background block is wider if {$under_exposed_max % 2 == 0} { @@ -1176,14 +1248,14 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] set undertext "$undertext[string repeat { } $udiff]" } set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] #review - right-to-left langs should elide on left! - extra option required if {$overflowlength > 0} { @@ -1196,8 +1268,8 @@ tcl::namespace::eval overtype { #overlay line data is wider - trim if overflow not specified in opts - and overtype an ellipsis at right if it was specified if {![tcl::dict::get $opts -overflow]} { - #lappend outputlines [tcl::string::range $overtext 0 [expr {$colwidth - 1}]] - #set overtext [tcl::string::range $overtext 0 $colwidth-1 ] + #lappend outputlines [tcl::string::range $overtext 0 [expr {$renderwidth - 1}]] + #set overtext [tcl::string::range $overtext 0 $renderwidth-1 ] if {$opt_ellipsis} { set show_ellipsis 1 if {!$opt_ellipsiswhitespace} { @@ -1286,12 +1358,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] set left_exposed $under_exposed_max @@ -1307,8 +1378,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1336,10 +1407,17 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline\ + -info 1\ + -insert_mode 0\ + -transparent $opt_transparent\ + -exposed1 $opt_exposed1 -exposed2 $opt_exposed2\ + -overflow $opt_overflow\ + -startcolumn [expr {1 + $startoffset}]\ + $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] if {!$opt_overflow} { @@ -1364,7 +1442,7 @@ tcl::namespace::eval overtype { #padded overtext #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -expand_right $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] lappend outputlines [tcl::dict::get $rinfo result] } set replay_codes [tcl::dict::get $rinfo replay_codes] @@ -1433,12 +1511,11 @@ tcl::namespace::eval overtype { set overblock [tcl::string::map {\r\n \n} $overblock] set underlines [split $underblock \n] - #set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] - lassign [blocksize $underblock] _w colwidth _h colheight + lassign [blocksize $underblock] _w renderwidth _h renderheight set overlines [split $overblock \n] #set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] lassign [blocksize $overblock] _w overblock_width _h overblock_height - set under_exposed_max [expr {max(0,$colwidth - $overblock_width)}] + set under_exposed_max [expr {max(0,$renderwidth - $overblock_width)}] switch -- $opt_blockalign { left { @@ -1484,8 +1561,8 @@ tcl::namespace::eval overtype { foreach undertext $underlines overtext $overlines { set overtext_datalen [punk::ansi::printing_length $overtext] set ulen [punk::ansi::printing_length $undertext] - if {$ulen < $colwidth} { - set udiff [expr {$colwidth - $ulen}] + if {$ulen < $renderwidth} { + set udiff [expr {$renderwidth - $ulen}] #puts xxx append undertext [string repeat { } $udiff] } @@ -1513,10 +1590,10 @@ tcl::namespace::eval overtype { set undertext [tcl::string::cat $replay_codes_underlay $undertext] set overtext [tcl::string::cat $replay_codes_overlay $overtext] - set overflowlength [expr {$overtext_datalen - $colwidth}] + set overflowlength [expr {$overtext_datalen - $renderwidth}] if {$overflowlength > 0} { #raw overtext wider than undertext column - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] + set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -expand_right $opt_overflow -startcolumn [expr {1 + $startoffset}] $undertext $overtext] set replay_codes [tcl::dict::get $rinfo replay_codes] set rendered [tcl::dict::get $rinfo result] set overflow_right [tcl::dict::get $rinfo overflow_right] @@ -1564,8 +1641,9 @@ tcl::namespace::eval overtype { } else { #padded overtext #lappend outputlines [renderline -insert_mode 0 -transparent $opt_transparent -startcolumn [expr {$left_exposed + 1}] $undertext $overtext] - #Note - we still need overflow here - as although the overtext is short - it may oveflow due to the startoffset - set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -overflow $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #Note - we still need expand_right here - as although the overtext is short - it may oveflow due to the startoffset + set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -expand_right $opt_overflow -startcolumn [expr {$left_exposed + 1 + $startoffset}] $undertext $overtext] + #puts stderr "--> [ansistring VIEW -lf 1 -nul 1 $rinfo] <--" set overflow_right [tcl::dict::get $rinfo overflow_right] set unapplied [tcl::dict::get $rinfo unapplied] lappend outputlines [tcl::dict::get $rinfo result] @@ -1586,7 +1664,8 @@ tcl::namespace::eval overtype { #-returnextra enables returning of overflow and length #review - use punk::ansi::ta::detect to short-circuit processing and do simpler string calcs as an optimisation? #review - DECSWL/DECDWL double width line codes - very difficult/impossible to align and compose with other elements - #(could render it by faking it with sixels and a lot of work - find/make a sixel font and ensure it's exactly 2 cols per char) + #(could render it by faking it with sixels and a lot of work - find/make a sixel font and ensure it's exactly 2 cols per char? + # This would probably be impractical to support for different fonts) #todo - review transparency issues with single/double width characters #bidi - need a base direction and concept of directional runs for RTL vs LTR - may be best handled at another layer? proc renderline {args} { @@ -1608,8 +1687,10 @@ tcl::namespace::eval overtype { #[para] The main 3 are the result, overflow_right, and unapplied. #[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation. + #puts stderr "renderline '$args'" + if {[llength $args] < 2} { - error {usage: ?-info 0|1? ?-startcolumn ? ?-cursor_column ? ?-cursor_row |""? ?-transparent [0|1|]? ?-overflow [1|0]? undertext overtext} + error {usage: ?-info 0|1? ?-startcolumn ? ?-cursor_column ? ?-cursor_row |""? ?-transparent [0|1|]? ?-expand_right [1|0]? undertext overtext} } lassign [lrange $args end-1 end] under over if {[string first \n $under] >= 0} { @@ -1623,12 +1704,13 @@ tcl::namespace::eval overtype { set opts [tcl::dict::create\ -etabs 0\ -width \uFFEF\ - -overflow 0\ + -expand_right 0\ -transparent 0\ -startcolumn 1\ -cursor_column 1\ -cursor_row ""\ -insert_mode 1\ + -crm_mode 0\ -autowrap_mode 1\ -reverse_mode 0\ -info 0\ @@ -1643,13 +1725,15 @@ tcl::namespace::eval overtype { #cursor_row, when numeric will allow detection of certain row moves that are still within our row - allowing us to avoid an early return #An empty string for cursor_row tells us we have no info about our own row context, and to return with an unapplied string if any row move occurs - #exposed1 and exposed2 for first and second col of underying 2wide char which is truncated by transparency or overflow + #exposed1 and exposed2 for first and second col of underying 2wide char which is truncated by transparency, currsor movements to 2nd charcol, or overflow/expand_right #todo - return info about such grapheme 'cuts' in -info structure and/or create option to raise an error set argsflags [lrange $args 0 end-2] tcl::dict::for {k v} $argsflags { switch -- $k { - -experimental - -cp437 - -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -autowrap_mode - -reverse_mode - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { + -experimental - -cp437 - -width - -expand_right - -transparent - -startcolumn - -cursor_column - -cursor_row + - -crm_mode - -insert_mode - -autowrap_mode - -reverse_mode + - -info - -exposed1 - -exposed2 - -cursor_restore_attributes { tcl::dict::set opts $k $v } default { @@ -1660,7 +1744,7 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_width [tcl::dict::get $opts -width] set opt_etabs [tcl::dict::get $opts -etabs] - set opt_overflow [tcl::dict::get $opts -overflow] + set opt_expand_right [tcl::dict::get $opts -expand_right] set opt_colstart [tcl::dict::get $opts -startcolumn] ;#lhs limit for overlay - an offset to cursor_column - first visible column is 1. 0 or < 0 are before the start of the underlay set opt_colcursor [tcl::dict::get $opts -cursor_column];#start cursor column relative to overlay set opt_row_context [tcl::dict::get $opts -cursor_row] @@ -1676,20 +1760,11 @@ tcl::namespace::eval overtype { # -- --- --- --- --- --- --- --- --- --- --- --- set opt_autowrap_mode [tcl::dict::get $opts -autowrap_mode] ;#DECAWM - char or movement can go beyond leftmost/rightmost col to prev/next line set opt_reverse_mode [tcl::dict::get $opts -reverse_mode] ;#DECSNM + set opt_crm_mode [tcl::dict::get $opts -crm_mode];# CRM - show control character mode # -- --- --- --- --- --- --- --- --- --- --- --- set temp_cursor_saved [tcl::dict::get $opts -cursor_restore_attributes] - set test_mode 0 set cp437_glyphs [tcl::dict::get $opts -cp437] - foreach e [tcl::dict::get $opts -experimental] { - switch -- $e { - test_mode { - set test_mode 1 - set cp437_glyphs 1 - } - } - } - set test_mode 1 ;#try to elminate set cp437_map [tcl::dict::create] if {$cp437_glyphs} { set cp437_map [set ::punk::ansi::cp437_map] @@ -1721,6 +1796,10 @@ tcl::namespace::eval overtype { set cursor_row $opt_row_context } + set insert_mode $opt_insert_mode ;#default 1 + set autowrap_mode $opt_autowrap_mode ;#default 1 + set crm_mode $opt_crm_mode ;#default 0 (Show Control Character mode) + set reverse_mode $opt_reverse_mode #----- # @@ -1768,13 +1847,14 @@ tcl::namespace::eval overtype { } set understacks [list] set understacks_gx [list] + set pm_list [list] set i_u -1 ;#underlay may legitimately be empty set undercols [list] set u_codestack [list] #u_gx_stack probably isn't really a stack - I don't know if g0 g1 can stack or not - for now we support only g0 anyway set u_gx_stack [list] ;#separate stack for g0 (g1 g2 g3?) graphics on and off (DEC special graphics) - #set pt_underchars "" ;#for string_columns length calculation for overflow 0 truncation + #set pt_underchars "" ;#for string_columns length calculation for expand_right 0 truncation set remainder [list] ;#for returnextra foreach {pt code} $undermap { #pt = plain text @@ -1834,6 +1914,7 @@ tcl::namespace::eval overtype { #underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc + #keep any remaining PMs in place if {$code ne ""} { set c1c2 [tcl::string::range $code 0 1] @@ -1841,6 +1922,8 @@ tcl::namespace::eval overtype { \x1b\[ 7CSI\ \x9b 8CSI\ \x1b\( 7GFX\ + \x1b^ 7PMX\ + \x1bX 7SOS\ ] $c1c2] 0 3];# leadernorm is 1st 2 chars mapped to normalised indicator - or is original 2 chars switch -- $leadernorm { @@ -1875,6 +1958,26 @@ tcl::namespace::eval overtype { } } } + 7PMX - 7SOS { + #we can have PMs or SOS (start of string) in the underlay - though mostly the PMs should have been processed.. + #attach the PM/SOS (entire ANSI sequence) to the previous grapheme! + #It should not affect the size - but terminal display may get thrown out if terminal doesn't support them. + + #note that there may in theory already be ANSI stored - we don't assume it was a pure grapheme string + set graphemeplus [lindex $undercols end] + if {$graphemeplus ne "\0"} { + append graphemeplus $code + } else { + set graphemeplus $code + } + lset undercols end $graphemeplus + #The grapheme_width_cached function will be called on this later - and doesn't account for ansi. + #we need to manually cache the item with it's proper width + variable grapheme_widths + #stripped and plus version keys pointing to same length + dict set grapheme_widths $graphemeplus [grapheme_width_cached [::punk::ansi::ansistrip $graphemeplus]] + + } default { } @@ -1895,51 +1998,29 @@ tcl::namespace::eval overtype { #consider also if there are other codes that should be stacked..? } - if {!$test_mode} { - #fill columns to width with spaces, and carry over stacks - we will have to keep track of where the underlying data ends manually - TODO - #Specifying a width is suitable for terminal-like applications and text-blocks - if {$opt_width ne "\uFFEF"} { - if {[llength $understacks]} { - set cs $u_codestack - set gs $u_gx_stack - } else { - set cs [list] - set gs [list] - } - if {[llength $undercols]< $opt_width} { - set diff [expr {$opt_width- [llength $undercols]}] - if {$diff > 0} { - lappend undercols {*}[lrepeat $diff " "] - lappend understacks {*}[lrepeat $diff $cs] - lappend understacks_gx {*}[lrepeat $diff $gs] - } - } + #NULL empty cell indicator + if {$opt_width ne "\uFFEF"} { + if {[llength $understacks]} { + set cs $u_codestack + set gs $u_gx_stack + } else { + set cs [list] + set gs [list] } - } else { - #NULL empty cell indicator - if {$opt_width ne "\uFFEF"} { - if {[llength $understacks]} { - set cs $u_codestack - set gs $u_gx_stack - } else { - set cs [list] - set gs [list] - } - if {[llength $undercols]< $opt_width} { - set diff [expr {$opt_width- [llength $undercols]}] - if {$diff > 0} { - lappend undercols {*}[lrepeat $diff "\u0000"] - lappend understacks {*}[lrepeat $diff $cs] - lappend understacks_gx {*}[lrepeat $diff $gs] - } + if {[llength $undercols]< $opt_width} { + set diff [expr {$opt_width- [llength $undercols]}] + if {$diff > 0} { + lappend undercols {*}[lrepeat $diff "\u0000"] + lappend understacks {*}[lrepeat $diff $cs] + lappend understacks_gx {*}[lrepeat $diff $gs] } } - } + if {$opt_width ne "\uFFEF"} { - set colwidth $opt_width + set renderwidth $opt_width } else { - set colwidth [llength $undercols] + set renderwidth [llength $undercols] } @@ -2017,12 +2098,34 @@ tcl::namespace::eval overtype { } append pt_overchars $pt #will get empty pt between adjacent codes - foreach grapheme [punk::char::grapheme_split $pt] { - lappend overstacks $o_codestack - lappend overstacks_gx $o_gxstack - incr i_o - lappend overlay_grapheme_control_list [list g $grapheme] - lappend overlay_grapheme_control_stacks $o_codestack + if {!$crm_mode} { + foreach grapheme [punk::char::grapheme_split $pt] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } else { + set tsbegin [clock micros] + foreach grapheme_original [punk::char::grapheme_split $pt] { + set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original] + #puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm" + foreach grapheme [punk::char::grapheme_split $pt_crm] { + if {$grapheme eq "\n"} { + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"] + } else { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + } + set elapsed [expr {[clock micros] - $tsbegin}] + puts stderr "ptlen [string length $pt] elapsedus:$elapsed" } #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc @@ -2030,40 +2133,91 @@ tcl::namespace::eval overtype { # that pure resets are fairly common - more so than leading resets with other info # that non-sgr codes are not that common, so ok to check for resets before verifying it is actually SGR at all. if {$code ne ""} { - lappend overlay_grapheme_control_stacks $o_codestack - #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) - if {[punk::ansi::codetype::is_sgr_reset $code]} { - set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set o_codestack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #basic simplification first - remove straight dupes - set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars - set o_codestack [lremove $o_codestack {*}$dup_posns] - lappend o_codestack $code - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[regexp {\x1b7|\x1b\[s} $code]} { - #experiment - #cursor_save - for the replays review. - #jmn - #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] - lappend overlay_grapheme_control_list [list other $code] - } elseif {[regexp {\x1b8|\x1b\[u} $code]} { - #experiment - #cursor_restore - for the replays - set o_codestack [list $temp_cursor_saved] - lappend overlay_grapheme_control_list [list other $code] + #we need to immediately set crm_mode here if \x1b\[3h received + if {$code eq "\x1b\[3h"} { + set crm_mode 1 + } elseif {$code eq "\x1b\[3l"} { + set crm_mode 0 + } + #else crm_mode could be set either way from options + if {$crm_mode && $code ne "\x1b\[00001E"} { + #treat the code as type 'g' like above - only allow through codes to reset mode REVIEW for now just \x1b\[3l ? + #we need to somehow convert further \n in the graphical rep to an instruction for newline that will bypass further crm_mode processing or we would loop. + set code_as_pt [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $code] + #split using standard split for first foreach loop - grapheme based split when processing 2nd foreach loop + set chars [split $code_as_pt ""] + set codeparts [list] ;#list of 2-el lists each element {crmcontrol } or {g } + foreach c $chars { + if {$c eq "\n"} { + #use CNL (cursor next line) \x1b\[00001E ;#leading zeroes ok for this processor - used as debugging aid to distinguish + lappend codeparts [list crmcontrol "\x1b\[00001E"] + } else { + if {[llength $codeparts] > 0 && [lindex $codeparts end 0] eq "g"} { + set existing [lindex $codeparts end 1] + lset codeparts end [list g [string cat $existing $c]] + } else { + lappend codeparts [list g $c] + } + } + } + + set partidx 0 + foreach record $codeparts { + lassign $record rtype rval + switch -exact -- $rtype { + g { + append pt_overchars $rval + foreach grapheme [punk::char::grapheme_split $rval] { + lappend overstacks $o_codestack + lappend overstacks_gx $o_gxstack + incr i_o + lappend overlay_grapheme_control_list [list g $grapheme] + lappend overlay_grapheme_control_stacks $o_codestack + } + } + crmcontrol { + #leave o_codestack + lappend overlay_grapheme_control_stacks $o_codestack + lappend overlay_grapheme_control_list [list crmcontrol $rval] + } + } + } } else { - if {[punk::ansi::codetype::is_gx_open $code]} { - set o_gxstack [list "gx0_on"] - lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } elseif {[punk::ansi::codetype::is_gx_close $code]} { - set o_gxstack [list] - lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets - } else { + lappend overlay_grapheme_control_stacks $o_codestack + #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) + if {[punk::ansi::codetype::is_sgr_reset $code]} { + set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set o_codestack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #basic simplification first - remove straight dupes + set dup_posns [lsearch -all -exact $o_codestack $code] ;#must be -exact because of square-bracket glob chars + set o_codestack [lremove $o_codestack {*}$dup_posns] + lappend o_codestack $code + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[regexp {\x1b7|\x1b\[s} $code]} { + #experiment + #cursor_save - for the replays review. + #jmn + #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] + lappend overlay_grapheme_control_list [list other $code] + } elseif {[regexp {\x1b8|\x1b\[u} $code]} { + #experiment + #cursor_restore - for the replays + set o_codestack [list $temp_cursor_saved] lappend overlay_grapheme_control_list [list other $code] + } else { + if {[punk::ansi::codetype::is_gx_open $code]} { + set o_gxstack [list "gx0_on"] + lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } elseif {[punk::ansi::codetype::is_gx_close $code]} { + set o_gxstack [list] + lappend overlay_grapheme_control_list [list gx0 gx0_off] ;#don't store code - will complicate debugging if we spit it out and jump character sets + } else { + lappend overlay_grapheme_control_list [list other $code] + } } } } @@ -2089,11 +2243,12 @@ tcl::namespace::eval overtype { # -- --- --- #we need to initialise overflow_idx before any potential row-movements - as they need to perform a loop break and force in_excess to 1 - if {$opt_overflow} { - #somewhat counterintuitively - overflow true means we can have lines as long as we want, but either way there can be excess data that needs to be thrown back to the calling loop. + if {$opt_expand_right} { + #expand_right true means we can have lines as long as we want, but either way there can be excess data that needs to be thrown back to the calling loop. + #we currently only support horizontal expansion to the right (review regarding RTL text!) set overflow_idx -1 } else { - #overflow zero - we can't grow beyond our column width - so we get ellipsis or truncation + #expand_right zero - we can't grow beyond our column width - so we get ellipsis or truncation if {$opt_width ne "\uFFEF"} { set overflow_idx [expr {$opt_width}] } else { @@ -2134,10 +2289,7 @@ tcl::namespace::eval overtype { #movements only occur within the overlay range. #an underlay is however not necessary.. e.g - #renderline -overflow 1 "" data - #foreach {pt code} $overmap {} - set insert_mode $opt_insert_mode ;#default 1 - set autowrap_mode $opt_autowrap_mode ;#default 1 + #renderline -expand_right 1 "" data #set re_mode {\x1b\[\?([0-9]*)(h|l)} ;#e.g DECAWM #set re_col_move {\x1b\[([0-9]*)(C|D|G)$} @@ -2163,13 +2315,28 @@ tcl::namespace::eval overtype { switch -- $type { g { set ch $item + #crm_mode affects both graphic and control + if {0 && $crm_mode} { + set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $ch] + set chars [string map [list \n "\x1b\[00001E"] $chars] + if {[llength [split $chars ""]] > 1} { + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + #incr idx_over + break + } else { + set ch $chars + } + } incr idx_over; #idx_over (until unapplied reached anyway) is per *grapheme* in the overlay - not per col. if {($idx < ($opt_colstart -1))} { incr idx [grapheme_width_cached $ch] continue } #set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our active data width - set within_undercols [expr {$idx <= $colwidth-1}] + set within_undercols [expr {$idx <= $renderwidth-1}] #https://www.enigma.com/resources/blog/the-secret-world-of-newline-characters #\x85 NEL in the c1 control set is treated by some terminal emulators (e.g Hyper) as a newline, @@ -2194,7 +2361,7 @@ tcl::namespace::eval overtype { #linefeed after final column #puts "---c at overflow_idx=$overflow_idx" incr cursor_row - set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2 + set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to expand_right = 1 set instruction lf_overflow ;#only special treatment is to give it it's own instruction in case caller needs to handle differently priv::render_unapplied $overlay_grapheme_control_list $gci break @@ -2202,7 +2369,10 @@ tcl::namespace::eval overtype { #linefeed occurred in middle or at end of text #puts "---mid-or-end-text-linefeed idx:$idx overflow_idx:$overflow_idx" incr cursor_row - set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2 + if {$idx == -1 || $overflow_idx > $idx} { + #don't set overflow_idx higher if it's already set lower and we're adding graphemes to overflow + set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to expand_right = 1 + } set instruction lf_mid priv::render_unapplied $overlay_grapheme_control_list $gci break @@ -2284,23 +2454,35 @@ tcl::namespace::eval overtype { #tab of some length dependent on tabstops/elastic tabstop settings? } } elseif {$idx >= $overflow_idx} { - #jmn? - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci-1]] - #set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #don't incr idx beyond the overflow_idx - #idx_over already incremented - decrement so current overlay grapheme stacks go to unapplied - incr idx_over -1 - #priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#back one index here too - priv::render_this_unapplied $overlay_grapheme_control_list $gci ;# - set instruction overflow - break + #REVIEW + set next_gc [lindex $overlay_grapheme_control_list $gci+1] ;#next grapheme or control + lassign $next_gc next_type next_item + if {$autowrap_mode || $next_type ne "g"} { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci-1]] + #set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #don't incr idx beyond the overflow_idx + #idx_over already incremented - decrement so current overlay grapheme stacks go to unapplied + incr idx_over -1 + #priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#back one index here too + priv::render_this_unapplied $overlay_grapheme_control_list $gci ;# + set instruction overflow + break + } else { + #no point throwing back to caller for each grapheme that is overflowing + #without this branch - renderline would be called with overtext reducing only by one grapheme per call + #processing a potentially long overtext each time (ie - very slow) + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #JMN4 + + } } } else { #review. - #This corresponds to opt_overflow being true (at least until overflow_idx is in some cases forced to a value when throwing back to calling loop) + #overflow_idx = -1 + #This corresponds to expand_right being true (at least until overflow_idx is in some cases forced to a value when throwing back to calling loop) } - if {($do_transparency && [regexp $opt_transparent $ch])} { + if {($do_transparency && [regexp $opt_transparent $ch])} { #pre opt_colstart is effectively transparent (we have applied padding of required number of columns to left of overlay) if {$idx > [llength $outcols]-1} { lappend outcols " " @@ -2311,6 +2493,7 @@ tcl::namespace::eval overtype { } else { #todo - punk::char::char_width set g [lindex $outcols $idx] + #JMN set uwidth [grapheme_width_cached $g] if {[lindex $outcols $idx] eq ""} { #2nd col of 2-wide char in underlay @@ -2438,7 +2621,7 @@ tcl::namespace::eval overtype { } incr idx } - if {($cursor_column < [llength $outcols]) || $overflow_idx == -1 || $test_mode} { + if {($cursor_column < [llength $outcols]) || $overflow_idx == -1} { incr cursor_column } } elseif {$uwidth > 1} { @@ -2472,12 +2655,6 @@ tcl::namespace::eval overtype { priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode incr idx incr cursor_column - if {$overflow_idx !=-1 && !$test_mode} { - #overflow - if {$cursor_column > [llength $outcols]} { - set cursor_column [llength $outcols] - } - } } } } @@ -2485,13 +2662,29 @@ tcl::namespace::eval overtype { } - other { + other - crmcontrol { + if {$crm_mode && $type ne "crmcontrol" && $item ne "\x1b\[00001E"} { + if {$item eq "\x1b\[3l"} { + set crm_mode 0 + } else { + #When our initial overlay split was done - we weren't in crm_mode - so there are codes that weren't mapped to unicode control character representations + #set within_undercols [expr {$idx <= $renderwidth-1}] + #set chars [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $item] + set chars [ansistring VIEW -nul 1 -lf 1 -vt 1 -ff 1 $item] + priv::render_unapplied $overlay_grapheme_control_list $gci + #prefix the unapplied controls with the string version of this control + set unapplied_list [linsert $unapplied_list 0 {*}[split $chars ""]] + set unapplied [join $unapplied_list ""] + + break + } + } + #todo - consider CSI s DECSLRM vs ansi.sys \x1b\[s - we need \x1b\[s for oldschool ansi art - but may have to enable only for that. - #we should probably therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore + #we should possibly therefore reverse this mapping so that x1b7 x1b8 are the primary codes for save/restore? set code [tcl::string::map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $item] #since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied' - set matchinfo [list] #remap of DEC cursor_save/cursor_restore from ESC sequence to equivalent CSI #probably not ideal - consider putting cursor_save/cursor_restore in functions so they can be called from the appropriate switch branch instead of using this mapping @@ -2501,15 +2694,16 @@ tcl::namespace::eval overtype { set c1c2c3 [tcl::string::range $code 0 2] #set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)} #tcl 8.7 - faster to use inline list than to store it in a local var outside of loop. - #(surprising - but presumably ) + #(somewhat surprising) set leadernorm [tcl::string::range [tcl::string::map [list\ \x1b\[< 1006\ \x1b\[ 7CSI\ + \x1bP 7DCS\ \x9b 8CSI\ \x1b\] 7OSC\ \x9d 8OSC\ \x1b 7ESC\ - ] $c1c2c3] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars + ] $c1c2c3] 0 3] ;#leadernorm is 1st 1,2 or 3 chars mapped to 4char normalised indicator - or is original first chars (1,2 or 3 len) #we leave the tail of the code unmapped for now switch -- $leadernorm { @@ -2521,6 +2715,11 @@ tcl::namespace::eval overtype { 7CSI - 7OSC { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]] } + 7DCS { + #ESC P + #Device Control String https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Controls-beginning-with-ESC:ESC-F.C74 + set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]] + } 7ESC { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } @@ -2528,7 +2727,10 @@ tcl::namespace::eval overtype { set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]] } default { + puts stderr "Sequence detected as ANSI, but not handled in leadernorm switch. code: [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" #we haven't made a mapping for this + #could in theory be 1,2 or 3 in len + #although we shouldn't be getting here if the regexp for ansi codes is kept in sync with our switch branches set codenorm $code } } @@ -2551,44 +2753,44 @@ tcl::namespace::eval overtype { {7CSI} - {8CSI} { set param [tcl::string::range $codenorm 4 end-1] #puts stdout "--> CSI [tcl::string::index $leadernorm 0] bit param:$param" - switch -- [tcl::string::index $codenorm end] { - D { - #Col move - #puts stdout "<-back" - #cursor back - #left-arrow/move-back when ltr mode + set code_end [tcl::string::index $codenorm end] ;#used for e.g h|l set/unset mode + switch -exact -- $code_end { + A { + #Row move - up + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set num $param if {$num eq ""} {set num 1} + incr cursor_row -$num - set version 2 - if {$version eq "2"} { - #todo - startcolumn offset! - if {$cursor_column - $num >= 1} { - incr idx -$num - incr cursor_column -$num - } else { - if {!$autowrap_mode} { - set cursor_column 1 - set idx 0 - } else { - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - incr cursor_column -$num - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction wrapmovebackward - break - } - } - } else { - incr idx -$num - incr cursor_column -$num - if {$idx < $opt_colstart-1} { - #wrap to previous line and position cursor at end of data - set idx [expr {$opt_colstart-1}] - set cursor_column $opt_colstart - } + if {$cursor_row < 1} { + set cursor_row 1 } + + #ensure rest of *overlay* is emitted to remainder + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction up + #retain cursor_column + break + } + B { + #CUD - Cursor Down + #Row move - down + set num $param + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #move down + if {$num eq ""} {set num 1} + incr cursor_row $num + + + incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction down + #retain cursor_column + break } C { + #CUF - Cursor Forward #Col move #puts stdout "->forward" #todo - consider right-to-left cursor mode (e.g Hebrew).. some day. @@ -2610,7 +2812,7 @@ tcl::namespace::eval overtype { if {$overflow_idx == -1} { incr max } - if {$test_mode && $cursor_column == $max+1} { + if {$cursor_column == $max+1} { #move_forward while in overflow incr cursor_column -1 } @@ -2627,7 +2829,7 @@ tcl::namespace::eval overtype { } #horizontal movement beyond line extent needs to wrap - throw back to caller - #we may have both overflow_rightand unapplied data + #we may have both overflow_right and unapplied data #(can have overflow_right if we were in insert_mode and processed chars prior to this movement) #leave row as is - caller will need to determine how many rows the column-movement has consumed incr cursor_column $num ;#give our caller the necessary info as columns from start of row @@ -2642,7 +2844,8 @@ tcl::namespace::eval overtype { } } } else { - if {!$opt_overflow || ($cursor_column + $num) <= [llength $outcols+1]} { + #review - dead branch + if {!$expand_right || ($cursor_column + $num) <= [llength $outcols+1]} { incr idx $num incr cursor_column $num } else { @@ -2692,85 +2895,294 @@ tcl::namespace::eval overtype { } } } - G { + D { #Col move - #move absolute column - #adjust to colstart - as column 1 is within overlay - #??? - set idx [expr {$param + $opt_colstart -1}] - set cursor_column $param - error "renderline absolute col move ESC G unimplemented" - } - A { - #Row move - up - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + #puts stdout "<-back" + #cursor back + #left-arrow/move-back when ltr mode set num $param if {$num eq ""} {set num 1} - incr cursor_row -$num - if {$cursor_row < 1} { - set cursor_row 1 + set version 2 + if {$version eq "2"} { + #todo - startcolumn offset! + if {$cursor_column - $num >= 1} { + incr idx -$num + incr cursor_column -$num + } else { + if {!$autowrap_mode} { + set cursor_column 1 + set idx 0 + } else { + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr cursor_column -$num + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction wrapmovebackward + break + } + } + } else { + incr idx -$num + incr cursor_column -$num + if {$idx < $opt_colstart-1} { + #wrap to previous line and position cursor at end of data + set idx [expr {$opt_colstart-1}] + set cursor_column $opt_colstart + } } - - #ensure rest of *overlay* is emitted to remainder + } + E { + #CNL - Cursor Next Line + if {$param eq ""} { + set downmove 1 + } else { + set downmove [expr {$param}] + } + puts stderr "renderline CNL down-by-$downmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row + $downmove}] + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction up - #retain cursor_column - break + set instruction move + break + } - B { - #Row move - down - set num $param + F { + #CPL - Cursor Previous Line + if {$param eq ""} { + set upmove 1 + } else { + set upmove [expr {$param}] + } + puts stderr "renderline CPL up-by-$upmove" + set cursor_column 1 + set cursor_row [expr {$cursor_row -$upmove}] + if {$cursor_row < 1} { + set cursor_row 1 + } + set idx [expr {$cursor_column - 1}] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #move down - if {$num eq ""} {set num 1} - incr cursor_row $num - - - incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet + incr idx_over priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction down - #retain cursor_column - break + set instruction move + break + + } + G { + #CHA - Cursor Horizontal Absolute (move to absolute column no) + if {$param eq ""} { + set targetcol 1 + } else { + set targetcol $param + if {![string is integer -strict $targetcol]} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Unrecognised parameter '$param'" + } + set targetcol [expr {$param}] + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$targetcol > $max} { + puts stderr "renderline CHA (Cursor Horizontal Absolute) error. Param '$param' > max: $max" + set targetcol $max + } + } + #adjust to colstart - as column 1 is within overlay + #??? REVIEW + set idx [expr {($targetcol -1) + $opt_colstart -1}] + + + set cursor_column $targetcol + #puts stderr "renderline absolute col move ESC G (TEST)" } H - f { - #$re_both_move - lassign [split $param {;}] row col - set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] - #lassign $matchinfo _match row col + #CSI n;m H - CUP - Cursor Position - if {$col eq ""} {set col 1} - set max [llength $outcols] - if {$overflow_idx == -1} { - incr max - } - if {$col > $max} { - set cursor_column $max + #CSI n;m f - HVP - Horizontal Vertical Position REVIEW - same as CUP with differences (what?) in some terminal modes + # - 'counts as effector format function (like CR or LF) rather than an editor function (like CUD or CNL)' + # - REVIEW + #see Annex A at: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf + + #test e.g ansicat face_2.ans + #$re_both_move + lassign [split $param {;}] paramrow paramcol + #missing defaults to 1 + #CSI ;5H = CSI 1;5H -> row 1 col 5 + #CSI 17;H = CSI 17H = CSI 17;1H -> row 17 col 1 + + if {$paramcol eq ""} {set paramcol 1} + if {$paramrow eq ""} {set paramrow 1} + if {![string is integer -strict $paramcol] || ![string is integer -strict $paramrow]} { + puts stderr "renderline CUP (CSI H) unrecognised param $param" + #ignore? } else { - set cursor_column $col + set max [llength $outcols] + if {$overflow_idx == -1} { + incr max + } + if {$paramcol > $max} { + set target_column $max + } else { + set target_column [expr {$paramcol}] + } + + + if {$paramrow < 1} { + puts stderr "renderline CUP (CSI H) bad row target 0. Assuming 1" + set target_row 1 + } else { + set target_row [expr {$paramrow}] + } + if {$target_row == $cursor_row} { + #col move only - no need for break and move + #puts stderr "renderline CUP col move only to col $target_column param:$param" + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + } else { + set cursor_row $target_row + set cursor_column $target_column + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } } - set idx [expr {$cursor_column -1}] + } + J { + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? + switch -exact -- $modegroup { + ? { + #CSI ? Pn J - selective erase + puts stderr "overtype::renderline ED - SELECTIVE ERASE IN DISPLAY (UNIMPLEMENTED) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + default { + puts stderr "overtype::renderline ED - ERASE IN DISPLAY (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of screen + } + 1 { + #clear from cursor to beginning of screen + } + 2 { + #clear entire screen + #ansi.sys - move cursor to upper left REVIEW + set cursor_row 1 + set cursor_column 1 + set idx [expr {$cursor_column -1}] + set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move + break + } + 3 { + #clear entire screen. presumably cursor doesn't move - otherwise it would be same as 2J ? - if {$row eq ""} {set row 1} - set cursor_row $row - if {$cursor_row < 1} { - set cursor_row 1 + } + default { + } + } + + } } + } + K { + #see DECECM regarding background colour + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? + switch -exact -- $modegroup { + ? { + puts stderr "overtype::renderline DECSEL - SELECTIVE ERASE IN LINE (UNIMPLEMENTED) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + set param [string range $param 1 end] ;#chop qmark + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line - depending on DECSCA + } + 1 { + #clear from cursor to beginning of line - depending on DECSCA - incr idx_over - priv::render_unapplied $overlay_grapheme_control_list $gci - set instruction move - break + } + 2 { + #clear entire line - depending on DECSCA + } + default { + puts stderr "overtype::renderline DECSEL - SELECTIVE ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE (TESTING) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$param eq ""} {set param 0} + switch -exact -- $param { + 0 { + #clear from cursor to end of line + } + 1 { + #clear from cursor to beginning of line + + } + 2 { + #clear entire line + } + default { + puts stderr "overtype::renderline EL - ERASE IN LINE PARAM '$param' unrecognised [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + } + } + } + L { + puts stderr "overtype::renderline IL - Insert Line - not implemented [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + M { + #CSI Pn M - DL - Delete Line + puts stderr "overtype::renderline DL - Delete Line - not implemented [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" } X { - puts stderr "X - $param" + puts stderr "overtype::renderline X ECH ERASE CHARACTER - $param" #ECH - erase character if {$param eq "" || $param eq "0"} {set param 1}; #param=count of chars to erase priv::render_erasechar $idx $param #cursor position doesn't change. } + q { + set code_secondlast [tcl::string::index $codenorm end-1] + switch -exact -- $code_secondlast { + {"} { + #DECSCA - Select Character Protection Attribute + #(for use with selective erase: DECSED and DECSEL) + set param [tcl::string::range $codenorm 4 end-2] + if {$param eq ""} {set param 0} + #TODO - store like SGR in stacks - replays? + switch -exact -- $param { + 0 - 2 { + #canerase + puts stderr "overtype::renderline - DECSCA canerase not implemented - [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + 1 { + #cannoterase + puts stderr "overtype::renderline - DECSCA cannoterase not implemented - [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + default { + puts stderr "overtype::renderline DECSCA param '$param' not understood [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + + } + default { + puts stderr "overtype::renderline - CSI ... q not implemented - [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + } + + } r { #$re_decstbm #https://www.vt100.net/docs/vt510-rm/DECSTBM.html @@ -2789,78 +3201,119 @@ tcl::namespace::eval overtype { break } s { - # - todo - make ansi.sys CSI s cursor save only apply for certain cases? - may need to support DECSLRM instead which uses same code - - #$re_cursor_save - #cursor save could come after last column - if {$overflow_idx != -1 && $idx == $overflow_idx} { - #bartman2.ans test file - fixes misalignment at bottom of dialog bubble - #incr cursor_row - #set cursor_column 1 - #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) - set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] - } else { - set cursor_saved_position [list row $cursor_row column $cursor_column] - } - #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. - #we need the SGR and gx overlay codes prior to the cursor_save + #code conflict between ansi emulation and DECSLRM - REVIEW + #ANSISYSSC (when no parameters) - like other terminals - essentially treat same as DECSC + # todo - when parameters - support DECSLRM instead + + if {$param ne ""} { + #DECSLRM - should only be recognised if DECLRMM is set (vertical split screen mode) + lassign [split $param {;} margin_left margin_right + puts stderr "overtype DECSLRM not yet supported - got [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + if {$margin_left eq ""} { + set margin_left 1 + } + set columns_per_page 80 ;#todo - set to 'page width (DECSCPP set columns per page)' - could be 132 or?? + if {$margin_right eq ""} { + set margin_right $columns_per_page + } + puts stderr "DECSLRM margin left: $margin_left margin right: $margin_right" + if {![string is integer -strict $margin_left] || $margin_left < 0} { + puts stderr "DECSLRM invalid margin_left" + } + if {![string is integer -strict $margin_right] || $margin_right < 0} { + puts stderr "DECSLRM invalid margin_right" + } + set scrolling_region_size [expr {$margin_right - $margin_left}] + if {$scrolling_region_size < 2 || $scrolling_region_size > $columns_per_page} { + puts stderr "DECSLRM region size '$scrolling_regsion_size' must be between 1 and $columns_per_page" + } + #todo - #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. - #set sgr_stack [lindex $understacks $idx] - #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) - - set sgr_stack [list] - set gx_stack [list] - - #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. - #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. - - foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { - lassign $gc type code - #types g other sgr gx0 - switch -- $type { - gx0 { - #code is actually a stand-in for the graphics on/off code - not the raw code - #It is either gx0_on or gx0_off - set gx_stack [list $code] - } - sgr { - #code is the raw code - if {[punk::ansi::codetype::is_sgr_reset $code]} { - #jmn - set sgr_stack [list "\x1b\[m"] - } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { - set sgr_stack [list $code] - lappend overlay_grapheme_control_list [list sgr $code] - } elseif {[priv::is_sgr $code]} { - #often we don't get resets - and codes just pile up. - #as a first step to simplifying - at least remove earlier straight up dupes - set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) - set sgr_stack [lremove $sgr_stack {*}$dup_posns] - lappend sgr_stack $code + + } else { + #DECSC + #//notes on expected behaviour: + #DECSC - saves following items in terminal's memory + #cursor position + #character attributes set by the SGR command + #character sets (G0,G1,G2 or G3) currently in GL and GR + #Wrap flag (autowrap or no autowrap) + #State of origin mode (DECOM) + #selective erase attribute + #any single shift 2 (SS2) or single shift 3(SSD) functions sent + + #$re_cursor_save + #cursor save could come after last column + if {$overflow_idx != -1 && $idx == $overflow_idx} { + #bartman2.ans test file - fixes misalignment at bottom of dialog bubble + #incr cursor_row + #set cursor_column 1 + #bwings1.ans test file - breaks if we actually incr cursor (has repeated saves) + set cursor_saved_position [list row [expr {$cursor_row+1}] column 1] + } else { + set cursor_saved_position [list row $cursor_row column $cursor_column] + } + #there may be overlay stackable codes emitted that aren't in the understacks because they come between the last emmited character and the cursor_save control. + #we need the SGR and gx overlay codes prior to the cursor_save + + #a real terminal would not be able to know the state of the underlay.. so we should probably ignore it. + #set sgr_stack [lindex $understacks $idx] + #set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?) + + set sgr_stack [list] + set gx_stack [list] + + #we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those. + #The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme. + + foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] { + lassign $gc type code + #types g other sgr gx0 + switch -- $type { + gx0 { + #code is actually a stand-in for the graphics on/off code - not the raw code + #It is either gx0_on or gx0_off + set gx_stack [list $code] + } + sgr { + #code is the raw code + if {[punk::ansi::codetype::is_sgr_reset $code]} { + #jmn + set sgr_stack [list "\x1b\[m"] + } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { + set sgr_stack [list $code] + lappend overlay_grapheme_control_list [list sgr $code] + } elseif {[priv::is_sgr $code]} { + #often we don't get resets - and codes just pile up. + #as a first step to simplifying - at least remove earlier straight up dupes + set dup_posns [lsearch -all -exact $sgr_stack $code] ;#needs -exact - codes have square-brackets (glob chars) + set sgr_stack [lremove $sgr_stack {*}$dup_posns] + lappend sgr_stack $code + } } } } - } - set cursor_saved_attributes "" - switch -- [lindex $gx_stack 0] { - gx0_on { - append cursor_saved_attributes "\x1b(0" - } - gx0_off { - append cursor_saved_attributes "\x1b(B" + set cursor_saved_attributes "" + switch -- [lindex $gx_stack 0] { + gx0_on { + append cursor_saved_attributes "\x1b(0" + } + gx0_off { + append cursor_saved_attributes "\x1b(B" + } } - } - #append cursor_saved_attributes [join $sgr_stack ""] - append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] + #append cursor_saved_attributes [join $sgr_stack ""] + append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack] - #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. + #as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save. - #don't incr index - or the save will cause cursor to move to the right - #carry on - + #don't incr index - or the save will cause cursor to move to the right + #carry on + } } u { + #ANSISYSRC save cursor (when no parameters) (DECSC) + #$re_cursor_restore #we are going to jump somewhere.. for now we will assume another line, and process accordingly. #The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line) @@ -2901,135 +3354,260 @@ tcl::namespace::eval overtype { set instruction restore_cursor break } + "{" { + + puts stderr "renderline warning - CSI.. - unimplemented [ansistring VIEW -lf 1 -nul 1 $code]" + } + "}" { + set code_secondlast [tcl::string::index $codenorm end-1] + switch -exact -- $code_secondlast { + ' { + puts stderr "renderline warning - DECIC - Insert Column - CSI...' - unimplemented [ansistring VIEW -lf 1 -nul 1 $code]" + } + default { + puts stderr "renderline warning - CSI.. - unimplemented [ansistring VIEW -lf 1 -nul 1 $code]" + } + } + } ~ { - #$re_vt_sequence - #lassign $matchinfo _match key mod - lassign [split $param {;}] key mod - - #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ - # - #e.g esc \[2~ insert esc \[2;2~ shift-insert - #mod - subtract 1, and then use bitmask - #shift = 1, (left)Alt = 2, control=4, meta=8 (meta seems to do nothing on many terminals on windows? Intercepted by windows?) - #puts stderr "vt key:$key mod:$mod code:[ansistring VIEW $code]" - if {$key eq "1"} { - #home - } elseif {$key eq "2"} { - #Insert - if {$mod eq ""} { - #no modifier key - set insert_mode [expr {!$insert_mode}] - #rather than set the cursor - we return the insert mode state so the caller can decide + set code_secondlast [tcl::string::index $codenorm end-1] ;#used for e.g CSI x '~ + switch -exact -- $code_secondlast { + ' { + #DECDC - editing sequence - Delete Column + puts stderr "renderline warning - DECDC - unimplemented" } - } elseif {$key eq "3"} { - #Delete - presumably this shifts other chars in the line, with empty cells coming in from the end - switch -- $mod { - "" { - priv::render_delchar $idx - } - "5" { - #ctrl-del - delete to end of word (pwsh) - possibly word on next line if current line empty(?) + default { + #$re_vt_sequence + lassign [split $param {;}] key mod + + #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~ + # + #e.g esc \[2~ insert esc \[2;2~ shift-insert + #mod - subtract 1, and then use bitmask + #shift = 1, (left)Alt = 2, control=4, meta=8 (meta seems to do nothing on many terminals on windows? Intercepted by windows?) + #puts stderr "vt key:$key mod:$mod code:[ansistring VIEW $code]" + if {$key eq "1"} { + #home + } elseif {$key eq "2"} { + #Insert + if {$mod eq ""} { + #no modifier key + set insert_mode [expr {!$insert_mode}] + #rather than set the cursor - we return the insert mode state so the caller can decide + } + } elseif {$key eq "3"} { + #Delete - presumably this shifts other chars in the line, with empty cells coming in from the end + switch -- $mod { + "" { + priv::render_delchar $idx + } + "5" { + #ctrl-del - delete to end of word (pwsh) - possibly word on next line if current line empty(?) + } + } + } elseif {$key eq "4"} { + #End + } elseif {$key eq "5"} { + #pgup + } elseif {$key eq "6"} { + #pgDn + } elseif {$key eq "7"} { + #Home + #?? + set idx [expr {$opt_colstart -1}] + set cursor_column 1 + } elseif {$key eq "8"} { + #End + } elseif {$key eq "11"} { + #F1 - or ESCOP or e.g shift F1 ESC\[1;2P + } elseif {$key eq "12"} { + #F2 - or ESCOQ + } elseif {$key eq "13"} { + #F3 - or ESCOR + } elseif {$key eq "14"} { + #F4 - or ESCOS + } elseif {$key eq "15"} { + #F5 or shift F5 ESC\[15;2~ + } elseif {$key eq "17"} { + #F6 + } elseif {$key eq "18"} { + #F7 + } elseif {$key eq "19"} { + #F8 + } elseif {$key eq "20"} { + #F9 + } elseif {$key eq "21"} { + #F10 + } elseif {$key eq "23"} { + #F11 + } elseif {$key eq "24"} { + #F12 } + } - } elseif {$key eq "4"} { - #End - } elseif {$key eq "5"} { - #pgup - } elseif {$key eq "6"} { - #pgDn - } elseif {$key eq "7"} { - #Home - #?? - set idx [expr {$opt_colstart -1}] - set cursor_column 1 - } elseif {$key eq "8"} { - #End - } elseif {$key eq "11"} { - #F1 - or ESCOP or e.g shift F1 ESC\[1;2P - } elseif {$key eq "12"} { - #F2 - or ESCOQ - } elseif {$key eq "13"} { - #F3 - or ESCOR - } elseif {$key eq "14"} { - #F4 - or ESCOS - } elseif {$key eq "15"} { - #F5 or shift F5 ESC\[15;2~ - } elseif {$key eq "17"} { - #F6 - } elseif {$key eq "18"} { - #F7 - } elseif {$key eq "19"} { - #F8 - } elseif {$key eq "20"} { - #F9 - } elseif {$key eq "21"} { - #F10 - } elseif {$key eq "23"} { - #F11 - } elseif {$key eq "24"} { - #F12 } } h - l { + #set mode unset mode #we are matching only last char to get to this arm - but are there other sequences ending in h|l we need to handle? #$re_mode if first after CSI is "?" #some docs mention ESC=h|l - not seen on windows terminals.. review #e.g https://www2.math.upenn.edu/~kazdan/210/computer/ansi.html - if {[tcl::string::index $codenorm 4] eq "?"} { - set num [tcl::string::range $codenorm 5 end-1] ;#param between ? and h|l - #lassign $matchinfo _match num type - switch -- $num { - 5 { - #DECSNM - reverse video - #How we simulate this to render within a block of text is an open question. - #track all SGR stacks and constantly flip based on the current SGR reverse state? - #It is the job of the calling loop to do this - so at this stage we'll just set the states - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set reverse_mode 1 - } else { - #reset (disable) - set reverse_mode 0 - } + set modegroup [tcl::string::index $codenorm 4] ;#e.g ? = + switch -exact -- $modegroup { + ? { + set smparams [tcl::string::range $codenorm 5 end-1] ;#params between ? and h|l + #one or more modes can be set + set smparam_list [split $smparams {;}] + foreach num $smparam_list { + switch -- $num { + "" { + #ignore empties e.g extra/trailing semicolon in params + } + 5 { + #DECSNM - reverse video + #How we simulate this to render within a block of text is an open question. + #track all SGR stacks and constantly flip based on the current SGR reverse state? + #It is the job of the calling loop to do this - so at this stage we'll just set the states + + if {$code_end eq "h"} { + #set (enable) + set reverse_mode 1 + } else { + #reset (disable) + set reverse_mode 0 + } + + } + 7 { + #DECAWM autowrap + if {$code_end eq "h"} { + #set (enable) + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } + #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? + # presume not usually - but sanity check with warning for now. + if {$idx >= $overflow_idx} { + puts stderr "renderline warning - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + } else { + #reset (disable) + set autowrap_mode 0 + #REVIEW! + set overflow_idx -1 + } + } + 25 { + if {$code_end eq "h"} { + #visible cursor + + } else { + #invisible cursor + } + } + 117 { + #DECECM - Erase Color Mode + #https://invisible-island.net/ncurses/ncurses.faq.html + #The Erase color selection controls the background color used when text is erased or new + #text is scrolled on to the screen. Screen background causes newly erased areas or + #scrolled text to be written using color index zero, the screen background. This is VT + #and DECterm compatible. Text background causes erased areas or scrolled text to be + #written using the current text background color. This is PC console compatible and is + #the factory default. + + #see also: https://unix.stackexchange.com/questions/251726/clear-to-end-of-line-uses-the-wrong-background-color-in-screen + } + } } - 7 { - #DECAWM autowrap - if {$type eq "h"} { - #set (enable) - set autowrap_mode 1 - if {$opt_width ne "\uFFEF"} { - set overflow_idx $opt_width + } + = { + set num [tcl::string::range $codenorm 5 end-1] ;#param between = and h|l + puts stderr "overtype::renderline CSI=...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + #e.g CSI 4 h + set num [tcl::string::range $codenorm 4 end-1] ;#param before h|l + switch -exact -- $num { + 3 { + puts stderr "CRM MODE $code_end" + #CRM - Show control character mode + # 'No control functions are executed except LF,FF and VT which are represented in the CRM FONT before a CRLF(new line) is executed' + # + #use ansistring VIEW -nul 1 -lf 2 -ff 2 -vt 2 + #https://vt100.net/docs/vt510-rm/CRM.html + #NOTE - vt100 CRM always does auto-wrap at right margin. + #disabling auto-wrap in set-up or by sequence is disabled. + #We should default to turning off auto-wrap when crm_mode enabled.. but + #displaying truncated (on rhs) crm can still be very useful - and we have optimisation in overflow to avoid excess renderline calls (per grapheme) + #we therefore could reasonably put in an exception to allow auto_wrap to be disabled after crm_mode is engaged, + #although this would be potentially an annoying difference to some.. REVIEW + if {$code_end eq "h"} { + set crm_mode 1 + set autowrap_mode 1 + if {$opt_width ne "\uFFEF"} { + set overflow_idx $opt_width + } else { + #review - this is also the cursor position when adding a char at end of line? + set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + } } else { - #review - this is also the cursor position when adding a char at end of line? - set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it + set crm_mode 0 } - #review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now. - if {$idx >= $overflow_idx} { - puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected" + } + 4 { + #IRM - Insert/Replace Mode + if {$code_end eq "h"} { + #CSI 4 h + set insert_mode 1 + } else { + #CSI 4 l + #replace mode + set insert_mode 0 } - } else { - #reset (disable) - set autowrap_mode 0 - set overflow_idx -1 } + default { + puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + } + } + } + } + | { + switch -- [tcl::string::index $codenorm end-1] { + {$} { + #CSI ... $ | DECSCPP set columns per page- (recommended in vt510 docs as preferable to DECCOLM) + #real terminals generally only supported 80/132 + #some other virtuals support any where from 2 to 65,536? + #we will allow arbitrary widths >= 2 .. to some as yet undetermined limit. + #CSI $ | + #empty or 0 param is 80 for compatibility - other numbers > 2 accepted + set page_width -1 ;#flag as unset + if {$param eq ""} { + set page_width 80 + } elseif {[string is integer -strict $param] && $param >=2 0} { + set page_width [expr {$param}] ;#we should allow leading zeros in the number - but lets normalize using expr + } else { + puts stderr "overtype::renderline unacceptable DECSPP value '$param'" } - 25 { - if {$type eq "h"} { - #visible cursor - } else { - #invisible cursor + if {$page_width > 2} { + puts stderr "overtype::renderline DECSCPP - not implemented - but selected width '$page_width' looks ok" + #if cursor already beyond new page_width - will move to right colum - otherwise no cursor movement - } } - } - } else { - puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } + default { + puts stderr "overtype::renderline unrecognised CSI code ending in pipe (|) [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + } } } default { @@ -3038,24 +3616,49 @@ tcl::namespace::eval overtype { } } 7ESC { - #$re_other_single - switch -- [tcl::string::index $codenorm end] { + # + #re_other_single {\x1b(D|M|E)$} + #also PM \x1b^...(ST) + switch -- [tcl::string::index $codenorm 4] { + c { + #RIS - reset terminal to initial state - where 'terminal' in this case is the renderspace - not the underlying terminal! + puts stderr "renderline reset" + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction reset + break + } D { #\x84 #index (IND) #vt102-docs: "Moves cursor down one line in same column. If cursor is at bottom margin, screen performs a scroll-up" - puts stderr "ESC D not fully implemented" + puts stderr "renderline ESC D not fully implemented" incr cursor_row priv::render_unapplied $overlay_grapheme_control_list $gci set instruction down #retain cursor_column break } + E { + #\x85 + #review - is behaviour different to lf? + #todo - possibly(?) same logic as handling above. i.e return instruction depends on where column_cursor is at the time we get NEL + #leave implementation until logic for is set in stone... still under review + #It's arguable NEL is a pure cursor movement as opposed to the semantic meaning of crlf or lf in a file. + # + #Next Line (NEL) "Move the cursor to the left margin on the next line. If the cursor is at the bottom margin, scroll the page up" + puts stderr "overtype::renderline ESC E unimplemented" + + } + H { + #\x88 + #Tab Set + puts stderr "overtype::renderline ESC H tab set unimplemented" + } M { #\x8D #Reverse Index (RI) #vt102-docs: "Moves cursor up one line in same column. If cursor is at top margin, screen performs a scroll-down" - puts stderr "ESC M not fully implemented" + puts stderr "overtype::renderline ESC M not fully implemented" set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] #move up @@ -3069,31 +3672,89 @@ tcl::namespace::eval overtype { #retain cursor_column break } - E { - #\x85 - #review - is behaviour different to lf? - #todo - possibly(?) same logic as handling above. i.e return instruction depends on where column_cursor is at the time we get NEL - #leave implementation until logic for is set in stone... still under review - #It's arguable NEL is a pure cursor movement as opposed to the semantic meaning of crlf or lf in a file. - # - #Next Line (NEL) "Move the cursor to the left margin on the next line. If the cursor is at the bottom margin, scroll the page up" - puts stderr "ESC E unimplemented" + N { + #\x8e - affects next character only + puts stderr "overtype::renderline single shift select G2 command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + O { + #\x8f - affects next character only + puts stderr "overtype::renderline single shift select G3 command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + P { + #\x90 + #DCS - shouldn't get here - handled in 7DCS branch + #similarly \] OSC (\x9d) and \\ (\x9c) ST + } + V { + #\x96 } + W { + #\x97 + } + X { + #\x98 + #SOS + if {[string index $code end] eq "\007"} { + set sos_content [string range $code 2 end-1] ;#ST is \007 + } else { + set sos_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #return in some useful form to the caller + #TODO! + lappend sos_list [list string $sos_content row $cursor_row column $cursor_column] + puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } + ^ { + #puts stderr "renderline PM" + #Privacy Message. + if {[string index $code end] eq "\007"} { + set pm_content [string range $code 2 end-1] ;#ST is \007 + } else { + set pm_content [string range $code 2 end-2] ;#ST is \x1b\\ + } + #We don't want to render it - but we need to make it available to the application + #see the textblock library in punk, for the exception we make here for single backspace. + #It is unlikely to be encountered as a useful PM - so we hack to pass it through as a fix + #for spacing issues on old terminals which miscalculate the single-width 'Symbols for Legacy Computing' + if {$pm_content eq "\b"} { + #puts stderr "renderline PM sole backspace special handling for \U1FB00 - \U1FBFF" + #esc^\b\007 or esc^\besc\\ + #HACKY pass-through - targeting terminals that both mis-space legacy symbols *and* don't support PMs + #The result is repair of the extra space. If the terminal is a modern one and does support PM - the \b should be hidden anyway. + #If the terminal has the space problem AND does support PMs - then this just won't fix it. + #The fix relies on the symbol-supplier to cooperate by appending esc^\b\esc\\ to the problematic symbols. + + #priv::render_addchar $idx $code [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode + #idx has been incremented after last grapheme added + priv::render_append_to_char [expr {$idx -1}] $code + } + #lappend to a dict element in the result for application-specific processing + lappend pm_list $pm_content + } + _ { + #APC Application Program Command + #just warn for now.. + puts stderr "overtype::renderline ESC_ APC command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + } default { - puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" + puts stderr "overtype::renderline ESC code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented codenorm:[ansistring VIEW -lf 1 -vt 1 -nul 1 $codenorm]" } } } + 7DCS { + puts stderr "overtype::renderline DCS - DEVICE CONTROL STRING command UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]" + # + + } + 7OSC - 8OSC { + + } + default { + } } - #switch -regexp -matchvar matchinfo -- $code\ - #$re_mode { - #}\ - #default { - # puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" - #} } default { @@ -3104,7 +3765,7 @@ tcl::namespace::eval overtype { } #-------- - if {$opt_overflow == 0} { + if {$opt_expand_right == 0} { #need to truncate to the width of the original undertext #review - string_width vs printing_length here. undertext requirement to be already rendered therefore punk::char::string_width ok? #set num_under_columns [punk::char::string_width $pt_underchars] ;#plaintext underchars @@ -3275,20 +3936,24 @@ tcl::namespace::eval overtype { overflow_right $overflow_right\ unapplied $unapplied\ unapplied_list $unapplied_list\ - insert_mode $insert_mode\ - autowrap_mode $autowrap_mode\ + insert_mode $insert_mode\ + autowrap_mode $autowrap_mode\ + crm_mode $crm_mode\ + reverse_mode $reverse_mode\ insert_lines_above $insert_lines_above\ insert_lines_below $insert_lines_below\ cursor_saved_position $cursor_saved_position\ cursor_saved_attributes $cursor_saved_attributes\ cursor_column $cursor_column\ cursor_row $cursor_row\ - opt_overflow $opt_overflow\ + expand_right $opt_expand_right\ replay_codes $replay_codes\ replay_codes_underlay $replay_codes_underlay\ replay_codes_overlay $replay_codes_overlay\ + pm_list $pm_list\ ] if {$opt_returnextra == 1} { + #puts stderr "renderline: $result" return $result } else { #human/debug - map special chars to visual glyphs @@ -3313,6 +3978,7 @@ tcl::namespace::eval overtype { return $result } } else { + #puts stderr "renderline returning: result $outstring instruction $instruction unapplied $unapplied overflow_right $overflow_right" return $outstring } #return [join $out ""] @@ -3370,8 +4036,9 @@ tcl::namespace::eval overtype::piper { } interp alias "" piper_renderline "" overtype::piper::renderline -#intended for single grapheme - but will work for multiple -#cannot contain ansi or newlines +#intended primarily for single grapheme - but will work for multiple +#WARNING: query CAN contain ansi or newlines - but if cache was not already set manually,the answer will be incorrect! +#We deliberately allow this for PM/SOS attached within a column #(a cache of ansifreestring_width calls - as these are quite regex heavy) proc overtype::grapheme_width_cached {ch} { variable grapheme_widths @@ -3439,6 +4106,7 @@ tcl::namespace::eval overtype::priv { tcl::dict::set cache_is_sgr $code $answer return $answer } + # better named render_to_unapplied? proc render_unapplied {overlay_grapheme_control_list gci} { upvar idx_over idx_over upvar unapplied unapplied @@ -3532,7 +4200,7 @@ tcl::namespace::eval overtype::priv { set ustacks [lreplace $ustacks $i $i] set gxstacks [lreplace $gxstacks $i $i] } else { - + puts stderr "render_delchar - attempt to delchar at index $i >= number of outcols $nxt - shouldn't happen" } } proc render_erasechar {i count} { @@ -3563,21 +4231,68 @@ tcl::namespace::eval overtype::priv { upvar outcols o lset o $i $c } + + #Initial usecase is for old-terminal hack to add PM-wrapped \b + #review - can be used for other multibyte sequences that occupy one column? + #combiners? diacritics? + proc render_append_to_char {i c} { + upvar outcols o + if {$i > [llength $o]-1} { + error "render_append_to_char cannot append [ansistring VIEW -lf 1 -nul 1 $c] to existing char at index $i while $i >= llength outcols [llength $o]" + } + set existing [lindex $o $i] + if {$existing eq "\0"} { + lset o $i $c + } else { + lset o $i [string cat $existing $c] + } + } #is actually addgrapheme? proc render_addchar {i c sgrstack gx0stack {insert_mode 0}} { upvar outcols o upvar understacks ustacks upvar understacks_gx gxstacks - if 0 { - if {$c eq "c"} { - puts "i:$i c:$c sgrstack:[ansistring VIEW $sgrstack]" - puts "understacks:[ansistring VIEW $ustacks]" - upvar overstacks overstacks - puts "overstacks:[ansistring VIEW $overstacks]" - puts "info level 0:[info level 0]" - } + # -- --- --- + #this is somewhat of a hack.. probably not really the equivalent of proper reverse video? review + #we should ideally be able to reverse the video of a sequence that already includes SGR reverse/noreverse attributes + upvar reverse_mode do_reverse + #if {$do_reverse} { + # lappend sgrstack [a+ reverse] + #} else { + # lappend sgrstack [a+ noreverse] + #} + + #JMN3 + if {$do_reverse} { + #note we can't just look for \x1b\[7m or \x1b\[27m + # it may be a more complex sequence like \x1b\[0\;\;7\;31m etc + + set existing_reverse_state 0 + set codeinfo [punk::ansi::codetype::sgr_merge $sgrstack -info 1] + set codestate_reverse [dict get $codeinfo codestate reverse] + switch -- $codestate_reverse { + 7 { + set existing_reverse_state 1 + } + 27 { + set existing_reverse_state 0 + } + "" { + } + } + if {$existing_reverse_state == 0} { + set rflip [a+ reverse] + } else { + #reverse of reverse + set rflip [a+ noreverse] + } + #note that mergeresult can have multiple esc (due to unmergeables or non sgr codes) + set sgrstack [list [dict get $codeinfo mergeresult] $rflip] + #set sgrstack [punk::ansi::codetype::sgr_merge [list [dict get $codeinfo mergeresult] $rflip]] } + + # -- --- --- set nxt [llength $o] if {!$insert_mode} { diff --git a/src/vfs/_vfscommon/modules/punk/ansi-0.1.1.tm b/src/vfs/_vfscommon/modules/punk/ansi-0.1.1.tm index 85cb9f27..267e680e 100644 --- a/src/vfs/_vfscommon/modules/punk/ansi-0.1.1.tm +++ b/src/vfs/_vfscommon/modules/punk/ansi-0.1.1.tm @@ -106,7 +106,7 @@ tcl::namespace::eval punk::ansi::class { #overflow is a different concept - perhaps not particularly congruent with the idea of the textblock as a mini terminal emulator. #overflow effectively auto-expands the block(terminal?) width #overflow and wrap both being true won't make sense unless we implement a max_overflow concept - set o_rendered [overtype::renderspace -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] + set o_rendered [overtype::renderspace -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] if {$cksum eq "not-done"} { #if dimensions changed - the checksum won't have been done set o_rendered_what [$o_ansistringobj checksum] @@ -129,7 +129,7 @@ tcl::namespace::eval punk::ansi::class { set o_dimensions $dimensions - set rendered [overtype::renderspace -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] + set rendered [overtype::renderspace -cp437 1 -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]] return $rendered } method render_to_input_line {args} { @@ -176,7 +176,7 @@ tcl::namespace::eval punk::ansi::class { if {$opt_minus ne "0"} { set chunk [tcl::string::range $chunk 0 end-$opt_minus] } - set rendered [overtype::renderspace -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk] + set rendered [overtype::renderspace -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk] set marker "" for {set i 1} {$i <= $w} {incr i} { if {$i % 10 == 0} { @@ -514,11 +514,8 @@ tcl::namespace::eval punk::ansi { set encnames [encoding names] set encoding "" set dimensions "" - set test_mode 0 foreach a $args { - if {$a eq "test_mode"} { - set test_mode 1 - } elseif {$a in $encnames} { + if {$a in $encnames} { set encoding $a } else { if {[regexp {[0-9]+(?:x|X)[0-9]+} $a]} { @@ -553,28 +550,51 @@ tcl::namespace::eval punk::ansi { $obj destroy return $result } - proc example {} { + proc example {args} { + set base [punk::repo::find_project] + set default_ansibase [file join $base src/testansi] + + set argd [punk::args::get_dict [tstr -return string { + *proc -name punk::ansi::example -help "Display .ans image files in a grid that will fit in console + " + -colwidth -default 82 -help "Width of each column - default of 82 will fit a standard 80wide ansi image (when framed) + You can specify a narrower width to truncate images on the right side" + -folder -default "${$default_ansibase}" -help "Base folder for files if relative paths are used. + Defaults to /src/testansi - where projectbase is determined from current directory. + " + *values -min 0 -max -1 + files -default {belinda.ans bot.ans flower.ans fish.ans} -multiple true -help "List of filenames - leave empty to display 4 defaults" + }] $args] + set colwidth [dict get $argd opts -colwidth] + set ansibase [file normalize [dict get $argd opts -folder]] + set fnames [dict get $argd values files] + + #assumes fixed column widths e.g 80col images will fit in 82-width frames (common standard for old ansi art) (of arbitrary height) #todo - review dependency on punk::repo ? package require textblock package require punk::repo package require punk::console - set fnames [list belinda.ans bot.ans flower.ans fish.ans] - set base [punk::repo::find_project] - set ansibase [file join $base src/testansi] if {![file exists $ansibase]} { - puts stderr "Missing testansi folder at $base/src/testansi" + puts stderr "Missing folder at $ansibase" puts stderr "Ensure ansi test files exist: $fnames" #error "punk::ansi::example Cannot find example files" } - set missingbase [a+ yellow][textblock::block 80 23 ?][a] + set missingbase [a+ yellow][textblock::block [expr {$colwidth-2}] 23 ?][a] ;#assuming standard frame - subtract 2 for left/right borders set pics [list] foreach f $fnames { - if {![file exists $ansibase/$f]} { - set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$ansibase/$f[a]"] + if {[file pathtype $f] ne "absolute"} { + set filepath [file normalize $ansibase/$f] + } else { + set filepath [file normalize $f] + } + if {![file exists $filepath]} { + set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$f[a]"] lappend pics [tcl::dict::create filename $f pic $p status missing] } else { - set img [join [lines_as_list -line trimline -block trimtail [ansicat $ansibase/$f]] \n] + #set img [join [lines_as_list -line trimline -block trimtail [ansicat $filepath]] \n] + #-line trimline will wreck some images + set img [join [lines_as_list -block trimtail [ansicat $filepath]] \n] lappend pics [tcl::dict::create filename $f pic $img status ok] } } @@ -582,30 +602,73 @@ tcl::namespace::eval punk::ansi { set termsize [punk::console:::get_size] set margin 4 set freewidth [expr {[tcl::dict::get $termsize columns]-$margin}] - set per_row [expr {$freewidth / 80}] - - set rowlist [list] - set row [list] - set i 1 + set per_row [expr {$freewidth / $colwidth}] + + set rowlist [list] ;# { { } { } } + set heightlist [list] ;# { { } { } } + set maxheights [list] ;# { } + set row [list] ;#wip row + set rowh [list] ;#wip row img heights + set i 1 ;#track image index of whole pics list + set rowindex 0 foreach picinfo $pics { set subtitle "" if {[tcl::dict::get $picinfo status] ne "ok"} { set subtitle [tcl::dict::get $picinfo status] } set title [tcl::dict::get $picinfo filename] - lappend row [textblock::frame -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + set fr [textblock::frame -width $colwidth -subtitle $subtitle -title $title [tcl::dict::get $picinfo pic]] + # -- --- --- --- + #we need the max height of a row element to use join_basic instead of join below + # -- --- --- --- + set fr_height [textblock::height $fr] + lappend row $fr + lappend rowh $fr_height + + set rowmax [lindex $maxheights $rowindex] + if {$rowmax eq ""} { + #empty result means no maxheights entry for this row yet + set rowmax $fr_height + lappend maxheights $rowmax + } else { + if {$fr_height > $rowmax} { + set rowmax $fr_height + lset maxheights end $rowmax + } + } + # -- --- --- --- + if {$i % $per_row == 0} { lappend rowlist $row + lappend heightlist $rowh + incr rowindex set row [list] + set rowh [list] } elseif {$i == [llength $pics]} { lappend rowlist $row + lappend heightlist $rowh } incr i } - + #puts "--> maxheights: $maxheights" + #puts "--> heightlist: $heightlist" set result "" - foreach r $rowlist { - append result [textblock::join_basic -- {*}$r] \n + set rowindex 0 + set blankline [string repeat " " $colwidth] + foreach imgs $rowlist heights $heightlist { + set maxheight [lindex $maxheights $rowindex] + set adjusted_row [list] + foreach i $imgs h $heights { + if {$h < $maxheight} { + #add blank lines to bottom of shorter images so join_basic can be used. + #textblock::join of ragged-height images would work and remove the need for all the height calculation + #.. but it requires much more processing + append i [string repeat \n$blankline [expr {$maxheight - $h}]] + } + lappend adjusted_row $i + } + append result [textblock::join_basic -- {*}$adjusted_row] \n + incr rowindex } @@ -3199,6 +3262,28 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu return \x1b8 } # -- --- --- --- --- + #CRM Show Control Character Mode + proc enable_crm {} { + return \x1b\[3h + } + proc disable_crm {} { + return \x1b\[3l + } + + #DECSNM + #Note this can invert the enclosed section including any already reversed by SGR 7 - depending on terminal support. + #e.g + #set test [a+ reverse]aaa[a+ noreverse]bbb + # - $test above can't just be reversed by putting another [a+ reverse] in front of it. + # - but the following will work (even if underlying terminal doesn't support ?5 sequences) + #overtype::renderspace -width 20 [enable_inverse]$test + proc enable_inverse {} { + return \x1b\[?5h + } + proc disable_inverse {} { + return \x1b\[?5l + } + #DECAWM - automatic line wrapping proc enable_line_wrap {} { @@ -3399,6 +3484,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu #the purpose of backspace (or line cr) in embedded text is unclear. Should it allow some sort of character combining/overstrike as it has sometimes done historically (nroff/less)? e.g a\b` as an alternative combiner or bolding if same char #This should presumably only be done if the over_strike (os) capability is enabled in the terminal. Either way - it presumably won't affect printing width? set line [punk::ansi::ansistrip $line] + #ANSI (e.g PM/SOS) can contain \b or \n or \t but won't contribute to length + #ansistrip must come before any other processing of these chars. + #we can't use simple \b processing if we get ansi codes and aren't actually processing them (e.g moves) set line [punk::char::strip_nonprinting_ascii $line] ;#only strip nonprinting after ansistrip - some like BEL are part of ansi @@ -3748,6 +3836,7 @@ tcl::namespace::eval punk::ansi { -filter_fg 0\ -filter_bg 0\ -filter_reset 0\ + -info 0\ ] #codes *must* already have been split so that one esc per element in codelist @@ -3760,7 +3849,8 @@ tcl::namespace::eval punk::ansi { set opts $defaultopts_sgr_merge_singles foreach {k v} $args { switch -- $k { - -filter_fg - -filter_bg - -filter_reset { + -filter_fg - -filter_bg - -filter_reset - + -info { tcl::dict::set opts $k $v } default { @@ -4139,19 +4229,24 @@ tcl::namespace::eval punk::ansi { set codemerge [tcl::string::trimright $codemerge {;}] if {$unmergeable ne ""} { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m\x1b\[${unmergeable}m[join $othercodes ""]" } else { - return "\x1b\[${codemerge}m[join $othercodes ""]" + set mergeresult "\x1b\[${codemerge}m[join $othercodes ""]" } } else { if {$unmergeable eq ""} { #there were no SGR codes - not even resets - return [join $othercodes ""] + set mergeresult [join $othercodes ""] } else { set unmergeable [tcl::string::trimright $unmergeable {;}] - return "\x1b\[${unmergeable}m[join $othercodes ""]" + set mergeresult "\x1b\[${unmergeable}m[join $othercodes ""]" } } + if {[tcl::dict::get $opts -info]} { + return [dict create sgr $codemerge unmergeable $unmergeable othercodes $othercodes mergeresult $mergeresult codestate $codestate] + } else { + return $mergeresult + } } #has_sgr_reset - rather than support this function - create an sgr normalize function that removes dead params and brings reset to front of param list? @@ -4240,7 +4335,7 @@ tcl::namespace::eval punk::ansi::ta { #we also need to track the start of ST terminated code and not add it for replay (in the ansistring functions) #variable re_ST {(?:\x1bX|\u0098|\x1b\^|\u009E|\x1b_|\u009F)(?:[^\x1b\007\u009c]*)(?:\x1b\\|\007|\u009c)} ;#downsides: early terminating with nests, mixes 7bit 8bit start/ends (does that exist in the wild?) #keep our 8bit/7bit start-end codes separate - variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} + variable re_ST {(?:\x1bP|\x1bX|\x1b\^|\x1b_)(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007)|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)} @@ -4252,7 +4347,7 @@ tcl::namespace::eval punk::ansi::ta { # -- --- --- --- #handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regext TRIE generator that works with Tcl regexes #This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone. - variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} + variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c} # -- --- --- --- @@ -5674,7 +5769,12 @@ tcl::namespace::eval punk::ansi::ansistring { ENQ [list \x05 \u2405]\ ACK [list \x06 \u2406]\ BEL [list \x07 \u2407]\ + BS [list \x08 \u2408]\ + HT [list \x09 \u2409]\ + LF [list \x0a \u240a]\ + VT [list \x0b \u240b]\ FF [list \x0c \u240c]\ + CR [list \x0d \u240d]\ SO [list \x0e \u240e]\ SF [list \x0f \u240f]\ DLE [list \x10 \u2410]\ @@ -5688,12 +5788,15 @@ tcl::namespace::eval punk::ansi::ansistring { CAN [list \x18 \u2418]\ EM [list \x19 \u2419]\ SUB [list \x1a \u241a]\ + ESC [list \x1b \u241b]\ FS [list \x1c \u241c]\ GS [list \x1d \u241d]\ RS [list \x1e \u241e]\ US [list \x1f \u241f]\ + SP [list \x20 \u2420]\ DEL [list \x7f \u2421]\ ] + #alternate symbols for space # \u2422 Blank Symbol (b with forwardslash overly) # \u2423 Open Box (square bracket facing up like a tray/box) @@ -5836,6 +5939,7 @@ tcl::namespace::eval punk::ansi::ansistring { -cr 1\ -lf 0\ -vt 0\ + -ff 1\ -ht 1\ -bs 1\ -sp 1\ @@ -5850,16 +5954,22 @@ tcl::namespace::eval punk::ansi::ansistring { set opt_cr [tcl::dict::get $opts -cr] set opt_lf [tcl::dict::get $opts -lf] set opt_vt [tcl::dict::get $opts -vt] + set opt_ff [tcl::dict::get $opts -ff] set opt_ht [tcl::dict::get $opts -ht] set opt_bs [tcl::dict::get $opts -bs] set opt_sp [tcl::dict::get $opts -sp] # -- --- --- --- --- + # -lf 2, -vt 2 and -ff 2 are useful for CRM mode (Show Control Character Mode) in the terminal - where a newline is expected to display after the character. set visuals_opt $debug_visuals + set visuals_opt [dict remove $visuals_opt CR ESC LF VT FF HT BS SP] + if {$opt_esc} { tcl::dict::set visuals_opt ESC [list \x1b \u241b] + } else { + tcl::dict::unset visuals_opt ESC } if {$opt_cr} { tcl::dict::set visuals_opt CR [list \x0d \u240d] @@ -5870,9 +5980,20 @@ tcl::namespace::eval punk::ansi::ansistring { if {$opt_lf == 2} { tcl::dict::set visuals_opt LF [list \x0a \u240a\n] } - if {$opt_vt} { + if {$opt_vt == 1} { tcl::dict::set visuals_opt VT [list \x0b \u240b] } + if {$opt_vt == 2} { + tcl::dict::set visuals_opt VT [list \x0b \u240b\n] + } + switch -exact -- $opt_ff { + 1 { + tcl::dict::set visuals_opt FF [list \x0c \u240c] + } + 2 { + tcl::dict::set visuals_opt FF [list \x0c \u240c\n] + } + } if {$opt_ht} { tcl::dict::set visuals_opt HT [list \x09 \u2409] } diff --git a/src/vfs/_vfscommon/modules/punk/basictelnet-0.1.0.tm b/src/vfs/_vfscommon/modules/punk/basictelnet-0.1.0.tm index d2b0cd10..6a5c481d 100644 --- a/src/vfs/_vfscommon/modules/punk/basictelnet-0.1.0.tm +++ b/src/vfs/_vfscommon/modules/punk/basictelnet-0.1.0.tm @@ -531,7 +531,7 @@ namespace eval punk::basictelnet { # -- --- --- --- set tailinfo "" if {[string length $nextwaiting]} { - set waitingdisplay [overtype::renderspace -wrap 1 -width 77 -height 1 "" [ansistring VIEW -lf 1 -vt 1 $nextwaiting]] + set waitingdisplay [overtype::renderspace -cp437 1 -wrap 1 -width 77 -height 1 "" [ansistring VIEW -lf 1 -vt 1 $nextwaiting]] set tailinfo "[a+ red]from waiting:\n $waitingdisplay[a]" } ::punk::basictelnet::add_debug "[a+ Yellow black]from stdin sending: [ansistring VIEW -lf 1 -vt 1 $chunk][a]\n$tailinfo\n" stdin $sock @@ -629,7 +629,7 @@ namespace eval punk::basictelnet { #set rawview [ansistring VIEW -lf 1 -vt 1 [encoding convertfrom $encoding_guess $data]] set rawview [ansistring VIEW -lf 1 -vt 1 $data] #set viewblock [overtype::left -wrap 1 -width 78 -height 4 "" $rawview] - set viewblock [overtype::renderspace -experimental test_mode -wrap 1 -width 78 -height 4 "" $rawview] + set viewblock [overtype::renderspace -cp437 1 -wrap 1 -width 78 -height 4 "" $rawview] set lines [split $viewblock \n] if {[llength $lines] > 4} { append debug_info [join [list {*}[lrange $lines 0 1] "...<[expr {[llength $lines] -4}] lines undisplayed>..." {*}[lrange $lines end-1 end]] \n] diff --git a/src/vfs/_vfscommon/modules/punk/blockletter-0.1.0.tm b/src/vfs/_vfscommon/modules/punk/blockletter-0.1.0.tm new file mode 100644 index 00000000..244190fa --- /dev/null +++ b/src/vfs/_vfscommon/modules/punk/blockletter-0.1.0.tm @@ -0,0 +1,358 @@ +# -*- tcl -*- +# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'pmix make' or bin/punkmake to update from -buildversion.txt +# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.3.tm +# +# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. +# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# (C) 2024 +# +# @@ Meta Begin +# Application punk::blockletter 0.1.0 +# Meta platform tcl +# Meta license +# @@ Meta End + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin shellspy_module_punk::blockletter 0 0.1.0] +#[copyright "2024"] +#[titledesc {Module API}] [comment {-- Name section and table of contents description --}] +#[moddesc {-}] [comment {-- Description at end of page heading --}] +#[require punk::blockletter] +#[keywords module] +#[description] +#[para] - + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section Overview] +#[para] overview of punk::blockletter +#[subsection Concepts] +#[para] - + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +## Requirements +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by punk::blockletter +#[list_begin itemized] + +package require Tcl 8.6- +package require textblock +#*** !doctools +#[item] [package {Tcl 8.6}] +#[item] [package {textblock}] + +# #package require frobz +# #*** !doctools +# #[item] [package {frobz}] + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# oo::class namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#tcl::namespace::eval punk::blockletter::class { + #*** !doctools + #[subsection {Namespace punk::blockletter::class}] + #[para] class definitions + #if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} { + #*** !doctools + #[list_begin enumerated] + + # oo::class create interface_sample1 { + # #*** !doctools + # #[enum] CLASS [class interface_sample1] + # #[list_begin definitions] + + # method test {arg1} { + # #*** !doctools + # #[call class::interface_sample1 [method test] [arg arg1]] + # #[para] test method + # puts "test: $arg1" + # } + + # #*** !doctools + # #[list_end] [comment {-- end definitions interface_sample1}] + # } + + #*** !doctools + #[list_end] [comment {--- end class enumeration ---}] + #} +#} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# Base namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +tcl::namespace::eval punk::blockletter { + tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase + #variable xyz + + #*** !doctools + #[subsection {Namespace punk::blockletter}] + #[para] Core API functions for punk::blockletter + #[list_begin definitions] + + #A 3x4 block font + + variable default_frametype + set default_frametype {vl \u00a0 hl \u00a0 tlc \u00a0 trc \u00a0 blc \u00a0 brc \u00a0} + + # colours in order for T c l T k + set logo_letter_colours [list Web-red Web-green Web-royalblue Web-purple Web-orange] + set logo_letter_colours [list Red Green Blue Purple Yellow] + + + proc logo {args} { + variable logo_letter_colours + variable default_frametype + set argd [punk::args::get_dict [tstr -return string { + -frametype -default {${$default_frametype}} + -outlinecolour -default "web-white" + -backgroundcolour -default {} -help "e.g Web-white + This argument is the name as accepted by punk::ansi::a+" + *values -min 0 -max 0 + }] $args] + set f [dict get $argd opts -frametype] + set bd [dict get $argd opts -outlinecolour] + set bgansi [dict get $argd opts -backgroundcolour] ;#we use ta::detect to see if already ansi and apply as necessary + + #standard red green blue purple yellow + lassign $logo_letter_colours c_0 c_1 c_2 c_3 c_4 + + set tc [merge_left_block [T -bg $c_0 -border $bd -frametype $f] [c -bg $c_1 -border $bd -frametype $f]] + set tk [merge_left_block [T -bg $c_3 -border $bd -frametype $f] [k_short -bg $c_4 -border $bd -frametype $f]] + set logo [textblock::join_basic -- $tc [l -bg $c_2 -border $bd -frametype $f] [textblock::block 2 8 " "] $tk] + if {$bgansi ne ""} { + lassign [textblock::size_as_list $logo] lwidth lheight + set w [expr {$lwidth + 2}] + set h [expr {$lheight + 2}] + if {![punk::ansi::ta::detect $bgansi]} { + set bgansi [punk::ansi::a+ $bgansi] + } + set logobg $bgansi[textblock::block $w $h " "][punk::ansi::a] + set topmargin [string repeat " " $w] + set lmargin [textblock::block 1 [expr {$h + 1}] " "] + set logo [overtype::left -transparent " " $logobg [textblock::join_basic -- $lmargin $topmargin\n$logo]] + } + return $logo + } + + #for characters where it makes sense - offset left by 4 (1 'block' width) + proc merge_left {charleft textright} { + if {[string length $charleft] != 1} { + error "merge_left requires a single character as the charleft argument" + } + if {[textblock::height $charleft$textright] > 1} { + error "merge_left only operates on a plain char and a plain string with no newlines" + } + set rhs [textblock::join_basic -- [textblock::block 8 8 " "] [text $textright]] + #important to explicitly use -transparent " " (ordinary space) rather than -transparent 1 (any space?) + #This is because our frames have NBSP as filler to be non-transparent + return [overtype::left -transparent " " -overflow 1 [text $charleft] $rhs] + } + proc merge_left_block {blockleft blockright} { + set rhs [textblock::join_basic -- [textblock::block 8 8 " "] $blockright] + return [overtype::left -transparent " " -overflow 1 $blockleft $rhs] + } + + proc T {args} { + set args [dict remove $args -width -height] + append out [lib::hbar {*}$args]\n + append out [textblock::join -- " " [lib::vbar {*}$args] " "] + } + proc c {args} { + set args [dict remove $args -width -height] + append out [textblock::block 12 2 " "]\n + append out [lib::hbar {*}$args]\n + append out [textblock::join -- [lib::block {*}$args] " "]\n + append out [lib::hbar {*}$args] + } + proc l {args} { + set args [dict remove $args -width -height] + append out [lib::vbar {*}[dict merge {-height 8} $args]] + } + + #full height lower k + proc k {args} { + set args [dict remove $args -width -height] + set left [lib::vbar {*}[dict merge {-height 8} $args]] + set centre [textblock::block 4 4 " "]\n + append centre [lib::block {*}$args]\n + append centre [textblock::block 4 2 " "] + set right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args]\n + append right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args] + append out [textblock::join_basic -- $left $centre $right] + } + proc k_short {args} { + set args [dict remove $args -width -height] + append left [textblock::block 4 2 " "]\n + append left [lib::vbar {*}[dict merge {-height 6} $args]] + append centre [textblock::block 4 4 " "]\n + append centre [lib::block {*}$args]\n + append centre [textblock::block 4 2 " "] + append right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args]\n + append right [textblock::block 4 2 " "]\n + append right [lib::block {*}$args] + append out [textblock::join_basic -- $left $centre $right] + } + + proc text {args} { + variable default_frametype + set argd [punk::args::get_dict [tstr -return string { + -bgcolour -default "Web-red" + -bordercolour -default "web-white" + -frametype -default {${$default_frametype}} + *values -min 1 -max 1 + str -help "Text to convert to blockletters + Requires terminal font to support relevant block characters" + " + }] $args] + set opts [dict get $argd opts] + set str [dict get $argd values str] + set str [string map {\r\n \n} $str] + set outblocks [list] + set literals [list \n] + foreach char [split $str ""] { + if {$char in $literals} { + lappend outblocks $char + continue + } + if {$char in [list \t \r]} { + lappend outblocks [textblock::block 1 8 $char] + continue + } + if {[info commands ::punk::blockletter::$char] ne ""} { + lappend outblocks [::punk::blockletter::$char {*}$opts] + } else { + lappend outblocks [textblock::block 12 8 $char] + } + } + return [textblock::join_basic -- {*}$outblocks] + } + + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::blockletter ---}] +} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# Secondary API namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +tcl::namespace::eval punk::blockletter::lib { + + tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase + tcl::namespace::path [tcl::namespace::parent] + #*** !doctools + #[subsection {Namespace punk::blockletter::lib}] + #[para] Secondary functions that are part of the API + #[list_begin definitions] + + #proc utility1 {p1 args} { + # #*** !doctools + # #[call lib::[fun utility1] [arg p1] [opt {?option value...?}]] + # #[para]Description of utility1 + # return 1 + #} + + proc block {args} { + upvar ::punk::blockletter::default_frametype ft + set argd [punk::args::get_dict [tstr -return string { + -height -default 2 + -width -default 4 + -frametype -default {${$ft}} + -bgcolour -default "Web-red" + -bordercolour -default "web-white" + *values -min 0 -max 0 + }] $args] + set bg [dict get $argd opts -bgcolour] + set bd [dict get $argd opts -bordercolour] + set h [dict get $argd opts -height] + set w [dict get $argd opts -width] + set f [dict get $argd opts -frametype] + + #a frame will usually be filled with empty spaces if content not specified + #fill the frame with a non-space so we can do transparent overtypes using ordinary space as the transparency character + set w_in [expr {$w -2}] + set h_in [expr {$h -2}] + if {$w_in > 0 && $h_in > 0} { + set inner [textblock::block $w_in $h_in \u00a0] ;#NBSP + textblock::frame -type $f -height $h -width $w -ansiborder [a+ $bd $bg] -ansibase [a+ $bg] $inner + } else { + #important to use no content arg - as empty string has 'height' of 1 in the textblock context (min height of any string is 1 row in the console) + textblock::frame -type $f -height $h -width $w -ansiborder [a+ $bd $bg] -ansibase [a+ $bg] + } + + } + proc hbar {args} { + upvar ::punk::blockletter::default_frametype ft + set defaults [dict create\ + -height 2\ + -width 12\ + -frametype $ft\ + ] + set opts [dict merge $defaults $args] + block {*}$opts + } + proc vbar {args} { + upvar ::punk::blockletter::default_frametype ft + #default height a multiple of default hbar/block height + set defaults [dict create\ + -height 6\ + -width 4\ + -frametype $ft\ + ] + set opts [dict merge $defaults $args] + [namespace current]::block {*}$opts + } + + #*** !doctools + #[list_end] [comment {--- end definitions namespace punk::blockletter::lib ---}] +} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[section Internal] +#tcl::namespace::eval punk::blockletter::system { + #*** !doctools + #[subsection {Namespace punk::blockletter::system}] + #[para] Internal functions that are not part of the API + + + +#} +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +## Ready +package provide punk::blockletter [tcl::namespace::eval punk::blockletter { + variable pkg punk::blockletter + variable version + set version 0.1.0 +}] +return + +#*** !doctools +#[manpage_end] + diff --git a/src/vfs/_vfscommon/modules/punk/console-0.1.1.tm b/src/vfs/_vfscommon/modules/punk/console-0.1.1.tm index 99c99939..4dd7bd66 100644 --- a/src/vfs/_vfscommon/modules/punk/console-0.1.1.tm +++ b/src/vfs/_vfscommon/modules/punk/console-0.1.1.tm @@ -1021,8 +1021,8 @@ namespace eval punk::console { #It's known this isn't always the case - but things like textutil::untabify2 take only a single value #on some systems test_char_width is a similar speed to get_tabstop_apparent_width - but on some test_char_width is much slower #we will use test_char_width as a fallback - proc get_tabstop_apparent_width {} { - set tslist [get_tabstops] + proc get_tabstop_apparent_width {{inoutchannels {stdin stdout}}} { + set tslist [get_tabstops $inoutchannels] if {![llength $tslist]} { #either terminal failed to report - or none set. set testw [test_char_width \t] @@ -1075,23 +1075,37 @@ namespace eval punk::console { return [split [get_cursor_pos $inoutchannels] ";"] } - #todo - determine cursor on/off state before the call to restore properly. May only be possible + #todo - determine cursor on/off state before the call to restore properly. proc get_size {{inoutchannels {stdin stdout}}} { lassign $inoutchannels in out #we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810 #chan eof is faster whether chan exists or not than - if {[catch {chan eof $in} is_eof]} { - error "punk::console::get_size input channel $in seems to be closed ([info level 1])" + if {[catch {chan eof $out} is_eof]} { + error "punk::console::get_size output channel $out seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on input channel $in ([info level 1])" + error "punk::console::get_size eof on output channel $out ([info level 1])" } } - if {[catch {chan eof $out} is_eof]} { - error "punk::console::get_size output channel $out seems to be closed ([info level 1])" + #we don't need to care about the input channel if chan configure on the output can give us the info. + #short circuit ansi cursor movement method if chan configure supports the -winsize value + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + #this mechanism is much faster than ansi cursor movements + #REVIEW check if any x-platform anomalies with this method? + #can -winsize key exist but contain erroneous info? We will check that we get 2 ints at least + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + #continue on to ansi mechanism if we didn't get 2 ints + } + + if {[catch {chan eof $in} is_eof]} { + error "punk::console::get_size input channel $in seems to be closed ([info level 1])" } else { if {$is_eof} { - error "punk::console::get_size eof on output channel $out ([info level 1])" + error "punk::console::get_size eof on input channel $in ([info level 1])" } } @@ -1114,18 +1128,28 @@ namespace eval punk::console { } } - #faster - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore - proc get_size_cursorrestore {} { + #faster than get_size when it is using ansi mechanism - but uses cursor_save - which we may want to avoid if calling during another operation which uses cursor save/restore + proc get_size_cursorrestore {{inoutchannels {stdin stdout}}} { + lassign $inoutchannels in out + #we use the same shortcircuit mechanism as get_size to avoid ansi at all if the output channel will give us the info directly + set outconf [chan configure $out] + if {[dict exists $outconf -winsize]} { + lassign [dict get $outconf -winsize] cols lines + if {[string is integer -strict $cols] && [string is integer -strict $lines]} { + return [list columns $cols rows $lines] + } + } + if {[catch { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. - puts -nonewline [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] - lassign [get_cursor_pos_list] lines cols - puts -nonewline [punk::ansi::cursor_restore][punk::console::cursor_on];flush stdout + puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] + lassign [get_cursor_pos_list $inoutchannels] lines cols + puts -nonewline $out [punk::ansi::cursor_restore][punk::console::cursor_on];flush $out set result [list columns $cols rows $lines] } errM]} { - puts -nonewline [punk::ansi::cursor_restore_dec] - puts -nonewline [punk::ansi::cursor_on] + puts -nonewline $out [punk::ansi::cursor_restore_dec] + puts -nonewline $out [punk::ansi::cursor_on] error "$errM" } else { return $result @@ -1175,7 +1199,7 @@ namespace eval punk::console { } if {!$emit} { - puts -nonewline stdout \033\[2K\033\[1G ;#2K erase line 1G cursor at col1 + puts -nonewline stdout \033\[2K\033\[1G ;#2K erase line, 1G cursor at col1 } set response "" if {[catch { @@ -1405,12 +1429,12 @@ namespace eval punk::console { proc cursor_save {} { #*** !doctools #[call [fun cursor_save]] - puts -nonewline \x1b\[s + puts -nonewline stdout \x1b\[s } proc cursor_restore {} { #*** !doctools #[call [fun cursor_restore]] - puts -nonewline \x1b\[u + puts -nonewline stdout \x1b\[u } #DEC equivalents of cursor_save/cursor_restore - perhaps more widely supported? proc cursor_save_dec {} { diff --git a/src/vfs/_vfscommon/modules/punk/experiment-0.1.0.tm b/src/vfs/_vfscommon/modules/punk/experiment-0.1.0.tm index 89939ade..9d9861f2 100644 --- a/src/vfs/_vfscommon/modules/punk/experiment-0.1.0.tm +++ b/src/vfs/_vfscommon/modules/punk/experiment-0.1.0.tm @@ -474,12 +474,12 @@ namespace eval punk::experiment { proc render1 {} { variable b1 variable b2 - overtype::renderspace -overflow 1 -startcolumn 7 $b1 $b2 + overtype::renderspace -expand_right 1 -startcolumn 7 $b1 $b2 } proc render2 {} { variable b1 variable b3 - overtype::renderspace -overflow 1 -transparent @ $b1 $b3 + overtype::renderspace -expand_right 1 -transparent @ $b1 $b3 } oo::class create c1 { diff --git a/src/vfs/_vfscommon/modules/punk/mix/commandset/project-0.1.0.tm b/src/vfs/_vfscommon/modules/punk/mix/commandset/project-0.1.0.tm index 15281625..9afc685c 100644 --- a/src/vfs/_vfscommon/modules/punk/mix/commandset/project-0.1.0.tm +++ b/src/vfs/_vfscommon/modules/punk/mix/commandset/project-0.1.0.tm @@ -919,10 +919,18 @@ namespace eval punk::mix::commandset::project { if {[llength $col_states]} { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes s $col_states { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode] [overtype::left $col6 $s]" \n } } else { foreach row $col_rowids wd $workdirs db $col_fnames dup $col_dupids pname $col_pnames pcode $col_pcodes { + if {![file exists $wd]} { + set row [punk::ansi::a+ strike red]$row[a] + set wd [punk::ansi::a+ red]$wd[a] + } append msg "[overtype::right $col0 $row] [overtype::left $col1 $wd] [overtype::left $col2 $db] [overtype::right $col3 $dup] [overtype::left $col4 $pname] [overtype::left $col5 $pcode]" \n } } diff --git a/src/vfs/_vfscommon/modules/punk/repl-0.1.tm b/src/vfs/_vfscommon/modules/punk/repl-0.1.tm index 0d3f6115..864c4030 100644 --- a/src/vfs/_vfscommon/modules/punk/repl-0.1.tm +++ b/src/vfs/_vfscommon/modules/punk/repl-0.1.tm @@ -431,7 +431,7 @@ proc repl::post_operations {} { uplevel #0 {eval $::repl::running_script} } #todo - tidyup so repl could be restarted - set repl::post_operations_done 0 + set ::repl::post_operations_done 0 } @@ -860,7 +860,7 @@ namespace eval punk::repl::class { set o_cursor_col $line_nextchar_col } - set mergedinfo [overtype::renderline -info 1 -overflow 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $new0] + set mergedinfo [overtype::renderline -info 1 -expand_right 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $new0] set result [dict get $mergedinfo result] set o_insert_mode [dict get $mergedinfo insert_mode] @@ -934,13 +934,13 @@ namespace eval punk::repl::class { break } } - #puts stderr "overtype::renderline -info 1 -overflow 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $activeline '$p'" + #puts stderr "overtype::renderline -info 1 -expand_right 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $activeline '$p'" set underlay $activeline set line_nextchar_col [expr {[punk::char::string_width $underlay] + 1}] if {$o_cursor_col > $line_nextchar_col} { set o_cursor_col $line_nextchar_col } - set mergedinfo [overtype::renderline -info 1 -overflow 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $p] + set mergedinfo [overtype::renderline -info 1 -expand_right 1 -insert_mode $o_insert_mode -cursor_column $o_cursor_col -cursor_row $o_cursor_row $underlay $p] set debug "add_chunk$i" append debug \n $mergedinfo append debug \n "input:[ansistring VIEW -lf 1 -vt 1 $p]" @@ -1120,7 +1120,7 @@ namespace eval punk::repl::class { } else { set charhighlight [punk::ansi::a+ reverse]$char_at_cursor[a] } - set cursorline [overtype::renderline -transparent 1 -insert_mode 0 -overflow 0 $cursorline $prefix$charhighlight$suffix] + set cursorline [overtype::renderline -transparent 1 -insert_mode 0 -expand_right 0 $cursorline $prefix$charhighlight$suffix] lset lines $o_cursor_row-1 $cursorline } @@ -1921,7 +1921,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config if {[info complete $commandstr] && [string index $commandstr end] ne "\\"} { - #set commandstr [overtype::renderline -overflow 1 "" $commandstr] + #set commandstr [overtype::renderline -expand_right 1 "" $commandstr] set ::repl::output_stdout "" diff --git a/src/vfs/_vfscommon/modules/punk/repo-0.1.1.tm b/src/vfs/_vfscommon/modules/punk/repo-0.1.1.tm index ee2384b4..2cb5fd1d 100644 --- a/src/vfs/_vfscommon/modules/punk/repo-0.1.1.tm +++ b/src/vfs/_vfscommon/modules/punk/repo-0.1.1.tm @@ -134,13 +134,30 @@ namespace eval punk::repo { } interp alias "" fossil "" punk::repo::fossil_proxy + # --- + # Calling auto_execok on an external tool can be too slow to do during package load (e.g could be 150ms) + #safe interps can't call auto_execok #At least let them load the package even though much of it may be unusable depending on the safe configuration - catch { - if {[auto_execok fossil] ne ""} { - interp alias "" FOSSIL "" {*}[auto_execok fossil] - } + #catch { + # if {[auto_execok fossil] ne ""} { + # interp alias "" FOSSIL "" {*}[auto_execok fossil] + # } + #} + # --- + # ---------- + # + + #uppercase FOSSIL to bypass fossil as alias to fossil_proxy + proc establish_FOSSIL {args} { + if {![info exists ::auto_execs(FOSSIL)]} { + set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp + } + interp alias "" FOSSIL "" ;#delete establishment alias + FOSSIL {*}$args } + interp alias "" FOSSIL "" punk::repo::establish_FOSSIL + # ---------- proc askuser {question} { if {![catch {package require punk::lib}]} { @@ -370,7 +387,16 @@ namespace eval punk::repo { } if {$repodir eq ""} { - error "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "workingdir_state error: No repository found at or above path '$abspath'" + puts stderr "args: $args" + dict set resultdict revision {} + dict set resultdict revision_iso8601 {} + dict set resultdict paths {} + dict set resultdict ahead "" + dict set resultdict behind "" + dict set resultdict error {reason "no_repo_found"} + dict set resultdict repotype none + return $resultdict } set subpath [punk::path::relative $repodir $abspath] if {$subpath eq "."} { @@ -644,6 +670,16 @@ namespace eval punk::repo { set path_count_fields [list unchanged changed new missing extra] set state_fields [list ahead behind repodir subpath repotype revision revision_iso8601] set dresult [dict create] + if {[dict exists $repostate error]} { + foreach f $state_fields { + dict set dresult $f "" + } + foreach f $path_count_fields { + dict set dresult $f "" + } + #todo? + return $dresult + } foreach f $state_fields { dict set dresult $f [dict get $repostate $f] } diff --git a/src/vfs/_vfscommon/modules/test/tomlish-1.1.1.tm b/src/vfs/_vfscommon/modules/test/tomlish-1.1.1.tm index e5909c53..885c56a1 100644 Binary files a/src/vfs/_vfscommon/modules/test/tomlish-1.1.1.tm and b/src/vfs/_vfscommon/modules/test/tomlish-1.1.1.tm differ diff --git a/src/vfs/_vfscommon/modules/textblock-0.1.1.tm b/src/vfs/_vfscommon/modules/textblock-0.1.1.tm index 9695822b..88fdc3fd 100644 --- a/src/vfs/_vfscommon/modules/textblock-0.1.1.tm +++ b/src/vfs/_vfscommon/modules/textblock-0.1.1.tm @@ -60,6 +60,8 @@ package require punk::ansi package require punk::lib catch {package require patternpunk} package require overtype + +#safebase interps as at 2024-08 can't access deeper paths - even though they are below the supposed safe list. package require term::ansi::code::macros ;#required for frame if old ansi g0 used - review - make package optional? package require textutil @@ -1931,13 +1933,6 @@ tcl::namespace::eval textblock { set hval $ansibase_header$header ;#no reset set rowh [my header_height $hrow] - #set h_lines [lrepeat $rowh $hcell_line_blank] - #set hcell_blank [join $h_lines \n] - #set hval_lines [split $hval \n] - #set hval_lines [lrange $hval_lines 0 $rowh-1] - #set hval_block [join $hval_lines \n] - #set headercell [overtype::left -experimental test_mode $ansibase_header$hcell_blank$RST $hval_block] - if {$hrow == 0} { set hlims $header_boxlimits_toprow set rowpos "top" @@ -2144,7 +2139,7 @@ tcl::namespace::eval textblock { #puts $hblock #puts "==>hval:'$hval'[a]" #puts "==>hval:'[ansistring VIEW $hval]'" - #set spanned_frame [overtype::renderspace -experimental test_mode -transparent 1 $spanned_frame $hblock] + #set spanned_frame [overtype::renderspace -transparent 1 $spanned_frame $hblock] #spanned values default left - todo make configurable @@ -3502,11 +3497,11 @@ tcl::namespace::eval textblock { set height [textblock::height $table] ;#only need to get height once at start } else { set nextcol [textblock::join -- [textblock::block $padwidth $height $TSUB] $nextcol] - set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent $TSUB $table[unset table] $nextcol] + set table [overtype::renderspace -expand_right 1 -transparent $TSUB $table[unset table] $nextcol] #JMN #set nextcol [textblock::join -- [textblock::block $padwidth $height "\uFFFF"] $nextcol] - #set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol] + #set table [overtype::renderspace -expand_right 1 -transparent \uFFFF $table $nextcol] } incr padwidth $bodywidth incr colposn @@ -3607,14 +3602,7 @@ tcl::namespace::eval textblock { set table $nextcol set height [textblock::height $table] ;#only need to get height once at start } else { - set table [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -overflow 1 -experimental test_mode -transparent $TSUB $table $nextcol] - - #set nextcol [textblock::join -- [textblock::block $padwidth $height $TSUB] $nextcol] - #set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent $TSUB $table[unset table] $nextcol] - #JMN - - #set nextcol [textblock::join -- [textblock::block $padwidth $height "\uFFFF"] $nextcol] - #set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol] + set table [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -expand_right 1 -transparent $TSUB $table $nextcol] } incr padwidth $bodywidth incr colposn @@ -3724,7 +3712,7 @@ tcl::namespace::eval textblock { lappend body_blocks $nextcol_body } else { if {$headerheight > 0} { - set header_build [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -overflow 1 -experimental test_mode -transparent $TSUB $header_build[unset header_build] $nextcol_header[unset nextcol_header]] + set header_build [overtype::renderspace -startcolumn [expr {$padwidth + 1}] -expand_right 1 -transparent $TSUB $header_build[unset header_build] $nextcol_header[unset nextcol_header]] } lappend body_blocks $nextcol_body #set body_build [textblock::join -- $body_build[unset body_build] $nextcol_body] @@ -4057,7 +4045,7 @@ tcl::namespace::eval textblock { if append is chosen the new values will always start at the first column" -columns -default "" -type integer -help "Number of table columns Will default to 2 if not using an existing -table object" - *values + *values -min 0 -max 1 datalist -default {} -help "flat list of table cell values which will be wrapped based on -columns value" }] $args] set opts [dict get $argd opts] @@ -4408,6 +4396,14 @@ tcl::namespace::eval textblock { return [tcl::dict::create width $width height $height] ;#maintain order in 'image processing' standard width then height - caller may use lassign [tcl::dict::values [blocksize ]] width height } + proc size_as_opts {textblock} { + set sz [size $textblock] + return [dict create -width [dict get $sz width] -height [dict get $sz height]] + } + proc size_as_list {textblock} { + set sz [size $textblock] + return [list [dict get $sz width] [dict get $sz height]] + } #must be able to handle block as string with or without newlines #if no newlines - attempt to treat as a list #must handle whitespace-only string,list elements, and/or lines. @@ -5132,6 +5128,7 @@ tcl::namespace::eval textblock { [punk::lib::list_as_lines -- [lrepeat 8 " | "]] } proc table {args} { + #todo - use punk::args upvar ::textblock::class::opts_table_defaults toptdefaults set defaults [tcl::dict::create\ -rows [list]\ @@ -5183,7 +5180,7 @@ tcl::namespace::eval textblock { } variable frametypes - set frametypes [list light heavy arc double block block1 block2 ascii altg] + set frametypes [list light heavy arc double block block1 block2 block2hack ascii altg] #class::table needs to be able to determine valid frametypes proc frametypes {} { variable frametypes @@ -5192,7 +5189,7 @@ tcl::namespace::eval textblock { proc frametype {f} { #set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] switch -- $f { - light - heavy - arc - double - block - block1 - block2 - ascii - altg { + light - heavy - arc - double - block - block1 - block2 - block2hack - ascii - altg { return [tcl::dict::create category predefined type $f] } default { @@ -5213,7 +5210,7 @@ tcl::namespace::eval textblock { set is_custom_dict_ok 0 } if {!$is_custom_dict_ok} { - error "frame option -type must be one of known types: $textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" + error "frame option -type must be one of known types: $::textblock::frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" } set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] set custom_frame [tcl::dict::merge $default_custom $f] @@ -6323,9 +6320,12 @@ tcl::namespace::eval textblock { set vlr \u2595 ;# right one eighth block set vll \u258f ;# left one eighth block + #some terminals (on windows as at 2024) miscount width of these single-width blocks internally + #resulting in extra spacing that is sometimes well removed from the character itself (e.g at next ansi reset) + #This was fixed in windows-terminal based systems (2021) but persists in others. + #https://github.com/microsoft/terminal/issues/11694 set tlc \U1fb7d ;#legacy block set trc \U1fb7e ;#legacy block - set blc \U1fb7c ;#legacy block set brc \U1fb7f ;#legacy block @@ -6336,6 +6336,42 @@ tcl::namespace::eval textblock { set vlrj $vlr } + block2hack { + #the resultant table will have text appear towards top of each box + #with 'legacy' computing unicode block - hopefully these become more widely supported - as they are useful and fill in some gaps + set hlt \u2594 ;# upper one eighth block + set hlb \u2581 ;# lower one eighth block + set vlr \u2595 ;# right one eighth block + set vll \u258f ;# left one eighth block + + #see comments in block2 regarding the problems in some terminals that this *may* hack around to some extent. + #the caller probably only needs block2hack if block2 doesn't work + + #1) + #review - this hack looks sort of promising - but overtype::renderline needs fixing ? + #set tlc \U1fb7d\b ;#legacy block + #set trc \U1fb7e\b ;#legacy block + #set blc \U1fb7c\b ;#legacy block + #set brc \U1fb7f\b ;#legacy block + + #2) - works on cmd.exe and some others + # a 'privacy message' is 'probably' also not supported on the old terminal but is on newer ones + #known exception - conemu on windows - displays junk for various ansi codes - (and slow terminal anyway) + #this hack has a reasonable chance of working + #except that the punk overtype library does recognise PMs + #A single backspace however is an unlikely and generally unuseful PM - so there is a corresponding hack in the renderline system to pass this PM through! + #ugly - in that we don't know the application specifics of what the PM data contains and where it's going. + set tlc \U1fb7d\x1b^\b\x1b\\ ;#legacy block + set trc \U1fb7e\x1b^\b\x1b\\ ;#legacy block + set blc \U1fb7c\x1b^\b\x1b\\ ;#legacy block + set brc \U1fb7f\x1b^\b\x1b\\ ;#legacy block + + #horizontal and vertical bar joins + set hltj $hlt + set hlbj $hlb + set vllj $vll + set vlrj $vlr + } block { set hlt \u2580 ;#upper half set hlb \u2584 ;#lower half @@ -6357,7 +6393,7 @@ tcl::namespace::eval textblock { set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] ;#only default the general types - these form defaults for more specific types if they're missing if {[llength $f] % 2 != 0} { #todo - retrieve usage from punk::args - error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $textblock::frametypes and does not appear to be a dictionary for a custom frametype" + error "textblock::frametype frametype '$f' is not one of the predefined frametypes: $::textblock::frametypes and does not appear to be a dictionary for a custom frametype" } #unknown order of keys specified by user - validate before creating vars as we need more general elements to be available as defaults dict for {k v} $f { @@ -6488,7 +6524,11 @@ tcl::namespace::eval textblock { -ellipsis 1\ -usecache 1\ -buildcache 1\ + -pad 1\ + -crm_mode 0\ ] + #-pad 1 is default so that simple 'textblock::frame "[a+ Red]a \nbbb[a]" extends the bg colour on the short ragged lines (and empty lines) + # for ansi art - -pad 0 is likely to be preferable set expect_optval 0 set argposn 0 @@ -6527,7 +6567,12 @@ tcl::namespace::eval textblock { #use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache foreach {k v} $arglist { switch -- $k { - -etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache { + -etabs - -type - -boxlimits - -boxmap - -joins + - -title - -subtitle - -width - -height + - -ansiborder - -ansibase + - -blockalign - -textalign - -ellipsis + - -crm_mode + - -usecache - -buildcache - -pad { tcl::dict::set opts $k $v } default { @@ -6543,11 +6588,13 @@ tcl::namespace::eval textblock { set opt_boxmap [tcl::dict::get $opts -boxmap] set opt_usecache [tcl::dict::get $opts -usecache] set opt_buildcache [tcl::dict::get $opts -buildcache] + set opt_pad [tcl::dict::get $opts -pad] + set opt_crm_mode [tcl::dict::get $opts -crm_mode] set usecache $opt_usecache ;#may need to override set buildcache $opt_buildcache set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] - set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable + set known_frametypes $frametypes ;# light, heavey etc as defined in the ::textblock::frametypes variable set default_custom [tcl::dict::create hl " " vl " " tlc " " trc " " blc " " brc " "] lassign [textblock::frametype $opt_type] _cat category _type ftype @@ -6686,6 +6733,19 @@ tcl::namespace::eval textblock { } } set contents [tcl::string::map [list \r\n \n] $contents] + if {$opt_crm_mode} { + if {$opt_height eq ""} { + set h [textblock::height $contents] + } else { + set h [expr {$opt_height -2}] + } + if {$opt_width eq ""} { + set w [textblock::width $contents] + } else { + set w [expr {$opt_width -2}] + } + set contents [overtype::renderspace -crm_mode 1 -wrap 1 -width $w -height $h "" $contents] + } set actual_contentwidth [textblock::width $contents] ;#length of longest line in contents (contents can be ragged) set actual_contentheight [textblock::height $contents] } else { @@ -7134,15 +7194,22 @@ tcl::namespace::eval textblock { append contents [::join [lrepeat $diff \n] ""] } - set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) - set paddedwidth [textblock::widthtopline $paddedcontents] - - #review - horizontal truncation - if {$paddedwidth > $cache_patternwidth} { - set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + if {$opt_pad} { + set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth) + set paddedwidth [textblock::widthtopline $paddedcontents] + #review - horizontal truncation + if {$paddedwidth > $cache_patternwidth} { + set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents] + } + #important to supply end of opts -- to textblock::join - particularly here with arbitrary data + set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays + } else { + set cwidth [textblock::width $contents] + if {$cwidth > $cache_patternwidth} { + set contents [overtype::renderspace -width $cache_patternwidth "" $contents] + } + set contentblock [textblock::join -- $contents] } - #important to supply end of opts -- to textblock::join - particularly here with arbitrary data - set contentblock [textblock::join -- $paddedcontents] ;#make sure each line has ansi replays set tlines [split $template \n] diff --git a/src/vfs/critcl.vfs/README.md b/src/vfs/critcl.vfs/README.md new file mode 100644 index 00000000..3d8ecd79 --- /dev/null +++ b/src/vfs/critcl.vfs/README.md @@ -0,0 +1,111 @@ +# Compiled Runtime In Tcl + + * Welcome to the C Runtime In Tcl, CriTcl for short, a system to + build C extension packages for Tcl on the fly, from C code + embedded within Tcl scripts, for all who wish to make their code + go faster. + +# Website + + * The main website of this project is http://andreas-kupries.github.io/critcl + + It provides access to pre-made binaries and archives for various + platforms, and the full documentation, especially the guides to + building and using Critcl. + + Because of the latter this document contains only the most basic + instructions on getting, building, and using Critcl. + +# Versions + + * Version 3 is the actively developed version of Critcl, with several + new features, listed in section **New Features**, below. This version + has changes to the public API which make it incompatible with packages + using Critcl version 2.x, or earlier. + + * The last of version 2 is 2.1, available at the same-named tag in the + repository. This version is not developed anymore. + +# Getting, Building, and Using Critcl + + * Retrieve the sources: + + ```% git clone http://github.com/andreas-kupries/critcl``` + + Your working directory now contains a directory ```critcl```. + + * Build and install it: + + Install requisites: cmdline, md5; possibly one of tcllibc, Trf, md5c to accelerate md5. + + ```% cd critcl``` + + ```% tclsh ./build.tcl install``` + + The generated packages are placed into the **[info library]** directory + of the **tclsh** used to run build.tcl. The **critcl** application script + is put into the directory of the **tclsh** itself (and modified to + use this executable). This may require administrative (root) permissions, + depending on the system setup. + + * It is expected that a working C compiler is available. Installation and + setup of such a compiler is platform and vendor specific, and instructions + for doing so are very much outside of scope for this document. Please find + and read the documentation, how-tos, etc. for your platform or vendor. + + * With critcl installed try out one of the examples: + + ```% cd examples/stack``` + + ```% critcl -keep -cache B -pkg cstack.tcl``` + + ```% critcl -keep -cache B -pkg stackc.tcl``` + + ```% tclsh``` + + ```> lappend auto_path [pwd]/lib``` + + ```> package require stackc``` + + ```> stackc create S``` + + ```> S push FOO``` + + ```> S size``` + + ```> S destroy``` + + ```> exit``` + + ```%``` + +# New Features + + * Declaration, export and import of C-APIs through stubs tables. + + * Generation of source packages from critcl-based code containing a + TEA-based buildsystem wrapped around the raw critcl. + + * Declaration, initializaton and use of user-specified configuration + options. An important use is the declaration and use of custom + build configurations, like 'link a 3rd party library dynamically, + statically, build it from copy of its sources, etc.', etc. + + * This is of course not everything. For the details please read the + Changes sections of the documentation. + +# Documentation + + * Too much to cover here. Please go to http://andreas-kupries.github.io/critcl + for online reading, or the directories **embedded/www** and + **embedded/man** for local copies of the documentation in HTML + and nroff formats, respectively. + +# History + + * **2013-01-21** : Move code to from jcw to andreas-kupries. + + * **2011-08-18** : Move code to public repository on GitHub + + The Subversion repository at *svn://svn.equi4.com/critcl* is now obsolete. + GitHub has the new official repository for Critcl. diff --git a/src/vfs/critcl.vfs/doc/checklist.txt b/src/vfs/critcl.vfs/doc/checklist.txt new file mode 100644 index 00000000..9bb46bb4 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/checklist.txt @@ -0,0 +1,20 @@ +When releasing: + + - Run the test suite. + + - Run the examples. + + - Bump version in `doc/version.inc`. + + - If necessary, further bump: + - The versions of `package provide/ifneeded` in files: + - `lib/critcl-app/pkgindex.tcl` + - `lib/critcl/pkgindex.tcl` + - `lib/critcl/critcl.tcl` + - The version in `doc/pkg_version.inc`. + + - Regenerate the embedded documentation. + + - Commit + + - Push diff --git a/src/vfs/critcl.vfs/doc/critcl.man b/src/vfs/critcl.vfs/doc/critcl.man new file mode 100644 index 00000000..ead3b25e --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl.man @@ -0,0 +1,73 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[include version.inc] +[manpage_begin critcl n [vset VERSION]] +[include include/module.inc] +[titledesc {Introduction To CriTcl}] +[description] +[para] +[include include/welcome.inc] +[include include/advert.inc] +[para] + +[comment {= = == === ===== ======== ============= =====================}] +[section {History & Motivation}] + +[para] [vset critcl] started life as an experiment by [vset jcw] and was a self-contained +Tcl package to build C code into a Tcl/Tk extension on the fly. It was somewhat inspired +by Brian Ingerson's [term Inline] for [term Perl], but is considerably more lightweight. + +[para] It is for the last 5% to 10% when pure Tcl, which does go a long way, is not +sufficient anymore. I.e. for + +[list_begin enumerated] +[enum] when the last bits of performance are needed, +[enum] access to 3rd party libraries, +[enum] hiding critical pieces of your library or application, and +[enum] simply needing features provided only by C. +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Overview] + +To make the reader's topics of interest easy to find this documentation is roughly +organized by [vset quad], i.e. [include include/quad.inc] + +[strong Note]: At this point in time the documentation consists mainly of references, and +a few how-to guides. Tutorials and Explanations are in need of expansion, this is planned. + +[comment {= = == === ===== ======== ============= =====================}] +[section {Known Users}] +[include include/pkg_users.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[section {Tutorials - Practical Study - To Learn}] + +This section is currently empty. + +[comment {= = == === ===== ======== ============= =====================}] +[section {Explanations - Theoretical Knowledge - To Understand}] + +This section is currently empty. + +[comment {= = == === ===== ======== ============= =====================}] +[section {How-To Guides - Practical Work - To Solve Problems}] + +[list_begin enumerated] +[enum] [term {How To Get The CriTcl Sources}]. +[enum] [term {How To Install CriTcl}]. +[enum] [term {How To Use CriTcl}] - A light introduction through examples. +[enum] [strong NEW]: [term {How To Adapt Critcl Packages for Tcl 9}]. +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section {References - Theoretical Work - To Gain Knowlegde}] + +[list_begin enumerated] +[enum] [term {The CriTcl License}] +[enum] [term {CriTcl Releases & Changes}] +[include include/reference_docs.inc] +[enum] [term {Guide To The CriTcl Internals}] +[list_end] + +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_application.man b/src/vfs/critcl.vfs/doc/critcl_application.man new file mode 100644 index 00000000..72e6f7a3 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_application.man @@ -0,0 +1,45 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include pkg_version.inc] +[manpage_begin critcl_application n [vset VERSION]] +[include include/module.inc] +[titledesc {CriTcl Application Reference}] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the [cmd critcl] command. +Its intended audience are people having to build packages using +[package critcl] for deployment. Writers of packages with embedded C +code can ignore this document. + +[vset see_overview] + +[para] + +This application resides in the Application Layer of CriTcl. +[para][image arch_application][para]. + +[comment {= = == === ===== ======== ============= =====================}] + +The application supports the following general command line: + +[list_begin definitions] +[call [cmd critcl] [opt [arg option]...] [opt [arg file]...]] + +The exact set of options supported, their meaning, and interaction is +detailed in section [sectref {Application Options}] below. + +For a larger set of examples please see section "Building CriTcl Packages" +in the document about [manpage {Using CriTcl}]. + +[list_end] + + +[section {Application Options}] [include include/aoptions.inc] +[section {Package Structure}] [include include/pstructure.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_application_package.man b/src/vfs/critcl.vfs/doc/critcl_application_package.man new file mode 100644 index 00000000..00603c9c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_application_package.man @@ -0,0 +1,62 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include pkg_version.inc] +[manpage_begin critcl_application_package n [vset VERSION]] +[include include/module.inc] +[titledesc {CriTcl Application Package Reference}] +[require Tcl 8.6] +[require critcl::app [opt [vset VERSION]]] +[require critcl [opt [vset VERSION]]] +[require platform [opt 1.0.2]] +[require cmdline] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the [package critcl::app] +package. Its intended audience are developers working on critcl's +internals. [vset not_needed_for_critcl_script] + +[vset see_overview] + +[para] + +This package resides in the Application Layer of CriTcl. +[para][image arch_application][para], + +implementing the functionality of the [manpage {CriTcl Application}], +and through this, the mode [sectref {Modes Of Operation/Use} {generate package}]. + +The actual application is (only) a shim wrapping around this +package. It itself is build on top of the core package +[package critcl]. + +[comment {= = == === ===== ======== ============= =====================}] +[section API] + +The package exports a single command + +[list_begin definitions] +[call [cmd ::critcl::app::main] [arg commandline]] + +The [arg commandline] is a list of zero or more options followed by zero or +more [vset critcl_script] files. By default, the [vset critcl_script] files +are build and the results cached. This cuts down on the time needed to +load the package. The last occurrence of [option -pkg] and [option -tea], if +provided, selects the corresponding alternative mode of operations. + +For a larger set of examples please see section "Building CriTcl Packages" +in the document about [manpage {Using CriTcl}]. + + +[list_end] + +The options are: +[section {Options}] [include include/aoptions.inc] +[section {Modes Of Operation/Use}] [include include/modes.inc] +[section {Package Structure}] [include include/pstructure.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_bitmap.man b/src/vfs/critcl.vfs/doc/critcl_bitmap.man new file mode 100644 index 00000000..15bf5ed2 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_bitmap.man @@ -0,0 +1,161 @@ +[comment {-*- tcl -*- doctools manpage}] +[vset bitmap_version 1.1] +[manpage_begin critcl::bitmap n [vset bitmap_version]] +[include include/module2.inc] +[keywords singleton {Tcl Interp Association}] +[keywords bitmask bitset flags] +[titledesc {CriTcl - Wrap Support - Bitset en- and decoding}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::bitmap [opt [vset bitmap_version]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the +[package critcl::bitmap] package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package [package critcl::iassoc]. + +[para] C level libraries often use bit-sets to encode many flags into a +single value. Tcl bindings to such libraries now have the task of +converting a Tcl representation of such flags (like a list of strings) +into such bit-sets, and back. + +[emph Note] here that the C-level information has to be something which +already exists. The package does [emph not] create these values. This is +in contrast to the package [package critcl::enum] which creates an +enumeration based on the specified symbolic names. + +[para] This package was written to make the declaration and management +of such bit-sets and their associated conversions functions easy, +hiding all attendant complexity from the user. + +[para] Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code. + +[para] This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] + +[list_begin definitions] +[call [cmd ::critcl::bitmap::def] [arg name] [arg definition] [opt [arg exclusions]]] + +This command defines two C functions for the conversion of the +[arg name]d bit-set into Tcl lists, and vice versa. + +The underlying mapping tables are automatically initialized on first +access, and finalized on interpreter destruction. + +[para] The [arg definition] dictionary provides the mapping from the +Tcl-level symbolic names of the flags to their C expressions (often +the name of the macro specifying the actual value). + +[emph Note] here that the C-level information has to be something which +already exists. The package does [emph not] create these values. This is +in contrast to the package [package critcl::enum] which creates an +enumeration based on the specified symbolic names. + +[para] The optional [arg exlusion] list is for the flags/bit-sets for +which conversion from bit-set to flag, i.e. decoding makes no +sense. One case for such, for example, are flags representing a +combination of other flags. + +[para] The package generates multiple things (declarations and +definitions) with names derived from [arg name], which has to be a +proper C identifier. + +[list_begin definitions] +[def [arg name]_encode] +The function for encoding a Tcl list of strings into the equivalent +bit-set. + +Its signature is +[para][example_begin] +int [arg name]_encode (Tcl_Interp* interp, Tcl_Obj* flags, int* result); +[example_end] + +[para] The return value of the function is a Tcl error code, +i.e. [const TCL_OK], [const TCL_ERROR], etc. + +[def [arg name]_decode] +The function for decoding a bit-set into the equivalent Tcl list of +strings. + +Its signature is +[para][example_begin] +Tcl_Obj* [arg name]_decode (Tcl_Interp* interp, int flags); +[example_end] + +[def [arg name].h] +A header file containing the declarations for the two conversion +functions, for use by other parts of the system, if necessary. + +[para] The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files ([cmd csources]). + +[def [arg name]] +The name of a critcl argument type encapsulating the encoder function +for use by [cmd critcl::cproc]. + +[def [arg name]] +The name of a critcl result type encapsulating the decoder function +for use by [cmd critcl::cproc]. + +[list_end] +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Example] + +The example shown below is the specification of the event flags pulled +from the draft work on a Tcl binding to Linux's inotify APIs. + +[example { +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::bitmap +} + +critcl::bitmap::def tcl_inotify_events { + accessed IN_ACCESS + all IN_ALL_EVENTS + attribute IN_ATTRIB + closed IN_CLOSE + closed-nowrite IN_CLOSE_NOWRITE + closed-write IN_CLOSE_WRITE + created IN_CREATE + deleted IN_DELETE + deleted-self IN_DELETE_SELF + dir-only IN_ONLYDIR + dont-follow IN_DONT_FOLLOW + modified IN_MODIFY + move IN_MOVE + moved-from IN_MOVED_FROM + moved-self IN_MOVE_SELF + moved-to IN_MOVED_TO + oneshot IN_ONESHOT + open IN_OPEN + overflow IN_Q_OVERFLOW + unmount IN_UNMOUNT +} { + all closed move oneshot +} + +# Declarations: tcl_inotify_events.h +# Encoder: int tcl_inotify_events_encode (Tcl_Interp* interp, Tcl_Obj* flags, int* result); +# Decoder: Tcl_Obj* tcl_inotify_events_decode (Tcl_Interp* interp, int flags); +# crit arg-type tcl_inotify_events +# crit res-type tcl_inotify_events +}] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_build.man b/src/vfs/critcl.vfs/doc/critcl_build.man new file mode 100644 index 00000000..cb222aa4 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_build.man @@ -0,0 +1,17 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include version.inc] +[manpage_begin critcl_build_tool n [vset VERSION]] +[include include/module.inc] +[titledesc {CriTcl build.tcl Tool Reference}] +[description] +[include include/welcome.inc] + +The script [file build.tcl] found in the top directory of the [vset critcl] sources is the +main tool of use to a developer or maintainer of [vset critcl] itself. + +[para] Invoking it a via [example {./build.tcl help}] provides the online help for this +tool, explaining the operations available, and their arguments. + +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_callback.man b/src/vfs/critcl.vfs/doc/critcl_callback.man new file mode 100644 index 00000000..19890b3b --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_callback.man @@ -0,0 +1,196 @@ +[vset VERSION 1.1] +[comment {-*- tcl -*- doctools manpage}] +[manpage_begin critcl::callback n [vset VERSION]] +[include include/module2.inc] +[titledesc {CriTcl - C-level Callback Utilities}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::callback [opt [vset VERSION]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the +[package critcl::callback] package. + +This package provides, via a stubs API table, data structures and +functions to manage callbacks from C to Tcl. The package has no +Tcl-level facilities. + +Its intended audience are mainly developers wishing to write Tcl +packages with embedded C code who have to invoke user-specified +command (prefixes) in Tcl. + +[para] +This package resides in the Support Package Layer of CriTcl. + +[para][image arch_support][para] + +[comment {= = == === ===== ======== ============= =====================}] +[section API] + +The package API consist of one opaque data structure +([type critcl_callback_p]) and four functions operating on the same. + +These functions are + +[list_begin definitions] +[comment {* * ** *** ***** ******** ************* *********************}] +[call [type critcl_callback_p] [fun critcl_callback_new] \ + [arg interp] [arg objc] [arg objv] [arg nargs]] + +This function creates a new callback (manager) and returns it as its result. + +[para] +The callback is initialized with the Tcl_Interp* [arg interp] +specifying where to run the callback, the fixed part of the command to +run in standard [arg objc]/[arg objv] notation, plus the number of +free arguments to expect after the fixed part. + +[para] +The fixed part is the essentially the command prefix of the callback. + +[para] +All [type Tcl_Obj*] elements of [arg objv] are protected against early +release by incrementing their reference counts. The callback +effectively takes ownership of these objects. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [type void] [fun critcl_callback_extend] \ + [arg callback] [arg argument]] + +This function takes a [arg callback] of type [type critcl_callback_p] +and extends its fixed part with the [arg argument], taking the first +free slot for arguments to do so. + +This means that after the application of this function the specified +callback has one free argument less. + +[para] +With assertions active attempting to extend beyond the number of free +arguments will cause a panic. Without assertions active expect a crash +at some point. + +[para] +This allows the user to extend the fixed part of the callback with +semi-fixed elements, like method names (See [sectref {Multiple methods}]). + +[para] +The [arg argument] is protected against early release by incrementing +its reference count. The callback effectively takes ownership of this +object. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [type void] [fun critcl_callback_destroy] \ + [arg callback]] + +This function takes a [arg callback] of type [type critcl_callback_p] +and releases all memory associated with it. + +After application of this function the callback cannot be used anymore. + +[para] +All fixed elements of the callback (owned by it) are released by +decrementing their reference counts. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [type int] [fun critcl_callback_invoke] \ + [arg callback] [arg objc] [arg objv]] + +This function invokes the callback in the Tcl interpreter specified at +the time of construction, in the global level and namespace, with the +free arguments filled by the [type Tcl_Obj*] objects specified via +[arg objc]/[arg objv]. + +[para] +It returns the Tcl status of the invoked command as its result. + +Any further results or error messages will be found in the result area +of the Tcl interpreter in question. The exact nature of such is +dependent on the callback itself. + +[para] +With assertions active attempting to use more arguments than available +will cause a panic. Without assertions active expect a crash at some +point. + +[para] +While the callback is running all [type Tcl_Obj*] elements of the +command, fixed and arguments, are protected against early release by +temporarily incrementing their reference counts. + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Examples] + +[subsection {Simple callback}] + +The example here shows the important parts of using the functions of +this package for a simple callback which is invoked with a single +argument, some kind of data to hand to the Tcl level. + +[example { + // Create the callback with interpreter and command prefix in + // oc/ov, plus space for the argument + critcl_callback_p cb = critcl_callback_new (interp, oc, ov, 1); + + // Invoke the callback somewhere in the C package using this one, + // with Tcl_Obj* data holding the information to pass up. + critcl_callback_invoke (cb, 1, &data); + + // At the end of the lifetime, release the callback. + critcl_callback_destroy (cb); +}] + +Note that the functions of this package are designed for the case +where the created callback ([const cb] above) is kept around for a +long time, and many different invokations. + +[para] +Using the sequence above as is, creating and destroying the callback +each time it is invoked will yield very poor performance and lots of +undesirable memory churn. + + +[subsection {Multiple methods}] + +While we can use the methodology of the previous section when a single +(Tcl-level) callback is invoked from different places in C, with +different methods, simply having another argument slot and filling it +an invokation time with the method object, a second methodology is +open to us due to [fun critcl_callback_extend]. + +[example { + + // Create one callback manager per different method the callback + // will be used with. Fill the first of the two declared arguments + // with the different methods. + critcl_callback_p cb_a = critcl_callback_new (interp, oc, ov, 2); + critcl_callback_p cb_b = critcl_callback_new (interp, oc, ov, 2); + + critcl_callback_extend (cb_a, Tcl_NewStringObj ("method1", -1)); + critcl_callback_extend (cb_b, Tcl_NewStringObj ("method2", -1)); + + // After the extension we have one free argument left, for use in + // the invokations. + + critcl_callback_invoke (cb_a, 1, &dataX); + + critcl_callback_invoke (cb_b, 1, &dataY); + + + // At the end release both managers again + critcl_callback_destroy (cb_a); + critcl_callback_destroy (cb_b); +}] + +The nice thing here is that the method objects are allocated only once +and automatically shared by all the calls. No memory churn to +repeatedly allocate the same string objects over and over again. + + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_changes.man b/src/vfs/critcl.vfs/doc/critcl_changes.man new file mode 100644 index 00000000..5737bc9f --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_changes.man @@ -0,0 +1,16 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include version.inc] +[manpage_begin critcl_changes n [vset VERSION]] +[include include/module.inc] +[titledesc {CriTcl Releases & Changes}] +[description] +[include include/welcome.inc] +[include include/advert.inc] + +See the changes done in each release of [vset critcl], from the latest at the top to the +beginning of the project. + +[include include/changes.inc] +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_class.man b/src/vfs/critcl.vfs/doc/critcl_class.man new file mode 100644 index 00000000..68efd81c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_class.man @@ -0,0 +1,57 @@ +[comment {-*- tcl -*- doctools manpage}] +[vset VERSION 1.1] +[manpage_begin critcl::class n [vset VERSION]] +[include include/module2.inc] +[keywords {C class} {C object} {C instance}] +[titledesc {CriTcl - Code Gen - C Classes}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::class [opt [vset VERSION]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the [package critcl::class] +package. This package provides convenience commands for advanced +functionality built on top of the core. + +[para] With it a user wishing to create a C level object with class +and instance commands can concentrate on specifying the class- and +instance-variables and -methods in a manner similar to a TclOO class, +while all the necessary boilerplate around it is managed by this +package. + +[para] Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code. + +[para] This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] + +[list_begin definitions] +[call [cmd ::critcl::class::define] [arg name] [arg script]] + +This is the main command to define a new class [arg name], where +[arg name] is the name of the Tcl command representing the class, +i.e. the [term {class command}]. The [arg script] provides the +specification of the class, i.e. information about included headers, +class- and instance variables, class- and instance-methods, etc. + +See the section [sectref {Class Specification API}] below for the +detailed list of the available commands and their semantics. + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section {Class Specification API}][include include/class_spec.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[section Example][include include/class_example.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_cproc.man b/src/vfs/critcl.vfs/doc/critcl_cproc.man new file mode 100644 index 00000000..2d8f8e31 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_cproc.man @@ -0,0 +1,40 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include pkg_version.inc] +[manpage_begin critcl_cproc_types n [vset VERSION]] +[include include/module.inc] +[titledesc {CriTcl cproc Type Reference}] +[require Tcl 8.6] +[require critcl [opt [vset VERSION]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is a breakout of the descriptions for the predefined argument- and result-types usable +with the [cmd critcl::cproc] command, as detailed in the reference manpage for the [package critcl] +package, plus the information on how to extend the predefined set with custom types. The breakout +was made to make this information easier to find (toplevel document vs. having to search the large +main reference). + +[para] Its intended audience are developers wishing to write Tcl packages with embedded C code. + +[section {Standard argument types}] [include include/cproc/api_stdat_cproc.inc] +[section {Standard result types}] [include include/cproc/api_stdrt_cproc.inc] +[section {Advanced: Adding types}] [include include/cproc/api_extcproc2.inc] + +[section Examples] + +The examples shown here have been drawn from the section "Embedding C" in the document about +[manpage {Using CriTcl}]. Please see that document for many more examples. + +[include include/cproc/using_eproc.inc] [comment {%% cproc}] +[include include/cproc/using_eprocstr.inc] [comment {%% cproc, strings}] +[include include/cproc/using_eproctypes.inc] [comment {%% cproc types, intro & trivial}] +[include include/cproc/using_eproctypes2.inc] [comment {%% cproc types, semi-trivial}] +[include include/cproc/using_eproctypes3.inc] [comment {%% cproc types, support (incl alloc'd)}] +[include include/cproc/using_eproctypes4.inc] [comment {%% cproc types, results}] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_cutil.man b/src/vfs/critcl.vfs/doc/critcl_cutil.man new file mode 100644 index 00000000..ff5003b6 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_cutil.man @@ -0,0 +1,413 @@ +[vset VERSION 0.3] +[comment {-*- tcl -*- doctools manpage}] +[manpage_begin critcl::cutil n [vset VERSION]] +[include include/module2.inc] +[titledesc {CriTcl - C-level Utilities}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::cutil [opt [vset VERSION]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the [package critcl::cutil] +package. This package encapsulates a number of C-level utilites for +easier writing of memory allocations, assertions, and narrative tracing +and provides convenience commands to make these utilities accessible +to critcl projects. + +Its intended audience are mainly developers wishing to write Tcl +packages with embedded C code. +[para] + +This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +The reason for this is that the main [package critcl] package makes +use of the facilities for narrative tracing when +[cmd {critcl::config trace}] is set, to instrument commands and +procedures. + +[comment {= = == === ===== ======== ============= =====================}] +[section API] + +[list_begin definitions] +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::cutil::alloc]] + +This command provides a number C-preprocessor macros which make the +writing of memory allocations for structures and arrays of structures +easier. + +[para] When run the header file [file critcl_alloc.h] is directly made +available to the [file .critcl] file containing the command, and +becomes available for use in [cmd {#include}] directives of companion +C code declared via [cmd critcl::csources]. + +[para] The macros definitions and their signatures are: + +[example { + type* ALLOC (type) + type* ALLOC_PLUS (type, int n) + type* NALLOC (type, int n) + type* REALLOC (type* var, type, int n) + void FREE (type* var) + + void STREP (Tcl_Obj* o, char* s, int len); + void STREP_DS (Tcl_Obj* o, Tcl_DString* ds); + void STRDUP (varname, char* str); +}] + +[para] The details of the semantics are explained in section +[sectref Allocation]. + +[para] The result of the command is an empty string. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::cutil::assertions] [opt [arg enable]]] + +This command provides a number C-preprocessor macros for the writing +of assertions in C code. + +[para] When invoked the header file [file critcl_assert.h] is directly +made available to the [file .critcl] file containing the command, and +becomes available for use in [cmd {#include}] directives of companion +C code declared via [cmd critcl::csources]. + +[para] The macro definitions and their signatures are + +[example { + void ASSERT (expression, char* message); + void ASSERT_BOUNDS (int index, int size); + + void STOPAFTER (int n); +}] + +[para] Note that these definitions are conditional on the existence of +the macro [const CRITCL_ASSERT]. + +Without a [cmd {critcl::cflags -DCRITCL_ASSERT}] all assertions in the +C code are quiescent and not compiled into the object file. In other +words, assertions can be (de)activated at will during build time, as +needed by the user. + +[para] For convenience this is controlled by [arg enable]. By default +([const false]) the facility available, but not active. + +Using [const true] not only makes it available, but activates it as +well. + +[para] The details of the semantics are explained in section +[sectref Assertions]. + +[para] The result of the command is an empty string. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::cutil::tracer] [opt [arg enable]]] + +This command provides a number C-preprocessor macros for tracing +C-level internals. + +[para] When invoked the header file [file critcl_trace.h] is directly +made available to the [file .critcl] file containing the command, and +becomes available for use in [cmd {#include}] directives of companion +C code declared via [cmd critcl::csources]. Furthermore the [file .c] +file containing the runtime support is added to the set of C companion +files + +[para] The macro definitions and their signatures are + +[example { + /* (de)activation of named logical streams. + * These are declarators, not statements. + */ + + TRACE_ON; + TRACE_OFF; + TRACE_TAG_ON (tag_identifier); + TRACE_TAG_OFF (tag_identifier); + + /* + * Higher level trace statements (convenience commands) + */ + + void TRACE_FUNC (const char* format, ...); + void TRACE_FUNC_VOID; + any TRACE_RETURN (const char* format, any x); + void TRACE_RETURN_VOID; + void TRACE (const char* format, ...); + + /* + * Low-level trace statements the higher level ones above + * are composed from. Scope management and output management. + */ + + void TRACE_PUSH_SCOPE (const char* scope); + void TRACE_PUSH_FUNC; + void TRACE_POP; + + void TRACE_HEADER (int indent); + void TRACE_ADD (const char* format, ...); + void TRACE_CLOSER; + + /* + * Convert tag to the underlying status variable. + */ + + TRACE_TAG_VAR (tag) + + /* + * Conditional use of arbitrary code. + */ + + TRACE_RUN (code); + TRACE_DO (code); + TRACE_TAG_DO (code); +}] + +[para] Note that these definitions are conditional on the existence of +the macro [const CRITCL_TRACER]. + +Without a [cmd {critcl::cflags -DCRITCL_TRACER}] all trace +functionality in the C code is quiescent and not compiled into the +object file. In other words, tracing can be (de)activated at will +during build time, as needed by the user. + +[para] For convenience this is controlled by [arg enable]. By default +([const false]) the facility available, but not active. + +Using [const true] not only makes it available, but activates it as +well. + +Further note that the command [cmd critcl::config] now accepts a +boolean option [const trace]. Setting it activates enter/exit tracing +in all commands based on [cmd critcl::cproc], with proper printing of +arguments and results. This implicitly activates the tracing facility +in general. + +[para] The details of the semantics are explained in section +[sectref Tracing] + +[para] The result of the command is an empty string. + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Allocation] + +[list_begin definitions] +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {type* ALLOC (type)}]] + +This macro allocates a single element of the given [arg type] and +returns a pointer to that memory. + +[call [cmd {type* ALLOC_PLUS (type, int n)}]] + +This macro allocates a single element of the given [arg type], plus an +additional [arg n] bytes after the structure and returns a pointer to +that memory. + +[para] This is for variable-sized structures of. An example of such +could be a generic list element structure which stores management +information in the structure itself, and the value/payload immediately +after, in the same memory block. + +[call [cmd {type* NALLOC (type, int n)}]] + +This macro allocates [arg n] elements of the given [arg type] and +returns a pointer to that memory. + +[call [cmd {type* REALLOC (type* var, type, int n)}]] + +This macro expands or shrinks the memory associated with the C +variable [arg var] of type [arg type] to hold [arg n] elements of the +type. It returns a pointer to that memory. + +Remember, a reallocation may move the data to a new location in memory +to satisfy the request. Returning a pointer instead of immediately +assigning it to the [arg var] allows the user to validate the new +pointer before trying to use it. + +[call [cmd {void FREE (type* var)}]] + +This macro releases the memory referenced by the pointer variable +[arg var]. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void STREP (Tcl_Obj* o, char* s, int len)}]] + +This macro properly sets the string representation of the Tcl object +[arg o] to a copy of the string [arg s], expected to be of length +[arg len]. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void STREP_DS (Tcl_Obj* o, Tcl_DString* ds)}]] + +This macro properly sets the string representation of the Tcl object +[arg o] to a copy of the string held by the [type DString] [arg ds]. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void STRDUP (varname, char* str)}]] + +This macro duplicates the string [arg str] into the heap and stores +the result into the named [type char*] variable [arg var]. + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Assertions] + +[list_begin definitions] +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void ASSERT (expression, char* message}]] + +This macro tests the [arg expression] and panics if it does not hold. +The specified [arg message] is used as part of the panic. +The [arg message] has to be a static string, it cannot be a variable. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void ASSERT_BOUNDS (int index, int size)}]] + +This macro ensures that the [arg index] is in the +range [const 0] to [const {size-1}]. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void STOPAFTER(n)}]] + +This macro throws a panic after it is called [arg n] times. +Note, each separate instance of the macro has its own counter. + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Tracing] + +All output is printed to [const stdout]. + +[list_begin definitions] + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd TRACE_ON]] +[call [cmd TRACE_OFF]] +[call [cmd {TRACE_TAG_ON (identifier)}]] +[call [cmd {TRACE_TAG_OFF (identifier)}]] + +These "commands" are actually declarators, for use outside of +functions. They (de)activate specific logical streams, named either +explicitly by the user, or implicitly, refering to the current file. + +[para] For example: +[para][example { + TRACE_TAG_ON (lexer_in); +}] + +[para] All high- and low-level trace commands producing output have +the controlling tag as an implicit argument. The scope management +commands do not take tags. + + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE_FUNC}]] +[call [cmd {void TRACE_TAG_FUNC (tag)}]] +[call [cmd {void TRACE_FUNC_VOID}]] +[call [cmd {void TRACE_TAG_FUNC_VOID (tag)}]] + +Use these macros at the beginning of a C function to record entry into +it. The name of the entered function is an implicit argument +([var __func__]), forcing users to have a C99 compiler.. + +[para] The tracer's runtime maintains a stack of active functions and +expects that function return is signaled by either [fun TRACE_RETURN], +[fun TRACE_RETURN_VOID], or the equivalent forms taking a tag. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE_RETURN_VOID}]] +[call [cmd {void TRACE_TAG_RETURN_VOID (tag)}]] + +Use these macros instead of [example {return}] to return from a void +function. Beyond returning from the function this also signals the +same to the tracer's runtime, popping the last entered function from +its stack of active functions. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {any TRACE_RETURN ( char* format, any x)}]] +[call [cmd {any TRACE_TAG_RETURN (tag, char* format, any x)}]] + +Use this macro instead of [example {return x}] to return from a +non-void function. + +Beyond returning from the function with value [arg x] this also +signals the same to the tracer's runtime, popping the last entered +function from its stack of active functions. + +The [arg format] is expected to be a proper formatting string for +[fun printf] and analogues, able to stringify [arg x]. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE ( char* format, ...)}]] +[call [cmd {void TRACE_TAG (tag, char* format, ...)}]] + +This macro is the trace facilities' equivalent of [fun printf], +printing arbitrary data under the control of the [arg format]. + +[para] The printed text is closed with a newline, and indented as per +the stack of active functions. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE_HEADER (int indent)}]] +[call [cmd {void TRACE_TAG_HEADER (tag, int indent)}]] + +This is the low-level macro which prints the beginning of a trace +line. This prefix consists of physical location (file name and line +number), if available, indentation as per the stack of active scopes +(if activated), and the name of the active scope. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE_CLOSER}]] +[call [cmd {void TRACE_TAG_CLOSER (tag)}]] + +This is the low-level macro which prints the end of a trace +line. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE_ADD (const char* format, ...)}]] +[call [cmd {void TRACE_TAG_ADD (tag, const char* format, ...)}]] + +This is the low-level macro which adds formatted data to the line. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {void TRACE_PUSH_SCOPE (const char* name)}]] +[call [cmd {void TRACE_PUSH_FUNC}]] +[call [cmd {void TRACE_PUSH_POP}]] + +These are the low-level macros for scope management. The first two +forms push a new scope on the stack of active scopes, and the last +forms pops the last scope pushed. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {TRACE_TAG_VAR (tag)}]] + +Helper macro converting from a tag identifier to the name of the +underlying status variable. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {TRACE_RUN (code);}]] + +Conditionally insert the [arg code] at compile time when the tracing +facility is activated. + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd {TRACE_DO (code);}]] +[call [cmd {TRACE_TAG_DO (tag, code);}]] + +Insert the [arg code] at compile time when the tracing facility is +activated, and execute the same when either the implicit tag for the +file or the user-specified tag is active. + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_devguide.man b/src/vfs/critcl.vfs/doc/critcl_devguide.man new file mode 100644 index 00000000..2465baeb --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_devguide.man @@ -0,0 +1,228 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include version.inc] +[manpage_begin critcl_devguide n [vset VERSION]] +[include include/module.inc] +[titledesc {Guide To The CriTcl Internals}] +[description] +[include include/welcome.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[section Audience] + +[para] This document is a guide for developers working on CriTcl, i.e. maintainers fixing +bugs, extending the package's functionality, etc. + +[para] Please read + +[list_begin enum] +[enum] [term {CriTcl - License}], +[enum] [term {CriTcl - How To Get The Sources}], and +[enum] [term {CriTcl - The Installer's Guide}] +[list_end] + +first, if that was not done already. + +[para] Here we assume that the sources are already available in a directory of the readers +choice, and that the reader not only know how to build and install them, but also has all +the necessary requisites to actually do so. The guide to the sources in particular also +explains which source code management system is used, where to find it, how to set it up, +etc. + +[section {Playing with CriTcl}] +[include include/largeexampleref.inc] +[include include/smallexampleref.inc] + + +[section {Developing for CriTcl}] + +[comment @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@] +[subsection {Architecture & Concepts}] +[include include/architecture.inc] + +[comment @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@] +[subsection Requirements] + +To develop for critcl the following packages and applications must be available in the +environment. These are all used by the [cmd build.tcl] helper application. + +[list_begin definitions] +[def [syscmd dtplite]] + +A Tcl application provided by Tcllib, for the validation and conversion of +[term doctools]-formatted text. + +[def [syscmd dia]] + +A Tcl application provided by Tklib, for the validation and conversion +of [package diagram]-formatted figures into raster images. + +[para] Do not confuse this with the Gnome [syscmd dia] application, which is a graphical +editor for figures and diagrams, and completely unrelated. + +[def [package fileutil]] +A Tcl package provided by Tcllib, providing file system utilities. + +[def "[package vfs::mk4], [package vfs]"] +Tcl packages written in C providing access to Tcl's VFS facilities, required for the +generation of critcl starkits and starpacks. + +[list_end] + +[comment @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@] +[subsection {Directory structure}] + +[list_begin definitions][comment {___1___}] + +[comment {= = == === ===== ======== ============= =======================}] +[def Helpers] +[list_begin definitions] +[def [file build.tcl]] + +This helper application provides various operations needed by a developer for critcl, like +regenerating the documentation, the figures, building and installing critcl, etc. + +[para] Running the command like + +[example { + ./build.tcl help +}] + +will provide more details about the available operations and their arguments. +[list_end] + +[comment {= = == === ===== ======== ============= =======================}] +[def Documentation] +[list_begin definitions] +[def [file doc/]] + +This directory contains the documentation sources, for both the text, and the figures. +The texts are written in [term doctools] format, whereas the figures are written for +tklib's [package dia](gram) package and application. + +[def [file embedded/]] + +This directory contains the documentation converted to regular manpages (nroff) and HTML. + +It is called embedded because these files, while derived, are part of the git repository, +i.e. embedded into it. This enables us to place these files where they are visible when +serving the prject's web interface. + +[list_end] + +[comment {= = == === ===== ======== ============= =======================}] +[def Testsuite] +[list_begin definitions] +[def [file test/all.tcl]] +[def [file test/testutilities.tcl]] +[def [file test/*.test]] + +These files are a standard testsuite based on Tcl's [package tcltest] package, with some +utility code snarfed from [package Tcllib]. + +[para] This currently tests only some of the [package stubs::*] packages. + +[def [file test/*.tcl]] + +These files (except for [file all.tcl] and [file testutilities.tcl]) are example files +(Tcl with embedded C) which can be run through critcl for testing. + +[para] [strong TODO] for a maintainers: These should be converted into a proper test suite. + +[list_end] + +[comment {= = == === ===== ======== ============= =======================}] +[def {Package Code, General structure}] + +[list_begin definitions] +[list_end] + +[comment {= = == === ===== ======== ============= =======================}] +[def {Package Code, Per Package}] +[list_begin definitions][comment ----------------------PCPP] + +[def [package critcl]] +[list_begin definitions][comment ---------------critcl] +[def [file lib/critcl/critcl.tcl]] +The Tcl code implementing the package. + +[def [file lib/critcl/Config]] +The configuration file for the standard targets and their settings. + +[def [file lib/critcl/critcl_c/]] +Various C code snippets used by the package. + +This directory also contains the copies of the Tcl header files used to compile the +assembled C code, for the major brnaches of Tcl, i.e. 8.4, 8.5, and 8.6. + +[list_end][comment -----------------------------critcl] + +[def [package critcl::util]] +[list_begin definitions][comment ---------------critcl::util] +[def [file lib/critcl-util/util.tcl]] +The Tcl code implementing the package. +[list_end][comment -----------------------------critcl::util] + +[def [package critcl::app]] +[list_begin definitions][comment ---------------critcl::app] +[def [file lib/app-critcl/critcl.tcl]] +The Tcl code implementing the package. +[list_end][comment -----------------------------critcl::app] + +[def [package critcl::iassoc]] +[list_begin definitions][comment ---------------critcl::iassoc] +[def [file lib/critcl-iassoc/iassoc.tcl]] +The Tcl code implementing the package. +[def [file lib/critcl-iassoc/iassoc.h]] +C code template used by the package. +[list_end][comment -----------------------------critcl::iassoc] + +[def [package critcl::class]] +[list_begin definitions][comment ---------------critcl::class] +[def [file lib/critcl-class/class.tcl]] +The Tcl code implementing the package. +[def [file lib/critcl-class/class.h]] +C code template used by the package. +[list_end][comment -----------------------------critcl::class] + + +[def [package stubs::*]] +[list_begin definitions][comment ---------------stubs] +[def [file lib/stubs/*]] + +A set of non-public (still) packages which provide read and write access to and represent +Tcl stubs tables. These were created by taking the [file genStubs.tcl] helper application +coming with the Tcl core sources apart along its internal logical lines. + +[list_end][comment -----------------------------stubs] + +[def [package critclf]] +[list_begin definitions][comment ---------------critclf] +[def [file lib/critclf/]] + +Arjen Markus' work on a critcl/Fortran. The code is outdated and has not been adapted to +the changes in critcl version 3 yet. + +[list_end][comment -----------------------------critclf] + +[def [package md5]] +[def [package md5c]] +[def [package platform]] + +These are all external packages whose code has been inlined in the repository for easier +development (less dependencies to pull), and quicker deployment from the repository +(generation of starkit and -pack). + +[para] [strong TODO] for maintainers: These should all be checked against their origin for +updates and changes since they were inlined. + +[list_end][comment ------------------------------------PCPP] + +[list_end][comment {___1___}] + +[comment {TODO **** Package dependency diagram ****}] +[comment {TODO **** Diagram of the internal call graph ? ****}] +[comment {TODO **** Add test/ ****}] + +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_emap.man b/src/vfs/critcl.vfs/doc/critcl_emap.man new file mode 100644 index 00000000..6ad25e07 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_emap.man @@ -0,0 +1,185 @@ +[comment {-*- tcl -*- doctools manpage}] +[vset emap_version 1.3] +[manpage_begin critcl::emap n [vset emap_version]] +[include include/module2.inc] +[keywords singleton {Tcl Interp Association}] +[keywords bitmask bitset flags] +[titledesc {CriTcl - Wrap Support - Enum en- and decoding}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::emap [opt [vset emap_version]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the +[package critcl::emap] package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package [package critcl::iassoc]. + +[para] C level libraries often use enumerations or integer values to encode +information, like the state of a system. Tcl bindings to such libraries now +have the task of converting a Tcl representation, i.e. a string into such +state, and back. + +[emph Note] here that the C-level information has to be something which +already exists. The package does [emph not] create these values. This is +in contrast to the package [package critcl::enum] which creates an +enumeration based on the specified symbolic names. + +[para] This package was written to make the declaration and management +of such enumerations and their associated conversions functions easy, +hiding all attendant complexity from the user. + +[para] Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code. + +[para] This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] + +[list_begin definitions] +[call [cmd ::critcl::emap::def] [arg name] [arg definition] \ + [opt [option -nocase]] \ + [opt "[option -mode] [arg mode]"]] + +This command defines C functions for the conversion of the [arg name]d +state code into a Tcl string, and vice versa. + +The underlying mapping tables are automatically initialized on first +access (if not fully constant), and finalized on interpreter +destruction. + +[para] The [arg definition] dictionary provides the mapping from the +Tcl-level symbolic names of the state to their C expressions (often +the name of the macro specifying the actual value). + +[emph Note] here that the C-level information has to be something which +already exists. The package does [emph not] create these values. This is +in contrast to the package [package critcl::enum] which creates an +enumeration based on the specified symbolic names. + +[para] Further note that multiple strings can be mapped to the same C +expression. When converting to Tcl the first string for the mapping is +returned. An important thing to know: If all C expressions are +recognizable as integer numbers and their covered range is not too +large (at most 50) the package will generate code using direct and +fast mapping tables instead of using a linear search. + +[para] If the option [option -nocase] is specified then the encoder +will match strings case-insensitively, and the decoder will always +return a lower-case string, regardless of the string's case in the +[arg definition]. + +[para] If the option [option -mode] is specified its contents will +interpreted as a list of access modes to support. The two allowed +modes are [const c] and [const tcl]. Both modes can be used +together. The default mode is [const tcl]. + +[para] The package generates multiple things (declarations and +definitions) with names derived from [arg name], which has to be a +proper C identifier. Some of the things are generated conditional on +the chosen [arg mode]s. + +[list_begin definitions] +[def [arg name]_encode] +The [const tcl]-mode function for encoding a Tcl string into the +equivalent state code. + +Its signature is +[para][example_begin] +int [arg name]_encode (Tcl_Interp* interp, Tcl_Obj* state, int* result); +[example_end] + +[para] The return value of the function is a Tcl error code, +i.e. [const TCL_OK], [const TCL_ERROR], etc. + +[def [arg name]_encode_cstr] +The [const c]-mode function for encoding a C string into the +equivalent state code. + +Its signature is +[para][example_begin] +int [arg name]_encode_cstr (const char* state); +[example_end] + +[para] The return value of the function is the encoded state, or -1 if +the argument is not a vlaid state. + +[def [arg name]_decode] +The [const tcl]-mode function for decoding a state code into the +equivalent Tcl string. + +Its signature is +[para][example_begin] +Tcl_Obj* [arg name]_decode (Tcl_Interp* interp, int state); +[example_end] + +[def [arg name]_decode_cstr] +The [const c]-mode function for decoding a state code into the +equivalent C string. + +Its signature is +[para][example_begin] +const char* [arg name]_decode_cstr (int state); +[example_end] + +[para] The return value of the function is the C string for the state, +or [const NULL] if the [arg state] argument does not contain a valid +state value. + + +[def [arg name].h] +A header file containing the declarations for the conversion +functions, for use by other parts of the system, if necessary. + +[para] The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files ([cmd csources]). + +[def [arg name]] +For mode [const tcl] the command registers a new argument-type for +[cmd critcl::cproc] with critcl, encapsulating the encoder function. + +[def [arg name]] +For mode [const tcl] the command registers a new result-type for +[cmd critcl::cproc] with critcl, encapsulating the decoder function. + +[list_end] +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Example] + +The example shown below is the specification for the possible modes of +entry (normal, no feedback, stars) used by the Tcl binding to the +linenoise library. + +[example { +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::emap +} + +critcl::emap::def hiddenmode { + no 0 n 0 off 0 false 0 0 0 + all 1 yes 1 y 1 on 1 true 1 1 1 + stars 2 +} -nocase + +# Declarations: hiddenmode.h +# Encoder: int hiddenmode_encode (Tcl_Interp* interp, Tcl_Obj* state, int* result); +# Decoder: Tcl_Obj* hiddenmode_decode (Tcl_Interp* interp, int state); +# ResultType: hiddenmode +# ArgumentType: hiddenmode +}] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_enum.man b/src/vfs/critcl.vfs/doc/critcl_enum.man new file mode 100644 index 00000000..6c9d486b --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_enum.man @@ -0,0 +1,172 @@ +[comment {-*- tcl -*- doctools manpage}] +[vset enum_version 1.2] +[manpage_begin critcl::enum n [vset enum_version]] +[include include/module2.inc] +[keywords singleton {Tcl Interp Association}] +[keywords {string pool} {literal pool}] +[keywords {string to int mapping} conversion] +[keywords {int to string mapping}] +[titledesc {CriTcl - Wrap Support - String/Integer mapping}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::enum [opt [vset enum_version]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the +[package critcl::enum] package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package [package critcl::literals]. + +[para] It is an extended form of string pool which not only converts +integer values into Tcl-level strings, but also handles the reverse +direction, converting from strings to the associated integer values. + +[para] It essentially provides a bi-directional mapping between a C +enumeration type and a set of strings, one per enumeration value. + +[emph Note] that the C enumeration in question is created by the +definition. It is not possible to use the symbols of an existing +enumeration type. + +[para] This package was written to make the declaration and management +of such mappings easy. It uses a string pool for one of the directions, +using its ability to return shared literals and conserve memory. + +[para] Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code. + +[para] This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] + +[list_begin definitions] +[call [cmd ::critcl::enum::def] [arg name] [arg definition] [opt [arg mode]]] + +This command defines two C functions for the conversion between +C values and Tcl_Obj'ects, with named derived from [arg name]. + +[para] The [arg definition] dictionary provides the mapping from the +specified C-level symbolic names to the strings themselves. + +[para] +The [arg mode]-list configures the output somewhat. +The two allowed modes are [const +list] and [const tcl]. +All modes can be used together. +The default mode is [const tcl]. +Using mode [const +list] implies [const tcl] as well. + +[para] For mode [const tcl] the new function has two arguments, a +[type Tcl_Interp*] pointer refering to the interpreter holding the +string pool, and a code of type "[arg name]_pool_names" (see below), +the symbolic name of the string to return. The result of the function +is a [type Tcl_Obj*] pointer to the requested string constant. + +[para] For mode [const +list] all of [const tcl] applies, plus an +additional function is generated which takes three arguments, in +order: a [type Tcl_Interp*] pointer refering to the interpreter +holding the string pool, an [type int] holding the size of the last +argument, and an array of type "[arg name]_pool_names" holding the +codes (see below), the symbolic names of the strings to return. The +result of the function is a [type Tcl_Obj*] pointer to a Tcl list +holding the requested string constants. + +[para] The underlying string pool is automatically initialized on +first access, and finalized on interpreter destruction. + +[para] The package generates multiple things (declarations and +definitions) with names derived from [arg name], which has to be a +proper C identifier. + +[list_begin definitions] +[def [arg name]_pool_names] +The C enumeration type containing the specified symbolic names. + +[def [arg name]_ToObj] +The function converting from integer value to Tcl string. + +Its signature is +[para][example_begin] +Tcl_Obj* [arg name]_ToObj (Tcl_Interp* interp, [arg name]_names literal); +[example_end] + +[def [arg name]_ToObjList] +The mode [const +list] function converting from integer array to Tcl +list of strings. + +Its signature is +[para][example_begin] +Tcl_Obj* [arg name]_ToObjList (Tcl_Interp* interp, int c, [arg name]_names* literal); +[example_end] + +[def [arg name]_GetFromObj] +The function converting from Tcl string to integer value. + +Its signature is +[para][example_begin] +int [arg name]_GetFromObj (Tcl_Interp* interp, Tcl_Obj* obj, int flags, int* literal); +[example_end] + +The [arg flags] are like for [fun Tcl_GetIndexFromObj]. + +[def [arg name].h] + +A header file containing the declarations for the converter functions, +for use by other parts of the system, if necessary. + +[para] The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files ([cmd csources]). + +[def [arg name]] +At the level of critcl itself the command registers a new result-type +for [cmd critcl::cproc], which takes an integer result from the function +and converts it to the equivalent string in the pool for the script. + +[def [arg name]] +At the level of critcl itself the command registers a new argument-type +for [cmd critcl::cproc], which takes a Tcl string and converts it to the +equivalent integer for delivery to the function. + +[list_end] +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Example] + +The example shown below is the specification for a set of actions, methods, +and the like, a function may take as argument. + +[example { +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::enum +} + +critcl::enum::def action { + w_create "create" + w_directory "directory" + w_events "events" + w_file "file" + w_handler "handler" + w_remove "remove" +} + +# Declarations: action.h +# Type: action_names +# Accessor: Tcl_Obj* action_ToObj (Tcl_Interp* interp, int literal); +# Accessor: int action_GetFromObj (Tcl_Interp* interp, Tcl_Obj* o, int flags, int* literal); +# ResultType: action +# ArgType: action +}] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_howto_install.man b/src/vfs/critcl.vfs/doc/critcl_howto_install.man new file mode 100644 index 00000000..1179728a --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_howto_install.man @@ -0,0 +1,51 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: how-to}] +[include version.inc] +[manpage_begin critcl_howto_install n [vset VERSION]] +[include include/module.inc] +[titledesc {How To Install CriTcl}] +[description] +[include include/welcome.inc] + +[para] [vset critcl] is installed in four major steps: + +[list_begin enumerated] +[enum] [sectref {Install The Requisites}] +[enum] Follow the instructions on [term {How To Get The CriTcl Sources}] +[enum] [sectref {Install The CriTcl Packages}] +[enum] [sectref {Test The Installation}] +[list_end] + +It is now possible to follow the instructions on [term {How To Use CriTcl}]. + +[comment {= = == === ===== ======== ============= =====================}] +[section {Install The Requisites}] + +This major step breaks down into three minor steps: + +[list_begin enumerated] +[enum] [sectref {Install A Working C Compiler}] and development environment. +[enum] [sectref {Install A Working Tcl Shell}] +[enum] [sectref {Install Supporting Tcl Packages}] +[list_end] + +[subsection {Install A Working C Compiler}] [include include/rq_cc.inc] +[subsection {Install A Working Tcl Shell}] [include include/rq_tcl.inc] +[subsection {Install Supporting Tcl Packages}] [include include/rq_tcllib.inc] + +[comment {= = == === ===== ======== ============= =====================}] +[section {Install The CriTcl Packages}] + +Note that this step has different instructions dependent on the platform [vset critcl] is +to be installed on. In other words, only one of the sub sections applies, the other can be +ignored. + +[subsection {Install On Unix}] [include include/b_unix.inc] +[subsection {Install On Windows}] [include include/b_windows.inc] + +[comment {= = == === ===== ======== ============= =====================}] + +[section {Test The Installation}] [include include/b_test.inc] + +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_howto_sources.man b/src/vfs/critcl.vfs/doc/critcl_howto_sources.man new file mode 100644 index 00000000..887a79f8 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_howto_sources.man @@ -0,0 +1,48 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: how-to}] +[include version.inc] +[manpage_begin critcl_howto_sources n [vset VERSION]] +[include include/module.inc] +[titledesc {How To Get The CriTcl Sources}] +[description] +[include include/welcome.inc] + +[para] The sources for [vset critcl] are retrieved in two easy steps: + +[list_begin enumerated] +[enum] [sectref {Install the Git Source Code Manager}] +[enum] [sectref {Retrieve The Sources}] +[list_end] + +It is now possible to follow the instructions on [term {How To Install CriTcl}]. + +[comment {= = == === ===== ======== ============= =====================}] +[section {Install the Git Source Code Manager}] + +[vset critcl]'s sources are managed by the popular [vset git_home]. + +[para] Binaries of clients for popular platforms can be found at the [vset git_binaries]. + +[para] See also if your operating system's package manager provides clients and associated +tools for installation. If so, follow the instructions for the installation of such +packages on your system. + +[comment {= = == === ===== ======== ============= =====================}] +[section {Retrieve The Sources}] + +[list_begin enumerated] +[enum] Choose a directory for the sources, and make it the working directory. + +[enum] Invoke the command +[example_begin] +git clone [vset project_home] +[example_end] + +[enum] The working directory now contains a sub-directory [file critcl] holding the +sources of [vset critcl]. + +[list_end] + +[include include/feedback.inc] +[manpage_end] + diff --git a/src/vfs/critcl.vfs/doc/critcl_howto_use.man b/src/vfs/critcl.vfs/doc/critcl_howto_use.man new file mode 100644 index 00000000..cae9260c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_howto_use.man @@ -0,0 +1,98 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: how-to}] +[include version.inc] +[manpage_begin critcl_howto_use n [vset VERSION]] +[include include/module.inc] +[titledesc {How To Use CriTcl}] +[description] +[para] +[include include/welcome.inc] + +[para] This document assumes the presence of a working [vset critcl] installation. + +[para] If that is missing follow the instructions on [term {How To Install CriTcl}]. + +[comment {= = == === ===== ======== ============= =====================}] + +[section Basics] [include include/use/first.inc] +[vset base " Starting from the [sectref Basics]. + Edit the file [file example.tcl]. + Remove the definition of [cmd hello]. Replace it with "] +[vset rebuild { and rebuild the package.}] + +[subsection {Simple Arguments}] [include include/use/args.inc] +[subsection {Simple Results}] [include include/use/results.inc] +[subsection {Range-limited Simple Arguments}] [include include/use/args_range.inc] +[subsection {String Arguments}] [include include/use/args_str.inc] +[subsection {String Results}] [include include/use/results_str.inc] +[subsection {List Arguments}] [include include/use/args_list.inc] +[subsection {Constrained List Arguments}] [include include/use/args_list_constrained.inc] +[subsection {Raw Tcl_Obj* Arguments}] [include include/use/args_obj.inc] +[subsection {Raw Tcl_Obj* Results}] [include include/use/results_obj.inc] +[subsection {Errors & Messages}] [include include/use/errors.inc] +[subsection {Tcl_Interp* Access}] [include include/use/interp.inc] +[subsection {Binary Data Arguments}] [include include/use/args_binary.inc] +[subsection {Constant Binary Data Results}] [include include/use/results_const_binary.inc] +[subsection {Tcl Runtime Version}] [include include/use/runtime.inc] +[subsection {Additional Tcl Code}] [include include/use/tcl_sources.inc] +[subsection {Debugging Support}] [include include/use/debugging.inc] +[subsection {Install The Package}] [include include/use/build_install.inc] + +[section {Using External Libraries}] [include include/use/second.inc] +[vset ebase " Starting from the [sectref {Using External Libraries} {base wrapper}]. + Edit the file [file example.tcl]. "] + +[subsection {Default Values For Arguments}] [include include/use/args_default.inc] +[subsection {Custom Argument Validation}] [include include/use/args_check.inc] +[subsection {Separating Local C Sources}] [include include/use/csources.inc] +[subsection {Very Simple Results}] [include include/use/cconst.inc] +[subsection {Structure Arguments}] [include include/use/args_structure.inc] +[subsection {Structure Results}] [include include/use/results_structure.inc] +[subsection {Structure Types}] [include include/use/objtype_structure.inc] +[subsection {Large Structures}] [include include/use/objtype_large.inc] +[subsection {External Structures}] [include include/use/external_struct.inc] +[subsection {External Enumerations}] [include include/use/external_enum.inc] +[subsection {External Bitsets/Bitmaps/Flags}] [include include/use/external_bitmap.inc] +[subsection {Non-standard header/library locations}] [include include/use/locations.inc] +[subsection {Non-standard compile/link configuration}] [include include/use/flags.inc] +[subsection {Querying the compilation environment}] [include include/use/env_query.inc] +[subsection {Shared C Code}] [include include/use/csources_ii.inc] + +[section Various] +[subsection {Author, License, Description, Keywords}] [include include/use/meta.inc] +[subsection {Get Critcl Application Help}] [include include/use/build_help.inc] +[subsection {Supported Targets & Configurations}] [include include/use/build_targets.inc] +[subsection {Building A Package}] [include include/use/build_package.inc] +[subsection {Building A Package For Debugging}] [include include/use/build_package_debug.inc] + +[comment { + [section {-- topics to do --}] + + [list_begin itemized] + [item] 'args' handling + [item] void and ok results (no results, full custom results) + [item] channels arguments, results ? + [item] demo: callbacks + [item] demo: iassoc + [item] demo: string pool + [item] demo: assertions --> cutil + [item] demo: memory utilities -/ + [item] demo: tracing utilities / + [item] + [list_end] + + [section {-- topics ignored for now as advanced, niche, without example, superceded --}] + + [list_begin itemized] + [item] cdefines - no - better done with emap/bitmap + [item] ccommand - no - no real example available. advanced + [item] tk - no - widgets - no example available. advanced + [item] fallback to tcl if C not available for platform - niche + [item] cross compilation - need external support for that how to + [item] custom config - no - advanced + [item] prefill result cache - niche + [list_end] +}] + +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_iassoc.man b/src/vfs/critcl.vfs/doc/critcl_iassoc.man new file mode 100644 index 00000000..86e0464d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_iassoc.man @@ -0,0 +1,129 @@ +[vset VERSION 1.2] +[comment {-*- tcl -*- doctools manpage}] +[manpage_begin critcl::iassoc n [vset VERSION]] +[include include/module2.inc] +[keywords singleton {Tcl Interp Association}] +[titledesc {CriTcl - Code Gen - Tcl Interp Associations}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::iassoc [opt [vset VERSION]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the [package critcl::iassoc] +package. This package provides convenience commands for advanced +functionality built on top of the critcl core. + +[para] With it a user wishing to associate some data with a Tcl +interpreter via Tcl's [fun Tcl_(Get|Set)AssocData()] APIs can now +concentrate on the data itself, while all the necessary boilerplate +around it is managed by this package. + +[para] Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code. + +[para] This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] + +[list_begin definitions] +[call [cmd ::critcl::iassoc::def] [arg name] [arg arguments] [arg struct] \ + [arg constructor] [arg destructor]] + +This command defines a C function with the given [arg name] which +provides access to a structure associated with a Tcl interpreter. + +[para] The C code code fragment [arg struct] defines the elements of +said structure, whereas the fragments [arg constructor] and +[arg destructor] are C code blocks executed to initialize and release +any dynamically allocated parts of this structure, when needed. Note +that the structure itself is managed by the system. + +[para] The new function takes a [const Tcl_Interp*] pointer refering +to the interpreter whose structure we wish to obtain as the first +argument, plus the specified [arg arguments] and returns a pointer to +the associated structure, of type "[arg name]_data" (see below). + +[para] The [arg arguments] are a dictionary-like list of C types and +identifiers specifying additional arguments for the accessor function, +and, indirectly, the [arg constructor] C code block. This is useful +for the supplication of initialization values, or the return of more +complex error information in case of a construction failure. + +[para] The C types associated with the structure are derived from +[arg name], with "[arg name]_data__" the type of the structure itself, +and "[arg name]_data" representing a pointer to the structure. + +The C code blocks can rely on the following C environments: +[list_begin definitions] +[def [arg constructor]] +[list_begin definitions] + +[def [var data]] Pointer to the structure (type: [arg name]_data) to +initialize. + +[def [var interp]] Pointer to the Tcl interpreter (type: Tcl_Interp*) +the new structure will be associated with. + +[def error] A C code label the constructor can jump to should it have +to signal a construction failure. It is the responsibility of the +constructor to release any fields already initialized before jumping +to this label. + +[def ...] The names of the constructor arguments specified with +[arg arguments]. +[list_end] +[def [arg destructor]] +[list_begin definitions] +[def [var data]] Pointer to the structure being released. +[def [var interp]] Pointer to the Tcl interpreter the structure +belonged to. +[list_end] +[list_end] +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Example] + +The example shown below is the specification of a simple interpreter-associated +counter. The full example, with meta data and other incidentals, can be found +in the directory [file examples/queue] of the critcl source +distribution/repository. + +[example { +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::iassoc +} + +critcl::iassoc::def icounter {} { + int counter; /* The counter variable */ +} { + data->counter = 0; +} { + /* Nothing to release */ +} + +critcl::ccode { + ... function (...) + { + /* Access to the data ... */ + icounter_data D = icounter (interp /* ... any declared arguments, here, none */); + ... D->counter ... + } +} +# or, of course, 'cproc's, 'ccommand's etc. + +package provide icounter 1 +}] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_license.man b/src/vfs/critcl.vfs/doc/critcl_license.man new file mode 100644 index 00000000..08fd6810 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_license.man @@ -0,0 +1,48 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[manpage_begin critcl_license n 1] +[include include/module.inc] +[titledesc {The CriTcl License}] +[description] +[include include/welcome.inc] + +[para] All packages are under the BSD license. + +[section License] + +[para] This software is copyrighted by Andreas Kupries and other parties. The following +terms apply to all files associated with the software unless explicitly disclaimed in +individual files. + +[para] 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. + +[para] 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. + +[para] 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. + +[para] 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-7014 (b) (3) +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 include/feedback.inc] +[manpage_end] + diff --git a/src/vfs/critcl.vfs/doc/critcl_literals.man b/src/vfs/critcl.vfs/doc/critcl_literals.man new file mode 100644 index 00000000..463224f6 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_literals.man @@ -0,0 +1,166 @@ +[comment {-*- tcl -*- doctools manpage}] +[vset literal_version 1.4] +[manpage_begin critcl::literals n [vset literal_version]] +[include include/module2.inc] +[keywords singleton {Tcl Interp Association}] +[keywords {string pool} {literal pool}] +[titledesc {CriTcl - Code Gen - Constant string pools}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::literals [opt [vset literal_version]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the +[package critcl::literals] package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package [package critcl::iassoc]. + +[para] Many packages will have a fixed set of string constants +occuring in one or places. Most of them will be coded to create a new +string [type Tcl_Obj*] from a C [type char*] every time the constant +is needed, as this is easy to to, despite the inherent waste of +memory. + +[para] This package was written to make declaration and management of +string pools which do not waste memory as easy as the wasteful +solution, hiding all attendant complexity from the user. + +[para] Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code. + +[para] This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] + +[list_begin definitions] +[call [cmd ::critcl::literals::def] [arg name] [arg definition] [opt [arg mode]]] + +This command defines a C function with the given [arg name] which +provides access to a pool of constant strings with a Tcl interpreter. + +[para] The [arg definition] dictionary provides the mapping from the +C-level symbolic names to the string themselves. + +[para] +The [arg mode]-list configures the output somewhat. +The three allowed modes are [const c], [const +list] and [const tcl]. +All modes can be used together. +The default mode is [const tcl]. +Using mode [const +list] implies [const tcl] as well. + +[para] For mode [const tcl] the new function has two arguments, a +[type Tcl_Interp*] pointer refering to the interpreter holding the +string pool, and a code of type "[arg name]_names" (see below), the +symbolic name of the literal to return. The result of the function is +a [type Tcl_Obj*] pointer to the requested string constant. + +[para] For mode [const c] the new function has one argument, a code of +type "[arg name]_names" (see below), the symbolic name of the literal +to return. The result of the function is a [type {const char*}] +pointer to the requested string constant. + +[para] For mode [const +list] all of [const tcl] applies, plus an +additional function is generated which takes three arguments, in +order, a [type Tcl_Interp*] pointer refering to the interpreter +holding the string pool, an [type int] holding the size of the last +argument, and an array of type "[arg name]_names" holding the codes +(see below), the symbolic names of the literals to return. The result +of the function is a [type Tcl_Obj*] pointer to a Tcl list holding the +requested string constants. + +[para] The underlying string pool is automatically initialized on +first access, and finalized on interpreter destruction. + +[para] The package generates multiple things (declarations and +definitions) with names derived from [arg name], which has to be a +proper C identifier. + +[list_begin definitions] +[def [arg name]] +The mode [const tcl] function providing access to the string pool. + +Its signature is +[para][example_begin] +Tcl_Obj* [arg name] (Tcl_Interp* interp, [arg name]_names literal); +[example_end] + +[def [arg name]_list] +The mode [const +list] function providing multi-access to the string pool. + +Its signature is +[para][example_begin] +Tcl_Obj* [arg name]_list (Tcl_Interp* interp, int c, [arg name]_names* literal); +[example_end] + +[def [arg name]_cstr] +The mode [const c] function providing access to the string pool. + +Its signature is +[para][example_begin] +const char* [arg name]_cstr ([arg name]_names literal); +[example_end] + +[def [arg name]_names] +A C enumeration type containing the symbolic names of the strings +provided by the pool. + +[def [arg name].h] +A header file containing the declarations for the accessor functions +and the enumeration type, for use by other parts of the system, if +necessary. + +[para] The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files ([cmd csources]). + +[def [arg name]] +[emph {New in version 1.1}]: + +For mode [const tcl] the command registers a new result-type for +[cmd critcl::cproc] with critcl, which takes an integer result from +the function and converts it to the equivalent string in the pool for +the script. + +[list_end] +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[section Example] + +The example shown below is the specification of the string pool pulled +from the draft work on a Tcl binding to Linux's inotify APIs. + +[example { +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::literals +} + +critcl::literals::def tcl_inotify_strings { + w_create "create" + w_directory "directory" + w_events "events" + w_file "file" + w_handler "handler" + w_remove "remove" +} {c tcl} + +# Declarations: tcl_inotify_strings.h +# Type: tcl_inotify_strings_names +# Accessor: Tcl_Obj* tcl_inotify_strings (Tcl_Interp* interp, +# tcl_inotify_strings_names literal); +# Accessor: const char* tcl_inotify_strings_cstr (tcl_inotify_strings_names literal); +# ResultType: tcl_inotify_strings +}] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_package.man b/src/vfs/critcl.vfs/doc/critcl_package.man new file mode 100644 index 00000000..282a09c2 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_package.man @@ -0,0 +1,47 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include pkg_version.inc] +[manpage_begin critcl_package n [vset VERSION]] +[include include/module.inc] +[titledesc {CriTcl Package Reference}] +[require Tcl 8.6] +[require critcl [opt [vset VERSION]]] +[require platform [opt 1.0.2]] +[require md5 [opt 2]] +[description] +[para] +[include include/welcome.inc] +[para] + +The [package critcl] package is the core of the system. For an overview of the +complete system, see [manpage {Introduction To CriTcl}]. For the usage of the +standalone [cmd critcl] program, see [manpage {CriTcl Application}]. + +This core package maybe be used to embed C code into Tcl scripts. It also +provides access to the internals that other parts of the core use and which +are of interest to those wishing to understand the internal workings of the +core and of the API it provides to the [manpage {CriTcl Application}]. These +advanced sections are marked as such so that those simply wishing to use the +package can skip them. + + +[para] + +This package resides in the Core Package Layer of CriTcl. + +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] + +[section API] [include include/api.inc] +[section {Concepts}] [include include/concepts.inc] + +[comment {= = == === ===== ======== ============= =====================}] + +[section Examples] + +See section "Embedding C" in [manpage {Using CriTcl}]. + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_tcl9.man b/src/vfs/critcl.vfs/doc/critcl_tcl9.man new file mode 100644 index 00000000..7dd747f7 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_tcl9.man @@ -0,0 +1,187 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}] +[comment {quadrant: reference}] +[include pkg_version.inc] +[manpage_begin critcl_tcl9 n [vset VERSION]] +[include include/module.inc] +[titledesc {How To Adapt Critcl Packages for Tcl 9}] +[description] +[para] +[include include/welcome.inc] +[para] + +This guide contains notes and actions to take by writers of [vset critcl]-based +packages to make their code workable for both Tcl 8.6 and 9. + +[comment {= = == === ===== ======== ============= =====================}] + +[list_begin enumerated] + +[enum] Generally, if there is no interest in moving to Tcl 9, i.e. Tcl 8.[lb]456[rb] + are the only supported runtimes, then just keep using [vset critcl] [const 3.2]. + +[para] The remainder of this document can be ignored. + +[enum] Use [vset critcl] version [vset VERSION] [strong {if, and only if}] + Tcl 9 support is wanted. + +[para] With some work this will then also provide backward compatibility with Tcl 8.6. + +[enum] Header [file tcl.h] + +[para] Replace any inclusion of Tcl's public [file tcl.h] header file in the package's + C code with the inclusion of [vset critcl]'s new header file [file tclpre9compat.h]. + +[para] This includes [file tcl.h] and further provides a set of compatibility definitions + which make supporting both Tcl 8.6 and Tcl 9 in a single code base easier. + +[para] The following notes assume that this compatibility layer is in place. + +[enum] [cmd critcl::tcl] + +[para] Before [vset critcl] [vset VERSION] a single default ([const 8.4]) was used for + the minimum Tcl version, to be overriden by an explicit [cmd critcl::tcl] in the + package code. + +[para] Now the default is dynamic, based on the [strong runtime] version, i.e. + [cmd {package provide Tcl}], [vset critcl] is run with/on. + +[para] When running on Tcl 9 the new default is version [const 9], and [const 8.6] else. + [strong Note] how this other default was bumped up from [const 8.4]. + +[para] As a consequence it is possible to + +[list_begin enumerated] + +[enum] Support just Tcl 8.4+, 8.5+, by having an explicit [cmd {critcl::tcl 8.x}] in + the package code. + +[para] [strong {Remember however}], it is better to simply stick with + [vset critcl] [const 3.2] for this. + +[enum] Support just Tcl 9 by having an explicit [cmd {critcl::tcl 9}] in the package code. + +[enum] Support both Tcl 8.6 and Tcl 9 (but not 8.4/8.5) by leaving [cmd critcl::tcl] out of the code + and using the proper [syscmd tclsh] version to run [vset critcl] with. +[list_end] + +[enum] Code checking + +[para] [vset critcl] [vset VERSION] comes with a very basic set of code checks pointing + out places where compatibility might or will be an issue. + +[para] The implementation checks all inlined C code declared by [cmd critcl::ccode], + [cmd critcl::ccommand], [cmd critcl::cproc] (and related/derived commands), as well + as the C companion files declared with [cmd critcl::csources]. + +[para] It is very basic because it simply greps the code line by line for a number + of patterns and reports on their presence. The C code is not fully parsed. + The check can and will report pattern found in C code comments, for example. + +[para] The main patterns deal with functions affected by the change to [type Tcl_Size], + the removal of old-style interpreter state handling, and command creation. + +[para] A warning message is printed for all detections. + +[para] This is disabled for the [const Tcl_Size]-related pattern if the line also matches + the pattern [const {*OK tcl9*}]. + +[para] In this way all places in the code already handled can be marked and excluded + from the warnings. + +[list_begin enumerated] + +[enum] Interpreter State handling + +[para] Tcl 9 removed the type [type Tcl_SavedResult] and its associated functions + [fun Tcl_SaveResult], [fun Tcl_RestoreResult], and [fun Tcl_DiscardResult]. + +[para] When a package uses this type and the related functions a rewrite is necessary. + +[para] With Tcl 9 use of type [type Tcl_InterpState] and its functions + [fun Tcl_SaveInterpState], [fun Tcl_RestoreInterpState], and + [fun Tcl_DiscardInterpState] is now required. + +[para] As these were introduced with Tcl 8.5 the rewrite gives us compatibility with + Tcl 8.6 for free. + +[enum] [type Tcl_Size] + +[para] One of the main changes introduced with Tcl 9 is the breaking of the 2G barrier + for the number of bytes in a string, elements in a list, etc. + + In a lot of interfaces [type int] was replaced with [type Tcl_Size], which is + effectively [type ptrdiff_t] behind the scenes. + +[para] The [file tclpre9compat.h] header mentioned above provides a suitable definition + of [type Tcl_Size] for [const 8.6], i.e. maps it to [type int]. + + This enables the package code to use [type Tcl_Size] everywhere and still have it + work for both Tcl 8.6 and 9. + +[para] It is of course necessary to rewrite the package code to use [type Tcl_Size]. + +[para] The checker reports all lines in the C code using a function whose signature + was changed to use [type Tcl_Size] over [type int]. + +[para] Note that it is necessary to manually check the package code for places where + a [const %d] text formatting specification should be replaced with + [const TCL_SIZE_FMT]. + +[para] I.e. all places where [type Tcl_Size] values are formatted with [fun printf]-style + functions a formatting string [example {"... %d ..."}] has to be replaced with + [example {"... " TCL_SIZE_FMT " ..."}] + +[para] The macro [cmd TCL_SIZE_FMT] is defined by Critcl's compatibility layer, as an + extension of the [cmd TCL_SIZE_MODIFIER] macro which only contains the + formatting modifier to insert into a plain [const %d] to handle [type Tcl_Size] + values. + +[para] [strong Note] how the original formatting string is split into multiple strings. + The C compiler will fuse these back together into a single string. + +[enum] Command creation. + +[para] This is technically a part of the [type Tcl_Size] changes. + +[para] All places using [fun Tcl_CreateObjCommand] have to be rewritten to use + [fun Tcl_CreateObjCommand2] instead, and the registered command functions + to use [type Tcl_Size] for their [arg objc] argument. + +[para] The [file tclpre9compat.h] header maps this back to the old function + when compilation is done against Tcl 8.6. + +[para] [vset critcl] does this itself for the commands created via [cmd critcl::ccommand], + [cmd critcl::cproc], and derived places ([package critcl::class]). + +[enum] TIP 494. This TIP adds three semantic constants wrapping [const -1] to Tcl 9 to + make the meaning of code clearer. As part of this it also casts the constant to the + proper type. They are: + +[list_begin itemized] +[item] [const TCL_IO_FAILURE] +[item] [const TCL_AUTO_LENGTH] +[item] [const TCL_INDEX_NONE] +[list_end] + +[para] Critcl's compatibility layer provides the same constants to Tcl 8.6. + +[para] Critcl's new checker highlights places where [const TCL_AUTO_LENGTH] is suitable. + +[para] Doing this for the other two constants looks to require deeper and proper parsing + of C code, which the checker does not do. + +[list_end] +[list_end] + +[section {Additional References}] +[list_begin enumerated] +[enum] [uri https://wiki.tcl-lang.org/page/Porting+extensions+to+Tcl+9] +[enum] [uri https://wiki.tcl-lang.org/page/Tcl+9+functions+using+Tcl%5FSize] +[enum] [uri https://core.tcl-lang.org/tcl/wiki?name=Migrating%20scripts%20to%20Tcl%209] +[enum] [uri https://core.tcl-lang.org/tcl/wiki?name=Migrating%20C%20extensions%20to%20Tcl%209] +[list_end] + + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/critcl_util.man b/src/vfs/critcl.vfs/doc/critcl_util.man new file mode 100644 index 00000000..4ed71624 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/critcl_util.man @@ -0,0 +1,87 @@ +[comment {-*- tcl -*- doctools manpage}] +[vset version 1.2] +[manpage_begin critcl::util n [vset version]] +[include include/module2.inc] +[titledesc {CriTcl - Utilities}] +[require Tcl 8.6] +[require critcl [opt 3.2]] +[require critcl::util [opt [vset version]]] +[description] +[para] +[include include/welcome.inc] +[para] + +This document is the reference manpage for the [package critcl::util] +package. This package provides convenience commands for advanced +functionality built on top of the core. + +Its intended audience are mainly developers wishing to write Tcl +packages with embedded C code. +[para] + +This package resides in the Core Package Layer of CriTcl. +[para][image arch_core][para] + +[comment {= = == === ===== ======== ============= =====================}] +[section API] + +[list_begin definitions] +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::util::checkfun] [arg name] [opt [arg label]]] + +This command checks the build-time environment for the existence of +the C function [arg name]. + +It returns [const true] on success, and [const false] otherwise. + + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::util::def] [arg path] [arg define] [opt [arg value]]] + +This command extends the specified configuration file [arg path] with a +[const \#define] directive for the named [arg define]. If the [arg value] +is not specified it will default to [const 1]. + +[para] The result of the command is an empty string. + +[para] Note that the configuration file is maintained in the [cmd critcl::cache] +directory. + + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::util::undef] [arg path] [arg define]] + +This command extends the specified configuration file [arg path] with an +[const \#undef] directive for the named [arg define]. + +[para] The result of the command is an empty string. + +[para] Note that the configuration file is maintained in the [cmd critcl::cache] +directory. + + +[comment {* * ** *** ***** ******** ************* *********************}] +[call [cmd ::critcl::util::locate] [arg label] [arg paths] [opt [arg cmd]]] + +This command checks the build-time environment for the existence of a file +in a set of possible [arg paths]. + +[para] If the option [arg cmd] prefix is specified it will be called with +the full path of a found file as its only argument to perform further checks. +A return value of [const false] will reject the path and continue the search. + +[para] The return value of the command is the found path, as listed in +[arg paths]. As a side effect the command will also print the found path, +prefixed with the [arg label], using [cmd critcl::msg]. + +[para] Failure to find the path is reported via [cmd critcl::error], and a +possible empty string as the result, if [cmd critcl::error] does not +terminate execution. + +[vset relative_path] + +[list_end] + +[comment {= = == === ===== ======== ============= =====================}] +[include include/feedback2.inc] +[manpage_end] diff --git a/src/vfs/critcl.vfs/doc/figures/arch_application.dia b/src/vfs/critcl.vfs/doc/figures/arch_application.dia new file mode 100644 index 00000000..22ea2259 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/arch_application.dia @@ -0,0 +1,4 @@ +# -*- tcl -*- tcl.tk//DSL diagram//EN//1.0 +set mark 0 +source [file join [file dirname [file normalize [info script]]] architecture.dia] +return diff --git a/src/vfs/critcl.vfs/doc/figures/arch_application.png b/src/vfs/critcl.vfs/doc/figures/arch_application.png new file mode 100644 index 00000000..2f732c83 Binary files /dev/null and b/src/vfs/critcl.vfs/doc/figures/arch_application.png differ diff --git a/src/vfs/critcl.vfs/doc/figures/arch_application.txt b/src/vfs/critcl.vfs/doc/figures/arch_application.txt new file mode 100644 index 00000000..5b455099 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/arch_application.txt @@ -0,0 +1,18 @@ +*================* +|Applications | +| critcl | +| critcl::app | +*================* + ++----------------+ +|Core Packages | +| critcl | +| critcl::util | ++----------------+ + ++----------------+ +|Support Packages| +| stubs::* | +| md5, platform | +| ... | ++----------------+ diff --git a/src/vfs/critcl.vfs/doc/figures/arch_core.dia b/src/vfs/critcl.vfs/doc/figures/arch_core.dia new file mode 100644 index 00000000..a9090b00 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/arch_core.dia @@ -0,0 +1,4 @@ +# -*- tcl -*- tcl.tk//DSL diagram//EN//1.0 +set mark 1 +source [file join [file dirname [file normalize [info script]]] architecture.dia] +return diff --git a/src/vfs/critcl.vfs/doc/figures/arch_core.png b/src/vfs/critcl.vfs/doc/figures/arch_core.png new file mode 100644 index 00000000..4ae56a7d Binary files /dev/null and b/src/vfs/critcl.vfs/doc/figures/arch_core.png differ diff --git a/src/vfs/critcl.vfs/doc/figures/arch_core.txt b/src/vfs/critcl.vfs/doc/figures/arch_core.txt new file mode 100644 index 00000000..fcd81b03 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/arch_core.txt @@ -0,0 +1,18 @@ ++----------------+ +|Applications | +| critcl | +| critcl::app | ++----------------+ + +*================* +|Core Packages | +| critcl | +| critcl::util | +*================* + ++----------------+ +|Support Packages| +| stubs::* | +| md5, platform | +| ... | ++----------------+ diff --git a/src/vfs/critcl.vfs/doc/figures/arch_support.dia b/src/vfs/critcl.vfs/doc/figures/arch_support.dia new file mode 100644 index 00000000..ac1e034c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/arch_support.dia @@ -0,0 +1,4 @@ +# -*- tcl -*- tcl.tk//DSL diagram//EN//1.0 +set mark 2 +source [file join [file dirname [file normalize [info script]]] architecture.dia] +return diff --git a/src/vfs/critcl.vfs/doc/figures/arch_support.png b/src/vfs/critcl.vfs/doc/figures/arch_support.png new file mode 100644 index 00000000..bee761f2 Binary files /dev/null and b/src/vfs/critcl.vfs/doc/figures/arch_support.png differ diff --git a/src/vfs/critcl.vfs/doc/figures/arch_support.txt b/src/vfs/critcl.vfs/doc/figures/arch_support.txt new file mode 100644 index 00000000..4d0e8458 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/arch_support.txt @@ -0,0 +1,18 @@ ++----------------+ +|Applications | +| critcl | +| critcl::app | ++----------------+ + ++----------------+ +|Core Packages | +| critcl | +| critcl::util | ++----------------+ + +*================* +|Support Packages| +| stubs::* | +| md5, platform | +| ... | +*================* diff --git a/src/vfs/critcl.vfs/doc/figures/architecture.dia b/src/vfs/critcl.vfs/doc/figures/architecture.dia new file mode 100644 index 00000000..e77d0680 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/architecture.dia @@ -0,0 +1,38 @@ +# -*- tcl -*- tcl.tk//DSL diagram//EN//1.0 +# Parser Tools Architecture Diagram + +set counter 0 +if {![info exists mark]} { set mark -1 } + +proc xbox {args} { + variable mark + variable counter + + if {$mark == $counter} { + lappend args color red stroke 2 + } + incr counter + return [uplevel 1 [list box {*}$args]] +} + +proc area {label args} { + set E [xbox fillcolor lightyellow {*}$args] + group { + text text $label with nw at [last box nw] + } + return $E +} + +down +set boxwidth [90 mm] +set movelength [5 mm] + +set A [area Applications] +move +set C [area "Core Packages"] +move +set S [area "Support Packages"] + +text at $A "critcl\ncritcl::app" +text at $C "critcl\ncritcl::util" +text at $S "stubs::*, md5, platform ..." diff --git a/src/vfs/critcl.vfs/doc/figures/architecture.png b/src/vfs/critcl.vfs/doc/figures/architecture.png new file mode 100644 index 00000000..dacfeb47 Binary files /dev/null and b/src/vfs/critcl.vfs/doc/figures/architecture.png differ diff --git a/src/vfs/critcl.vfs/doc/figures/architecture.txt b/src/vfs/critcl.vfs/doc/figures/architecture.txt new file mode 100644 index 00000000..69fdf3c6 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/figures/architecture.txt @@ -0,0 +1,18 @@ ++----------------+ +|Applications | +| critcl | +| critcl::app | ++----------------+ + ++----------------+ +|Core Packages | +| critcl | +| critcl::util | ++----------------+ + ++----------------+ +|Support Packages| +| stubs::* | +| md5, platform | +| ... | ++----------------+ diff --git a/src/vfs/critcl.vfs/doc/include/advert.inc b/src/vfs/critcl.vfs/doc/include/advert.inc new file mode 100644 index 00000000..8b61866f --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/advert.inc @@ -0,0 +1,5 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] + +[para] [vset slogan] +[para] Improve performance by rewriting the performance bottlenecks in C. +[para] Import the functionality of shared libraries into Tcl scripts. diff --git a/src/vfs/critcl.vfs/doc/include/aoptions.inc b/src/vfs/critcl.vfs/doc/include/aoptions.inc new file mode 100644 index 00000000..9c39f2bd --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/aoptions.inc @@ -0,0 +1,327 @@ + +[vset teaignored " +[para] +Ignored when generating a TEA package +(see option [option -tea] below). +"] + +[vset validated_on_build " +[para] Validated only if one of the input files for the [vset critcl_script] +actually defines and uses a custom build configuration option with that +[arg name]. +"] + + +The following options are understood: + +[list_begin options] +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -v] +[opt_def --version] + +Print the version to [const stdout] and exit. + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -I path] + +Arranges for the compiler to search [arg path] for headers. +[vset cumulative_opt] + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -L path] + +Arranges for the linker to search [arg path]. +[vset cumulative_opt] + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -cache path] + +Sets [arg path] as the directory to use as the result cache. The default is +[file ~/.critcl/], or [file ~/.critcl/.] when generating +a package. See option [option -pkg], below. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -clean] + +Arranges for all files and directories in the result cache to be deleted before +compilation begins. + +[para] Ignored when generating a package because this mode starts out with a +unique and empty result cache. See option [option -pkg], below. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -config path] + +Provides a custom configuration file. By default a configuration included in +the system core is used. + +When specified multiple times the last value is used. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -debug mode] + +Activates one of the following debugging modes: + + +[list_begin definitions] +[def [const memory]] + +Track and report memory allocations made by the Tcl core. + +[def [const symbols]] + +Compile all [file .c] files with debugging symbols. + +[def [const all]] + +Both [const memory] and [const symbols]. + +[list_end] + +[vset teaignored] + +[vset cumulative_opt] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -disable name] + +Sets the value of the custom build configuration option +[arg name] to [const false]. It is equivalent to "-with-[arg name] 0". + +[vset validated_on_build] + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -enable name] + +Sets the value of the custom build configuration option +[arg name] to [const true]. It is equivalent to "-with-[arg name] 1". + +[vset validated_on_build] + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -force] + +Forces compilation even if a shared library for the file already exists. +Unlike cleaning the cache, this is lazy in the destruction of files and only +affects relevant files. + +[para] Ignored when generating a package (see option [option -pkg], below), +which starts out with a unique and empty result cache. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -help] + +Prints a short description of command line syntax and options and then exits +the application. + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -keep] + +Causes the system to cache compiled [file .c] files. + +Also prevents the deletion of the unique result cache used by the run when +generating a package (see option [option -pkg] below), + +Intended for debugging of [cmd critcl] itself, where it may be necessary to +inspect the generated C code. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -libdir directory] + +Adds [arg directory] to the list of directories the linker searches for +libraries in (like [option -L]). With [option -pkg], generated packages are +saved in [arg directory]. + +When specified multiple times the last value is used. + +The default is [file lib], resolved relative to the current working directory. + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -includedir directory] + +Adds [arg directory] to the list of directories the compiler searches for +headers in. With [option -pkg], generated header files are saved in +[arg directory]. + +[vset cumulative_opt] + +The last value is used as the destination for generated header files. + +The default is the relative directory [file include], resolved relative to the +current working directory. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -pkg] + +Generates a package from the [vset critcl_script] files. Input files are +processed first as usual, but are then bundled into a single library, with +additional generated files to form the library into a standard Tcl package. + +[para] + +generation. If both options, i.e. [option -pkg] and [option -tea] are +specified the last one specified wins. + +[para] + +Options [option -clean] and [option -force] are ignored. [option -libdir] is +relevant in both this and [option -tea] mode. + +[para] + +[vset pkg_namerules] + + +[para] Examples: + +[example { + ... -pkg ... foo + + => Package name is: foo + => Input file is: foo.tcl +}] + +[example { + ... -pkg ... foo bar.tcl + + => Package name is: foo + => Input file is: bar.tcl +}] + +[example { + ... -pkg ... foo.tcl + + => Package name is: foo + => Input file is: foo.tcl +}] + +[example { + ... -pkg ... foo.so bar.tcl + + => Package name is: foo + => Input file is: bar.tcl +}] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -show] + +Prints the configuration of the chosen target to [const stdout] and then exits. + +Set [option -target], below. + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -showall] + +Prints the whole chosen configuration file to [const stdout] and then exits. + +See [option -config], above. + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -target name] + +Overrides the default choice of build target. + +Only the last occurrence of this option is used. + +The named target must exist in the chosen configuration file. + +Use [option -targets] (see below) to get a list of the +acceptable targets. + +Use [option -config] to select the configuration file. + +[vset teaignored] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -targets] + +Prints the list of all known targets from the chosen configuration file to +[const stdout] and then exits. + +Use [option -config] to select the configuration file. + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -tea] + +Like [option -pkg], except no binaries are generated. Creates a directory +hierarchy containing the [vset critcl_script], its companion files, and a +TEA-conformant build system with most of the needed support code, including +copies of the critcl packages. + +[para] + +If both [option -pkg] and [option -tea] are specified the last occurrence wins. + +[para] + +[option -I], [option -L], [option -clean], +[option -force], [option -cache], [option -includedir], [option -enable], +[option -disable], and [option -with-[var FOO]] are +ignored. In contrast, the option [option -libdir] is relevant in both +this and [option -pkg] mode. + +[para] [vset pkg_namerules] + +[para] Examples: + +[example { + ... -tea ... foo + + => Package name is: foo + => Input file is: foo.tcl +}] + +[example { + ... -tea ... foo bar.tcl + + => Package name is: foo + => Input file is: bar.tcl +}] + +[example { + ... -tea ... foo.tcl + + => Package name is: foo + => Input file is: foo.tcl +}] + +[example { + ... -tea ... foo.so bar.tcl + + => Package name is: foo + => Input file is: bar.tcl +}] + +[comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%] +[opt_def -with-[var name] value] + +This option sets the value of the custom build configuration option +[arg name] to [arg value]. + +[para] The information is validated only if one of the [file .critcl] +input files actually defines and uses a custom build configuration +option with that [arg name]. + +[vset teaignored] + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api.inc b/src/vfs/critcl.vfs/doc/include/api.inc new file mode 100644 index 00000000..2f9b597f --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api.inc @@ -0,0 +1,33 @@ + +A short note ahead of the documentation: Instead of repeatedly talking +about +"a Tcl script with embbedded C code", or +"a Tcl script containing CriTcl commands", +we call such a script a [vset critcl_script]. A file containing a +[vset critcl_script] usually has the extension [const .tcl] or +[const .critcl]. + +[comment { + Uncompleted docs for + + config -I ... - describe the options ... + + Undocumented commands ... + + c++command - +}] + +[subsection {Embedded C Code}] [include include/api_embedc.inc] +[subsection {Stubs Table Management}] [include include/api_stubs.inc] +[subsection {Package Meta Data}] [include include/api_meta.inc] +[subsection {Control & Interface}] [include include/api_control.inc] +[subsection {Introspection}] [include include/api_introspection.inc] +[subsection {Build Management}] [include include/api_bmgmt.inc] +[subsection {Result Cache Management}] [include include/api_rcache.inc] +[subsection {Build Configuration}] [include include/api_bconfig.inc] +[subsection {Tool API}] [include include/api_tools.inc] +[subsection {Advanced: Embedded C Code}] [include include/api_aembedc.inc] +[subsection {Custom Build Configuration}] [include include/api_cbconfig.inc] +[subsection {Advanced: Location management}] [include include/api_location.inc] +[subsection {Advanced: Diversions}] [include include/api_diversions.inc] +[subsection {Advanced: File Generation}] [include include/api_generation.inc] diff --git a/src/vfs/critcl.vfs/doc/include/api_aembedc.inc b/src/vfs/critcl.vfs/doc/include/api_aembedc.inc new file mode 100644 index 00000000..9e212cc7 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_aembedc.inc @@ -0,0 +1,61 @@ + +For advanced use, the following commands used by [cmd critcl::cproc] itself are +exposed. + +[vset given_cmd "Given an argument declaration as documented for [cmd critcl::cproc],"] + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argnames] [arg arguments]] + +[vset given_cmd] returns a list of the corresponding user-visible names. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argcnames] [arg arguments]] + +[vset given_cmd] returns a list of the corresponding C variable names for the +user-visible names. The names returned here match the names used in the +declarations and code returned by [cmd ::critcl::argvardecls] and +[cmd ::critcl::argconversion]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argcsignature] [arg arguments]] + +[vset given_cmd] returns a list of the corresponding C parameter declarations. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argvardecls] [arg arguments]] + +[vset given_cmd] returns a list of the corresponding C variable declarations. +The names used in these declarations match the names returned by +[cmd ::critcl::argcnames]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argconversion] [arg arguments] [opt [arg n]]] + +[vset given_cmd] returns a list of C code fragments converting the user visible +arguments found in the declaration from Tcl_Obj* to C types. The names used in +these statements match the names returned by [cmd ::critcl::argcnames]. + +[para] The generated code assumes that the procedure arguments start +at index [arg n] of the [var objv] array. The default is [const 1]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argoptional] [arg arguments]] + +[vset given_cmd] returns a list of boolean values indicating which arguments +are optional ([const true]), and which are not ([const false]). + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argdefaults] [arg arguments]] + +[vset given_cmd] returns a list containing the default values for all optional +arguments. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argsupport] [arg arguments]] + +[vset given_cmd] returns a list of C code fragments needed to define the +necessary supporting types. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_bconfig.inc b/src/vfs/critcl.vfs/doc/include/api_bconfig.inc new file mode 100644 index 00000000..46d7a88d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_bconfig.inc @@ -0,0 +1,57 @@ + +The following commands manage the build configuration, i.e. the per-platform +information about compilers, linkers, and their commandline options. + +[vset not_needed_for_critcl_script] + +[list_begin definitions] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::readconfig] [arg path]] + +Reads the build configuration file at [arg path] and configures the package +using the information for the target platform. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::showconfig] [opt [arg chan]]] + +Converts the active build configuration into a human-readable string and +returns it, or if [arg chan] is provided prints the result to that channel. + +[comment { + As a package it would be IMHO better to have these command only + return the necessary internal data, and have the application + higher up do the formatting. +}] + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::showallconfig] [opt [arg chan]]] + +Converts the set of all known build configurations from the currently active +build configuration file last set with [cmd critcl::readconfig] into a string +and returns it, or if [arg chan] is provided, prints it to that channel. + +[comment { + As a package it would be IMHO better to have these command only + return the necessary internal data, and have the application + higher up do the formatting. +}] + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::chooseconfig] [arg target] [opt [arg nomatcherr]]] + +Matches [arg target] against all known targets, returning a list containing +all the matching ones. This search is first done on an exact basis, and then +via glob matching. If no known target matches the argument the default is to +return an empty list. However, if the boolean [arg nomatcherr] is specified and +set an error is thrown using [cmd critcl::error] instead. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::setconfig] [arg target]] + +Configures the package to use the settings of [arg target]. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_bmgmt.inc b/src/vfs/critcl.vfs/doc/include/api_bmgmt.inc new file mode 100644 index 00000000..3a973bc2 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_bmgmt.inc @@ -0,0 +1,79 @@ + +The following command manages global settings, i.e. configuration options which +are independent of any [vset critcl_script]. + +[para] This command should not be needed to write a [vset critcl_script]. It is +a management command which is only useful to the [manpage {CriTcl Application}] +or similar tools. + +[list_begin definitions] + +[call [cmd ::critcl::config] [arg option] [opt [arg val]]] + +Sets and returns the following global configuration options: + +[list_begin options] +[opt_def force bool] + +When [const false] (the default), the C files are not built if there is a +cached shared library. + +[opt_def lines bool] + +When [const true] (the default), #line directives are embedded into the +generated C code. + +[include rq_cline.inc] + +[para] Developers of higher-level packages generating their own C +code, either directly or indirectly through critcl, should +also read section [sectref {Advanced: Location management}] to see how +critcl helps them in generating their directives. + +Examples of such packages come with critcl itself. See +[package critcl::iassoc] and [package critcl::class]. + +[opt_def trace bool] + +When [const false] (the default), no code tracing the entry and exit of +CriTcl-backed commands in the [vset critcl_script] is inserted. Insertion of +such code implicitly activates the tracing facility in general. See +[package critcl::cutil]. + +[opt_def I path] + +A single global include path to use for all files. Not set by default. + +[opt_def combine enum] +[list_begin definitions] +[def "[const dynamic] (the default)"] + +Object files have the suffix [const _pic]. + +[def [const static]] + +Object files have the suffix [const _stub]. + +[def [const standalone]] + +Object files have no suffix, and the generated C files are compiled +without using Tcl/Tk stubs. The result are object files usable for +static linking into a [term {big shell}]. + +[list_end] + + +[opt_def language string] +[opt_def keepsrc bool] + +When [const false] (the default), the generated [file .c] +files are deleted after the [file .o] files have been built. + + +[opt_def outdir directory] + +The directory where to place a generated shared library. By default, it is +placed into the [sectref {Result Cache}]. + +[list_end] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_cbconfig.inc b/src/vfs/critcl.vfs/doc/include/api_cbconfig.inc new file mode 100644 index 00000000..5a828651 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_cbconfig.inc @@ -0,0 +1,66 @@ + +This package provides one command for the management of +package-specific, i.e. developer-specified custom build configuration +options. + +[list_begin definitions] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::userconfig] [method define] [arg name] [arg description] [arg type] [opt [arg default]]] + +This command defines custom build configuration option, with +[arg description], [arg type] and optional [arg default] value. + +[para] The type can be either [const bool], or a list of values. + +[list_begin enumerated] +[enum] For [const bool] the default value, if specified, must be a +boolean. If it is not specified it defaults to [const true]. + +[enum] For a list of values the default value, if specified, must be a +value found in this list. If it is not specified it defaults to the +first value of the list. + +[list_end] + +[para] The [arg description] serves as in-code documentation of the +meaning of the option and is otherwise ignored. When generating a TEA +wrapper the description is used for the [syscmd configure] option +derived from the option declared by the command. + +[para] A boolean option [var FOO] are translated into a pair of +configure options, [option --enable-[var FOO]] and +[option --disable-[var FOO]], whereas an option whose [arg type] is a +list of values is translated into a single configure option +[option --with-[var FOO]]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::userconfig] [method query] [arg name]] + +This command queries the database of custom build configuration option +for the current [file .critcl] file and returns the chosen value. +This may be the default if no value was set via +[cmd {::critcl::userconfig set}]. + +[para] It is at this point that definitions and set values are brought +together, with the latter validated against the definition. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::userconfig] [method set] [arg name] [arg value]] + +This command is for use by a tool, like the [syscmd critcl] application, +to specify values for custom build configuration options. + +[para] At the time this command is used only the association between +option name and value is recorded, and nothing else is done. This +behaviour is necessary as the system may not know if an option of the +specified name exists when the command is invoked, nor its type. + +[para] Any and all validation is defered to when the value of an +option is asked for via [cmd {::critcl::userconfig query}]. + +[para] This means that it is possible to set values for any option we +like, and the value will take effect only if such an option is both +defined and used later on. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_control.inc b/src/vfs/critcl.vfs/doc/include/api_control.inc new file mode 100644 index 00000000..812658f3 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_control.inc @@ -0,0 +1,161 @@ + +These commands control the details of compilation and linking a +[vset critcl_script]. The information is used only to compile/link the +object for the [vset critcl_script]. For example, information for +[file FOO.tcl] is kept separate from information for [file BAR.tcl]. + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cheaders] [opt [arg arg]...]] + +Provides additional header locations. + +[para] Each argument is a glob pattern. If an argument begins with [const -] +it is an argument to the compiler. Otherwise the parent directory of each +matching path is a directory to be searched for header files. Returns an +error if a pattern matches no files. + +[vset relative_pattern] + +[para] [const {#include}] lines are not automatically generated for matching +header files. Use [cmd critcl::include] or [cmd critcl::ccode] as necessary to +add them. + +[para] [vset cumulative] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::csources] [opt [arg {glob pattern}]...]] + +Matching paths become inputs to the compilation of the current object +along with the sources for the current [vset critcl_script]. Returns an +error if no paths match a pattern. + +[vset relative_pattern] + +[para] [vset cumulative] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::clibraries] [opt [arg {glob pattern}]...]] + +provides the link step with additional libraries and library locations. + +A [arg {glob pattern}] that begins with [const -] is added as an argument to +the linker. Otherwise matching files are linked into the shared library. +Returns an error if no paths match a pattern. + +[vset relative_pattern] + +[para] [vset cumulative] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::source] [arg {glob pattern}]] + +Evaluates as scripts the files matching each [arg {glob pattern}]. Returns an +error if there are no matching files. + +[vset relative_pattern] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::tsources] [arg {glob pattern}]...] + +Provides the information about additional Tcl script files to source when the +shared library is loaded. + +[para] Matching paths are made available to the generated shared library when +it is loaded for the current [vset critcl_script]. Returns an error if a +pattern matches no files. + +[vset relative_pattern] + +[para] [vset cumulative] + +[para] After the shared library has been loaded, the declared files are sourced +in the same order that they were provided as arguments. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::owns] [arg {glob pattern}]...] + +Ignored in "compile and run" and "generate package" modes. + +In "generate TEA" mode each file matching a [arg {glob pattern}] is a file to +be included in the TEA extension but that could not be ascertained as such from +previous commands like [cmd critcl::csources] and [cmd critcl::tsources], +either because of they were specified dynamically or because they were directly +sourced. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cflags] [opt [arg arg]...]] + +[para] Each [arg arg] is an argument to the compiler. + +[para] [vset cumulative] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::ldflags] [opt [arg arg]...]] + +[para] Each [arg arg] is an argument to the linker. + +[para] [vset cumulative] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::framework] [opt [arg arg]...]] + +Each [arg arg] is the name of a framework to link on MacOS X. This command is +ignored if OS X is not the target so that frameworks can be specified +unconditionally. + +[para] [vset cumulative] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::tcl] [arg version]] + +Specifies the minimum version of the Tcl runtime +to compile and link the package for. The default is [const 8.4]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::tk]] + +Arranges to include the Tk headers and link to the Tk stubs. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::preload] [arg lib]...] + +Arranges for the external shared library [arg lib] to be loaded +before the shared library for the [vset critcl_script] is loaded. + +[para] [vset cumulative] + +[para][include preload_search.inc] + +[comment { + XXX preload - compile & run - will it work ? +}] + +For developers who want to understand or modify the internals of the +[package critcl] package, [sectref {Preloading functionality}] explains how +preloading is implemented. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::debug] [arg area]...] + +Specifies what debugging features to activate. Internally each area is translated into +area-specific flags for the compiler which are then handed over to +[cmd critcl::cflags]. + +[list_begin definitions] +[def [const memory]] + +Specifies Tcl memory debugging. + +[def [const symbols]] + +Specifies compilation and linking with debugging symbols for use by a debugger +or other tool. + +[def [const all]] + +Specifies all available debugging. + +[list_end] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_diversions.inc b/src/vfs/critcl.vfs/doc/include/api_diversions.inc new file mode 100644 index 00000000..c12ef0f9 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_diversions.inc @@ -0,0 +1,53 @@ + +Diversions are for higher-level packages generating their own C code, +to make their use of critcl's commands generating +[sectref {Embedded C Code}] easier. + +[para] These commands normally generate all of their C code for the +current [file .critcl] file, which may not be what is wanted by a +higher-level package. + +[para] With a diversion the generator output can be redirected into +memory and from there on then handled and processed as the caller +desires before it is committed to an actual [file .c] file. + +[para] An example of such a package comes with critcl itself, see the +implementation of package [package critcl::class]. + +[para] To help such developers three commands are provided to manage +diversions and the collection of C code in memory. These are: + +[list_begin definitions] +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::collect_begin]] + +This command starts the diversion of C code collection into memory. + +[para] The result of the command is the empty string. + +[para] Multiple calls are allowed, with each call opening a new +nesting level of diversion. + + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::collect_end]] + +This command end the diversion of C code collection into memory and +returns the collected C code. + +[para] If multiple levels of diversion are open the call only closes +and returns the data from the last level. + +[para] The command will throw an error if no diversion is active, +indicating a mismatch in the pairing of [cmd collect_begin] and +[cmd collect_end]. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::collect] [arg script]] + +This is a convenience command which runs the [arg script] under +diversion and returns the collected C code, ensuring the correct +pairing of [cmd collect_begin] and [cmd collect_end]. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_embedc.inc b/src/vfs/critcl.vfs/doc/include/api_embedc.inc new file mode 100644 index 00000000..b77c412d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_embedc.inc @@ -0,0 +1,234 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] + +The following commands append C code fragments to the current module. Fragments +appear in the module in the order they are appended, so the earlier fragments +(variables, functions, macros, etc.) are visible to later fragments. + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::ccode] [arg fragment]] + +Appends the C code in [arg fragment] to the current module and returns the +empty string. + +See [sectref {Runtime Behaviour}]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::ccommand] [arg tclname] [arg cname]] + +As documented below, except that [arg cname] is the name of a C function +that already exists. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::ccommand] [arg tclname] [arg arguments] [arg body] [ + opt "[arg option] [arg value]..."]] + +Appends the code to create a Tcl command named [arg tclname] and a +corresponding C function whose body is [arg body] and which behaves as +documented for Tcl's own +[uri https://www.tcl-lang.org/man/tcl/TclLib/CrtObjCmd.htm Tcl_CreateObjCommand]. + +[para] +[arg aguments] is a list of zero to four names for the standard arguments +[const clientdata], [const interp], [const objc], and [const objv]. The +standard default names are used in place of any missing names. + +This is a more low-level way than [cmd critcl::cproc] to define a command, as +processing of the items in [const objv] is left to the author, affording +complete control over the handling of the arguments to the command. + +See section [sectref {Runtime Behaviour}]. + +[para] +Returns the empty string. + +[para] +Each [arg option] may be one of: + +[list_begin options] +[opt_def -clientdata [arg c-expression]] + +Provides the client data for the new command. [const NULL] by default. + +[opt_def -delproc [arg c-expression]] + +Provides a function pointer of type [uri \ + https://www.tcl-lang.org/man/tcl/TclLib/CrtObjCmd.htm \ + Tcl_CmdDeleteProc +] as the deletion function for the new command. [const NULL] by default. + + +[include api_embedc_cnameoption.inc] + +[list_end] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cdata] [arg tclname] [arg data]] + +Appends the code to create a new Tcl command named [arg tclname] which returns +[arg data] as a [const ByteArray] result. + +[para] +Returns the empty string. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cconst] [arg tclname] [arg resulttype] [arg value]] + +Appends the code to create a new Tcl command named [arg tclname] which returns +the constant [arg value] having the Tcl type [arg resulttype]. [arg value] can +be a C macro or a function [emph call] (including the parentheses) to any +visible C function that does not take arguments. + +Unlike [cmd critcl::cdata], [arg resulttype] can be any type known to +[cmd critcl::cproc]. + +Its semantics are equivalent to: + +[example { + cproc $tclname {} $resulttype "return $value ;" +}] + +[para] This is more efficient than [cmd critcl::cproc] since there is no +C function generated. + +[para] +Returns the empty string. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cdefines] [arg {list of glob patterns}] [opt [arg namespace]]] + +Arranges for [term {C enum}] and [term #define] values that match one of the +patterns in [term {glob patterns}] to be created in the namespace +[arg namespace], each variable having the same as the corresponding C item. +The default namespace is the global namespace. A pattern that matches nothing +is ignored. + +[para] The Tcl variables are created when the module is compiled, using the +preprocessor in order to properly find all matching C definitions. + +[para] +Produces no C code. The desired C definitions must already exist. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cproc] [arg name] [arg arguments] [arg resulttype] [arg body] \ + [opt "[arg option] [arg value]..."]] + +Appends a function having [arg body] as its body, another shim function to +perform the needed conversions, and the code to create a corresponding Tcl +command named [arg tclname]. Unlike [cmd critcl::ccommand] the arguments and +result are typed, and CriTcl generates the code to convert between Tcl_Obj +values and C data types. + +See also [sectref {Runtime Behaviour}]. + +[para] +Returns the empty string. + +[para] +[list_begin arguments] + +[arg_def string option] Each may be one of: + +[list_begin options] + +[include api_embedc_cnameoption.inc] + +[opt_def -pass-cdata [arg boolean]] + +If [const false] (the default), the shim function performing the conversion to +and from Tcl level does not pass the ClientData as the first argument to +the function. + +[opt_def -arg-offset [arg int]] + +A non-negative integer, [const 0] by default, indicating the number of hidden +arguments preceding the actual procedure arguments. Used by higher-order code +generators where there are prefix arguments which are not directly seen by the +function but which influence argument counting and extraction. + +[list_end] + +[arg_def string resulttype] May be a predefined or a custom type. + +See [term {CriTcl cproc Type Reference}] for the full list of predefined types and how to +extend them. + +Unless otherwise noted, the Tcl return code is always [const TCL_OK]. + +[arg_def list arguments] Is a multi-dictionary where each key is an +argument type and its value is the argument name. + +For example: + +[example { int x int y }] + +[para] Each argument name must be a valid C identifier. + +[para] If the name is a list containing two items, the first item is the name +and the second item is the default value. A limited form of variadic arguments +can be accomplished using such default values. + +For example: + +[example { int {x 1} }] + +Here [arg x] is an optional argument of type [type int] with a default +value of [const 1]. + +[para] Argument conversion is completely bypassed when the argument is not +provided, so a custom converter doing validation does not get the chance to +validate the default value. In this case, the value should be checked in the +body of the function. + +[para] Each argument type may be a predefined or custom type. + +See [term {CriTcl cproc Type Reference}] for the full list of predefined types and how to +extend them. + +[list_end][comment {-- arguments --}] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cproc] [arg name] [arg arguments] [arg resulttype]] + +As documented below, but used when the C function named [arg name] already +exists. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cinit] [arg text] [arg externals]] + +Appends the C code in [arg text] and [arg externals], but only after all the +other fragments appended by the previously-listed commands regardless of their +placement in the [vset critcl_script] relative to this command. Thus, all +their content is visible. See also [sectref {Runtime Behaviour}]. + +[para] The C code in [arg text] is placed into the body of the initialization +function of the shared library backing the [vset critcl_script], and is +executed when this library is loaded into the interpreter. It has access to +the variable [var {Tcl_Interp* interp}] referencing the Tcl interpreter currently +being initialized. + +[para] [arg externals] is placed outside and just before the initialization +function, making it a good place for any external symbols required by +initialization function, but which should not be accessible by any other parts +of the C code. + +[para] [vset cumulative] + +[para] +Returns the empty string. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::include] [arg path]] + +This command is a convenient shorthand for + +[example { +critcl::code { + #include <${path}> +} +}] + +[comment ---------------------------------------------------------------------] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_embedc_cnameoption.inc b/src/vfs/critcl.vfs/doc/include/api_embedc_cnameoption.inc new file mode 100644 index 00000000..5301c03e --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_embedc_cnameoption.inc @@ -0,0 +1,5 @@ +[opt_def -cname [arg boolean]] + +If [const false] (the default), a name for the corresponding C function is +automatically derived from the fully-qualified [arg tclname]. Otherwise, name +of the C function is the last component of [arg tclname]. diff --git a/src/vfs/critcl.vfs/doc/include/api_generation.inc b/src/vfs/critcl.vfs/doc/include/api_generation.inc new file mode 100644 index 00000000..244a3eb0 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_generation.inc @@ -0,0 +1,37 @@ + +While file generation is related to the diversions explained in the +previous section they are not the same. + +Even so, like diversions this feature is for higher-level packages +generating their own C code. + +[para] Three examples of utility packages using this facility comes +with critcl itself. + +See the implementations of packages [package critcl::literals], +[package critcl::bitmap], and [package critcl::enum]. + +[para] When splitting a package implementation into pieces it is often +sensible to have a number of pure C companion files containing +low-level code, yet these files may require information about the code +in the main [file .critcl] file. Such declarations are normally not +exportable and using the stub table support does not make sense, as +this is completely internal to the package. + +[para] With the file generation command below the main [file .critcl] +file can generate any number of header files for the C companions to +pick up. + +[list_begin definitions] +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::make] [arg path] [arg contents]] + +This command creates the file [arg path] in a location where the C +companion files of the package are able to pick it up by simple +inclusion of [arg path] during their compilation, without interfering +with the outer system at all. + +[para] The generated file will contain the specified [arg contents]. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_introspection.inc b/src/vfs/critcl.vfs/doc/include/api_introspection.inc new file mode 100644 index 00000000..0672af3f --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_introspection.inc @@ -0,0 +1,95 @@ + +The following commands control compilation and linking. + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::check] [opt [arg label]] [arg text]] + +Returns a [const true] if the C code in [arg text] compiles sucessfully, and +[const false] otherwise. Used to check for availability of features in the +build environment. + +If provided, [arg label] is used to uniquely mark the results in the generated +log. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::checklink] [opt [arg label]] [arg text]] + +Like [cmd critcl::check] but also links the compiled objects, returning +[const true] if the link is successful and [const false] otherwise. + +If specified, [arg label] is used to uniquely mark the results in the generated +log. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::msg] [opt [option -nonewline]] [arg msg]] + +Scripts using [cmd critcl::check] and [cmd critcl::checklink] can use this +command to report results. Does nothing in [term {compile & run}] mode. Tools +like the [manpage {CriTcl Aplication}] may redefine this command to implement +their own message reporting. For example, [package critcl::app] and any +packages built on it print messages to [term stdout]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::print] [opt [option -nonewline]] [opt [arg chan]] [arg msg]] + +Used by the CriTcl internals to report activity. By default, effectively the +same thing as [cmd ::puts]. Tools directly using either the CriTcl package or +the CriTcl application package may redefine this procedure to implement their +own output functionality. + +[para] For example, the newest revisions of +[uri https://chiselapp.com/user/andreas_kupries/repository/Kettle/index Kettle] +use this to highlight build warnings. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::compiled]] + +Returns [const true] if the current [vset critcl_script] is already compiled +and [const false] otherwise. + +[para] Enables a [vset critcl_script] used as its own Tcl companion file (see +[cmd critcl::tsources]) to distinguish between being sourced for compilation in +[term {compile & run}] mode and being sourced from either the result of +[term {generate package}] mode or during the load phase of +[term {compile & run}] mode. + +The result is [const false] in the first case and [const true] in the later two +cases. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::compiling]] + +Returns [const true] if a working C compiler is available and [const false] +otherwise. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::done]] + +Returns [const true] when [vset critcl_script] has been built and +[const false] otherwise. Only useful from within a [vset critcl_script]. +Enables the Tcl parts of a [vset critcl_script] to distinguish between +[term {prebuilt package}] mode and [term {compile & run}] mode. + +[para] See also [sectref {Modes Of Operation/Use}]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::failed]] + +Returns [const true] if the [vset critcl_script] could not be built, and +[const false] otherwise. Forces the building of the package if it hasn't +already been done, but not its loading. Thus, a [vset critcl_script] can +check itself for availability of the compiled components. Only useful from +within a [vset critcl_script]. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::load]] + +Like [cmd critcl::failed] except that it also forces the loading of the +generated shared library, and that it returns [const true] on success and +[const false] on failure. Thus, a [vset critcl_script] can check itself for +availability of the compiled components. Only useful from within a +[vset critcl_script]. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_location.inc b/src/vfs/critcl.vfs/doc/include/api_location.inc new file mode 100644 index 00000000..0f1df825 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_location.inc @@ -0,0 +1,120 @@ + +First a small introduction for whose asking themselves +'what is location management' ? + +[para] By default critcl embeds [term #line] directives into the +generated C code so that any errors, warnings and notes found by the C +compiler during compilation will refer to the [file .critcl] file the +faulty code comes from, instead of the generated [file .c] file. + +[include rq_cline.inc] + +[para] Most users will not care about this feature beyond simply +wanting it to work and getting proper code references when reading +compiler output. + +[para] Developers of higher-level packages generating their own C code +however should care about this, to ensure that their generated code +contains proper references as well. Especially as this is key to +separating bugs concerning code generated by the package itself and +bug in the user's code going into the package, if any. + +[para] Examples of such packages come with critcl itself, see the +implementation of packages [package critcl::iassoc] and +[package critcl::class]. + +[para] To help such developers eight commands are provided to manage +such [term location] information. These are listed below. + +[para] A main concept is that they all operate on a single +[term {stored location}], setting, returning and clearing it. + +Note that this location information is completely independent of the +generation of [term #line] directives within critcl itself. + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::at::caller]] + +This command stores the location of the caller of the current +procedure as a tuple of file name and linenumber. Any previously +stored location is overwritten. + +The result of the command is the empty string. + +[call [cmd ::critcl::at::caller] [arg offset]] + +As above, the stored line number is modified by the specified +offset. In essence an implicit call of [cmd critcl::at::incr]. + +[call [cmd ::critcl::at::caller] [arg offset] [arg level]] + +As above, but the level the location information is taken from is +modified as well. Level [const 0] is the caller, [const -1] its +caller, etc. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::at::here]] + +This command stores the current location in the current procedure as a +tuple of file name and linenumber. Any previously stored location is +overwritten. + +The result of the command is the empty string. + +[para] In terms of [cmd ::critcl::at::caller] this is equivalent to +[example { + critcl::at::caller 0 1 +}] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::at::get*]] + +This command takes the stored location and returns a formatted +[term #line] directive ready for embedding into some C code. The +stored location is left untouched. + +Note that the directive contains its own closing newline. + +[para] For proper nesting and use it is recommended that such +directives are always added to the beginning of a code fragment. This +way, should deeper layers add their own directives these will come +before ours and thus be inactive. End result is that the outermost +layer generating a directive will 'win', i.e. have its directive +used. As it should be. + +[call [cmd ::critcl::at::get]] + +This command is like the above, except that it also clears the stored +location. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::at::=] [arg file] [arg line]] + +This command allows the caller to set the stored location to anything +they want, outside of critcl's control. + +The result of the command is the empty string. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::at::incr] [arg n]...] +[call [cmd ::critcl::at::incrt] [arg str]...] + +These commands allow the user to modify the line number of the stored +location, changing it incrementally. The increment is specified as +either a series of integer numbers ([cmd incr]), or a series of +strings to consider ([cmd incrt]). In case of the latter the delta is +the number of lines endings found in the strings. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::at::caller!]] +[call [cmd ::critcl::at::caller!] [arg offset]] +[call [cmd ::critcl::at::caller!] [arg offset] [arg level]] +[call [cmd ::critcl::at::here!]] + +These are convenience commands combining [cmd caller] and [cmd here] +with [cmd get]. I.e. they store the location and immediately return it +formatted as proper [term #line] directive. Also note that after their +use the stored location is cleared. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_meta.inc b/src/vfs/critcl.vfs/doc/include/api_meta.inc new file mode 100644 index 00000000..e37f6e8e --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_meta.inc @@ -0,0 +1,125 @@ + +CriTcl versions 3 and later can create TEApot meta-data to be placed into +[file teapot.txt] in a format suitable for use by the +[uri {http://docs.activestate.com/activetcl/8.5/tpm/toc.html} {TEApot tools}]. + +[para] +In version 2, some meta data support was already present through +[cmd ::critcl::license], but this was only used to generate [file license.txt]. + + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::license] [arg author] [opt [arg text]...]] + +Ignored in "compile & run" mode. + +[para] +In "generate package" mode provides information about the author of the +package and the license for the package. + +[para] +[arg text] arguments are concatenated to form the text of the license, which is +written to [file license.terms] in the same directory as [file pkgIndex.tcl]. +If no [arg text] is provided the license is read from [file license.terms] +in the same directory as the [vset critcl_script]. + +[para] This information takes precedence over any information specified through +the generic API [cmd ::critcl::meta]. It is additionally placed +into the meta data file [file teapot.txt] under the keys [term as::author] and +[term license]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::summary] [arg text]] + +Ignored in "compile & run" mode. + +[para] +In "generate package" mode places a short, preferably one-line description of +the package into the meta data file [file teapot.txt] under the key +[term summary]. This information takes precedence over information specified +through the generic API [cmd ::critcl::meta]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::description] [arg text]] + +Ignored in "compile & run" mode. + +[para] +In "generate package" mode places a longer description of the package into the +meta data file [file teapot.txt], under the key [term description]. The data +specified by this command takes precedence over any information specified +through the generic API [cmd ::critcl::meta]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::subject] [opt [arg key]...]] + +Ignored in "compile & run" mode. + +[para] +In "generate package" mode places each [arg key] into the meta data file +[file teapot.txt], under the key [term subject]. This information takes +precedence over any information specified through the generic API +[cmd ::critcl::meta]. + +[para] Calls to this command are cumulative. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::meta] [arg key] [opt [arg word]...]] + +Provides arbitrary meta data outside of the following reserved keys: + +[term as::author], +[term as::build::date], +[term description], +[term license], +[term name], +[term platform], +[term require] +[term subject], +[term summary], and +[term version], + +Its behaviour is like [cmd ::critcl::subject] in that it treats all +keys as list of words, with each call providing one or more words for +the key, and multiple calls extending the data for an existing key, if +not reserved. + +[para] While it is possible to declare information for one of the +reserved keys with this command such data is ignored when the final +meta data is assembled and written. + +[para] Use the commands +[cmd ::critcl::license], +[cmd ::critcl::summary], +[cmd ::critcl::description] +[cmd ::critcl::subject], +[cmd {package require}], and +[cmd {package provide}] +to declare data for the reserved keys. + +[para] The information for the reserved keys + +[term as::build::date] and +[term platform] + +is automatically generated by [package critcl] itself. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::meta?] [arg key]] + +Returns the value in the metadata associated with [arg key]. + +[para] Used primarily to retrieve the name of the package +from within utility packages having to adapt C code templates to their +environment. For example, [package critcl::class] uses does this. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::buildrequirement] [arg script]] + +Provides control over the capturing of dependencies declared via +[cmd {package require}]. [arg script] is evaluated and any dependencies +declared within are ignored, i.e. not recorded in the meta data. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_rcache.inc b/src/vfs/critcl.vfs/doc/include/api_rcache.inc new file mode 100644 index 00000000..05104148 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_rcache.inc @@ -0,0 +1,23 @@ + +The following commands control the [sectref {Result Cache}]. + +[vset not_needed_for_critcl_script] + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cache] [opt path]] + +Sets and returns the path to the directory for the package's result cache. + +[para] The default location is +[file ~/.critcl/[lb]platform::generic[rb]] and usually does not +require any changes. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::clean_cache] [opt [arg pattern]...]] + +Cleans the result cache, i.e. removes any and all files +and directories in it. If one or more patterns are specified then only +the files and directories matching them are removed. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/api_stubs.inc b/src/vfs/critcl.vfs/doc/include/api_stubs.inc new file mode 100644 index 00000000..c461d27a --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_stubs.inc @@ -0,0 +1,133 @@ + +CriTcl versions 3 and later provide [cmd critcl::api] to create and manipulate +stubs tables, Tcl's dynamic linking mechanism handling the resolution of +symbols between C extensions. + +See [uri http://wiki.tcl-lang.org/285] +for an introduction, and section [sectref {Stubs Tables}] +for the details of CriTcl's particular variant. + +[para] +Importing stubs tables, i.e. APIs, from another extension: + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::api] [method import] [arg name] [arg version]] + +Adds the following include directives into the [vset critcl_script] +[emph and] each of its companion [file .c] files: + +[list_begin enumerated] +[enum] #include <[var name]/[var name]Decls.h> +[enum] #include <[var name]/[var name]StubLib.h> +[list_end] + +Returns an error if [file [var name]] isn't in the search path for the +compiler. See [cmd critcl::cheaders] and the critcl application's [option -I] +and [option -includedir] options. + +[para] [emph Important:] If [var name] is a fully-qualified name in a +non-global namespace, e.g. +"c::stack", the namespace separators "::" are converted into underscores +("_") in path names, C code, etc. + +[para] [var name]/[var name]Decls.h contains the stubs table type declarations, +mapping macros, etc., and may include package-specific headers. See +[cmd {critcl::api header}], below. An [term {#include}] directive is added at +the beginning of the generated code for [vset critcl_script] and at the +beginning of each of its companion [file .c] files. + +[para] [var name]/[var name]StubLib.h contains the stubs table variable +definition and the function to initialize it. An [term {#include}] directive +for it is added to the initialization code for the [vset critcl_script] , +along with a call to the initializer function. + +[para] If [file [var name]/[var name].decls] accompanies +[var name]/[var name]Decls.h, it should contain the external representation of +the stubs table used to generate the headers. The file is read and the internal +representation of the stubs table returned for use by the importing package. +Otherwise, the empy string is returned. + +[para] One possible use would be the automatic generation of C code +calling on the functions listed in the imported API. + +[para] When generating a TEA package the names of the imported APIs +are used to declare [syscmd configure] options with which the user can +declare a non-standard directory for the headers of the API. Any API +[var name] is translated into a single configure option +[option --with-[var name]-include]. + +[list_end] + + +[para] Declaration and export of a stubs table, i.e. API, for +the [vset critcl_script]: + +[list_begin definitions] +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::api] [method function] [arg resulttype] [arg name] [arg arguments]] + +Adds to the public API of the [vset critcl_script] the signature +for the function named [arg name] and having the signature specified by +[arg arguments] and [arg resulttype]. Code is generated for a [file .decls] +file, the corresponding public headers, and a stubs table usable by +[cmd {critcl::api import}]. + +[para] [arg arguments] is a multidict where each key is an argument type and its +value is the argument name, and [arg resulttype] is a C type. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::api] [method header] [opt [arg {glob pattern}]...]] + +Each file matching a [arg {glob pattern}] is copied into the directory +containing the generated headers, and an [term {#include}] directive for it is +added to [file Decls.h] for the [vset critcl_script]. + +Returns an error if a [arg {glob pattern}] matches nothing. + +[para] [vset relative_pattern] + +[comment { + I am intentionally not documenting "critcl::api export". + I am not convinced yet that this method is needed. + The default, using the package name as the stubs table + library and interface names seems to me to be not only + reasonable, but the only setting truly needed. I simply + do not see a use case for having the library and interface + named different than the package. + (In a bundle, like tcllibc each bundled package still declares + itself properly). +}] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::api] [method extheader] [opt [arg file]...]] + +Like [cmd {::critcl::api header}], but each [arg file] should exist in the +external development environment. An [term {#include}] directive is added to +[file [var foo]Decls.h], but [arg file] is not copied to the package header +directory. [arg file] is not a glob pattern as CriTcl has no context, +i.e directory, in which to expand such patterns. + +[list_end] + +As with the headers for an imported API, an [term {#include}] directive is +added to the generated code for the [vset critcl_script] and to +each companion [file .c] file. + +[para] In "compile & run" mode the generated header files and any companion +headers are placed in the [sectref {Result Cache}] subdirectory for the +[vset critcl_script]. This directory is added to the include search path of +any other package importing this API and and building in mode "compile & run". + +[para] In "generate package" mode [option -includedir] specifies the +subdirectory in the package to place the generated headers in. This +directory is added to the search paths for header files, ensuring that a +package importing an API finds it if the package exporting that API used the +same setting for [option -includedir]. + +[para] In "generate TEA" mode the static scanner recognizes +[cmd {critcl::api header}] as a source of companion files. +It also uses data from calls to [cmd {critcl::api import}] to +add support for [option --with-[var foo]-include] options into the +generated [file configure(.in)] so that a user may specify custom +locations for the headers of any imported API. diff --git a/src/vfs/critcl.vfs/doc/include/api_tools.inc b/src/vfs/critcl.vfs/doc/include/api_tools.inc new file mode 100644 index 00000000..bc663eba --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/api_tools.inc @@ -0,0 +1,176 @@ + +The following commands provide tools like +[manpage {CriTcl Application}] or similar with +deeper access to the package's internals. + +[vset not_needed_for_critcl_script] + +[list_begin definitions] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::actualtarget]] + +Returns the platform identifier for the target platform, i.e. the platform to +build for. Unlike [cmd ::critcl::targetplatform] this is the true target, with +any cross-compilation information resolved. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::buildforpackage] [opt [arg flag]]] + +Signals whether the next file is to be built for inclusion into a package. If +not specified the [arg flag] defaults to [const true], i.e. building for a +package. This disables a number of things in the backend, namely the linking of +that file into a shared library and the loading of that library. It is expected +that the build results are later wrapped into a larger collection. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cnothingtodo] [arg file]] + +Checks whether there is anything to build for [arg file]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cresults] [opt [arg file]]] + +Returns information about building [arg file], or [cmd {info script}] If +[arg file] is not provided. + +The result in question is a dictionary containing the following items: + +[list_begin definitions] +[def [const clibraries]] +A list of external shared libraries and/or directories needed to link +[arg file]. + +[def [const ldflags]] +A list of linker flags needed to link [arg file]. + +[def [const license]] +The text of the license for the package [arg file] is located in. + +[def [const mintcl]] +The minimum version of Tcl required by the package [arg file] +is in to run successfully. A proper Tcl version number. + +[def [const objects]] +A list of object files to link into [arg file]. + +[def [const preload]] +A list of libraries to be preloaded in order to sucessfully load and use +[arg file]. + +[def [const tk]] +[const true] if [arg file] requires Tk and [const false] otherwise. + +[def [const tsources]] +A list of companion [file .tcl] files to source in order to load and use the +[term {CriTcl script}] [arg file]. + +[def [const log]] +The full build log generated by the compiler/linker, including command +line data from critcl, and other things. + +[def [const exl]] +The raw build log generated by the compiler/linker. Contains the output +generated by the invoked applications. +[list_end] + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::crosscheck]] + +Determines whether the package is configured for cross-compilation and prints a +message to the standard error channel if so. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::error] [arg msg]] + +Used to report internal errors. The default implementation simply returns the +error. Tools like the [manpage {CriTcl Application}] are allowed to redefine +this procedure to perform their own way of error reporting. There is +one constraint they are not allowed to change: The procedure must +[emph {not return}] to the caller. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::knowntargets]] + +Returns a list of the identifiers of all targets +found during the last invocation of [cmd critcl::readconfig]. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::sharedlibext]] + +Returns the file extension for shared libraries on the target platform. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::targetconfig]] + +Returns the identifier of the target to build for, as specified by either the +user or the system. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::buildplatform]] + +Returns the identifier of the build platform, i.e. where the package is running +on. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::targetplatform]] + +Returns the identifier of the target platform, +i.e. the platform to compile for. In contrast to +[cmd ::critcl::actualtarget] this may be the name of a +cross-compilation target. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::cobjects] [opt [arg {glob pattern}]...]] + +Like [cmd ::critcl::clibraries], but instead of matching libraries, each +[arg {glob pattern}] matches object files to be linked into the +shared object (at compile time, not runtime). If a [arg {glob pattern}] matches +nothing an error is returned. + +Not listed in [sectref {Control & Interface}] because it is of no use to +package writers. Only tools like the [manpage {CriTcl Application}] need it. + +[para] [vset relative_pattern] + +[para] Calls to this command are cumulative. + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::scan] [arg path]] + +The main entry point to CriTcl's static code scanner. Used by tools to +implement processing modes like the assembly of a directory hierarchy +containing a TEA-lookalike buildystem, etc. + +[para] +Scans [arg path] and returns a dictionary containing the following items: + +[list_begin definitions] +[def version] Package version. +[def org] Author(ing organization). + +[def files] List of the companion files, relative to the directory of the input +file. + +[list_end] + + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::name2c] [arg name]] + +Given the Tcl-level identifier [arg name], returns a list containing the +following details of its conversion to C: + +[list_begin itemized] +[item] Tcl namespace prefix +[item] C namespace prefix +[item] Tcl base name +[item] C base name +[list_end] + +[para] For use by utilities that provide Tcl commands without going through +standard commands like [cmd critcl::ccommand] or [cmd critcl::cproc]. +[package critcl::class] does this. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/architecture.inc b/src/vfs/critcl.vfs/doc/include/architecture.inc new file mode 100644 index 00000000..32b54630 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/architecture.inc @@ -0,0 +1,57 @@ + +The system consists of two main layers, as seen in the figure below, +plus a support layer containing general packages the system uses during +operation. + +[para][image architecture][para] + +[list_begin enumerated] +[enum] + +At the top we have an application built on top of the core packages, +providing command line access to the second and third usage modes, +i.e. [term {Generate Package}] and [term {Generate TEA Package}]. + +[list_begin definitions][comment {----- application ---}] +[def [syscmd critcl]] +[def [package critcl::app]] +[list_end][comment {------------------- application ---}] + +[enum] + +Below that is the core package providing the essential functionality +of the system, plus various utility packages which make common tasks +more convenient. + +[list_begin definitions][comment {----- core ---}] +[def [package critcl]] +[def [package critcl::util]] +[list_end][comment {------------------- core ---}] + +[enum] +Lastly a layer of supporting packages, mostly external to critcl. + +[list_begin definitions][comment {----- support ---}] +[def [package md5]] +For this pure-Tcl package to be fast users should get one of several +possible accelerator packages: +[list_begin enumerated] +[enum] [package tcllibc] +[enum] [package Trf] +[enum] [package md5c] +[list_end] + +[def [package cmdline]] +[def [package platform]] +[def [package stubs::container ]] +[def [package stubs::reader ]] +[def [package stubs::writer ]] +[def [package stubs::gen ]] +[def [package stubs::gen::init ]] +[def [package stubs::gen::header]] +[def [package stubs::gen::decl ]] +[def [package stubs::gen::macro ]] +[def [package stubs::gen::slot ]] +[def [package stubs::gen::lib ]] +[list_end][comment {------------------- support ---}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/b_test.inc b/src/vfs/critcl.vfs/doc/include/b_test.inc new file mode 100644 index 00000000..59b614a3 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/b_test.inc @@ -0,0 +1,19 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] + +Installing [vset critcl] contains an implicit test of its functionality. + +[para] One of its operation modes uses the MD5 hash internally to generate unique ids for +sources, as a means of detecting changes. To make generation of such hashes fast a +[vset critcl]-based package for MD5 is installed as part of the main installation process. + +[para] In other words, after installing the core packages of [vset critcl] this partial +installation is used to build the rest. + +[para] This is possible because building a package from [vset critcl]-based sources is the +operation mode not using MD5, therefore there is no circular dependency. + +[para] For our purposes this however is also a self-test of the system, verifying that the +core of [vset critcl] works, as well as the C compiler. + +[para] For additional testing simply move on to section [sectref {The First Package}] of +the guide on [term {How To Use CriTcl}]. diff --git a/src/vfs/critcl.vfs/doc/include/b_unix.inc b/src/vfs/critcl.vfs/doc/include/b_unix.inc new file mode 100644 index 00000000..813c58b9 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/b_unix.inc @@ -0,0 +1,42 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] + +This section offers instructions for installing [vset critcl] on various kinds of Unix and +Unix-related systems, i.e. [term Linux], the various [term BSD]s, etc. It especially +covers [term {Mac OS X}] as well. + +[para] Use the instructions in section [sectref {Install On Windows}] when installing on a +Windows platform and not using a unix-like environment as provided by tools like +[vset mingw], [vset cygwin], [vset git4win], [vset wsl], etc. + +[list_begin enumerated] + +[enum] Change the working directory to the top level directory of the [vset critcl] +checkout obtained by following the instructions of [term {How To Get The CriTcl Sources}]. + +[enum] Verify that the file [file build.tcl] is marked executable. Make it executable if +it is not. + +[enum] Invoke [example { ./build.tcl install }] to perform the installation. + +[para] [strong Attention] This command uses default locations for the placement of the +[cmd critcl] application, the various packages, and header files. + +[enum] Invoke [example { ./build.tcl dirs }] to see the chosens paths before actually +performing the installation. + +[enum] [include include/build_install_options.inc] + +These options are especially necessary in all environments not using the semi-standard +[file bin], [file lib], [file include] locations from [syscmd configure]. + +[para] As an example of such environments, Ubuntu (and possibly Debian) expect Tcl +packages to be installed into the [file /usr/share/tcltk] directory, therefore requiring +the use of [example {--lib-dir /usr/share/tcltk}] for proper installation. + +[list_end] + +[para] [strong Note] that this guide neither covers the details of the [method install] +method, nor does it cover any of the other methods available through the [cmd build.tcl] +tool of [vset critcl]. + +These can be found in the [term {CriTcl build.tcl Tool Reference}]. diff --git a/src/vfs/critcl.vfs/doc/include/b_windows.inc b/src/vfs/critcl.vfs/doc/include/b_windows.inc new file mode 100644 index 00000000..ac7c243b --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/b_windows.inc @@ -0,0 +1,38 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] + +This section offers instructions for installing [vset critcl] on a Windows (tm) host. + +[strong Note] that environments as provided by tools like [vset mingw], [vset cygwin], +[vset git4win], [vset wsl], etc. are classed as Unix-like, and the instructions in section +[sectref {Install On Unix}] apply. + +[list_begin enumerated] + +[enum] In a DOS box, change the working directory to the top level directory of the +[vset critcl] checkout obtained by following the instructions of +[term {How To Get The CriTcl Sources}]. + +[enum] In the same DOS box, invoke [example { tclsh.exe ./build.tcl install }] to perform +the installation. + +[para] [strong Attention] This command uses default locations for the placement of the +[cmd critcl] application, the various packages, and header files. + +[enum] Invoke [example { tclsh.exe ./build.tcl dirs }] to see the chosens paths before +actually performing the installation. + +[enum] [include include/build_install_options.inc] + +[list_end] + +[para] [strong Attention!] The current installer does not put an extension on the +[syscmd critcl] application. This forces users to either explicitly choose the +[syscmd tclsh] to run the application, or manually rename the installed file to +[file critcl.tcl]. The latter assumes that an association for [file .tcl] is available, to +either [syscmd tclsh], or [syscmd wish]. + +[para] [strong Note] that this guide neither covers the details of the [method install] +method, nor does it cover any of the other methods available through the [cmd build.tcl] +tool of [vset critcl]. + +These can be found in the [term {CriTcl build.tcl Tool Reference}]. diff --git a/src/vfs/critcl.vfs/doc/include/build_install_options.inc b/src/vfs/critcl.vfs/doc/include/build_install_options.inc new file mode 100644 index 00000000..2a3c2b55 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/build_install_options.inc @@ -0,0 +1,12 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] + +Use the options listed below to change the paths used for installation as desired. This is +the same method as with [cmd configure] based packages. + +[list_begin options] +[opt_def --prefix [arg path]] Base path for non-package files. +[opt_def --include-dir [arg path]] Destination path for header files. +[opt_def --exec-prefix [arg path]] Base path for applications and packages. +[opt_def --bin-dir [arg path]] Destination path for applications. +[opt_def --lib-dir [arg path]] Destination path for packages. +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes.inc b/src/vfs/critcl.vfs/doc/include/changes.inc new file mode 100644 index 00000000..e4e559cb --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes.inc @@ -0,0 +1,6 @@ +[para] The latest changes are found at the top. + +[include changes/32.inc] +[include changes/31.inc] +[include changes/3.inc] +[include changes/21.inc] diff --git a/src/vfs/critcl.vfs/doc/include/changes/21.inc b/src/vfs/critcl.vfs/doc/include/changes/21.inc new file mode 100644 index 00000000..7d09142c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/21.inc @@ -0,0 +1,127 @@ +[section {Changes for version 2.1}] +[list_begin enumerated] + +[enum] Fixed bug where [cmd critcl::tsources] interpreted relative +paths as relative to the current working directory instead of +relative to the [file .critcl] file using the command, as all other +commands of this type do. + +[enum] Fixed internals, preventing information collected for multiple +[file .critcl] files to leak between them. Notably, [cmd critcl::tk] +is not a global configuration option anymore. + +[enum] Fixed the command [cmd critcl::license] to be a null-operation +in mode "compile & run", instead of throwing an error. + +[enum] Fixed the critcl application's interference with the "compile & +run" result cache in [option -pkg] mode by having it use a wholly +separate (and by default transient) directory for that mode. + +[enum] Fixed bug where changes to a [file .critcl] file did not result +in a rebuild for mode "compile & run". All relevant API commands now +ensure UUID changes. + +[enum] Fixed bug in the backend handling of [cmd critcl::debug] where +the companion c-sources of a [file .critcl] file were not compiled +with debug options, although the [file .critcl] file was. + +[enum] Fixed bug in [cmd critcl::debug] which prevented recognition of +mode "all" when it was not the first argument to the command. + +[enum] Fixed bug in [file preload.c] preventing its compilation on +non-windows platforms. + +[enum] Fixed long-standing bug in the handling of namespace qualifiers +in the command name argument of [cmd critcl::cproc] and +[cmd critcl::ccommand]. It is now possible to specify a fully +qualified command name without issues. + +[enum] Extended/reworked [cmd critcl::tsources] to be the canonical +way of declaring [file .tcl] companion files even for mode "compile & +run". + +[enum] Extended/reworked [cmd critcl::tsources] to allow the use of a +[file .critcl] file as its own Tcl companion file. + +[enum] Extended [cmd critcl::framework] to internally check for OS X +build target, and to ignore the declaration if its not. + +[enum] Extended [cmd critcl::failed] to be callable more than once in +a [file .critcl] file. The first call forces the build, if it was not +done already, to get the result. Further calls return the cached +result of the first call. + +[enum] Extended the handling of environment variable CC in the code +determining the compiler to use to deal with (i.e. remove) paths to +the compiler, compiler file extensions, and compiler options specified +after the compiler itself, leaving only the bare name of the compiler. + +[enum] Extended the code handling the search for preloaded libraries +to print the paths it searched, making debugging of a search failure +easier. + +[enum] A new command [cmd critcl::tcl] can be used to declare the +version of Tcl minimally needed to build and run the [file .critcl] +file and package. Defaults to 8.4 if not declared. Extended critcl to +have the stubs and headers for all of Tcl 8.4, 8.5, and 8.6. + +[enum] A new command [cmd critcl::load] forces the build and load of a +[file .critcl] file. This is the official way for overriding critcl's +default lazy-build-&-load-on-demand scheme for mode "compile & run". + +[para] [emph Note] that after using [cmd critcl::load] / +[cmd critcl::failed] in a [file .critcl] file it is not possible to +use critcl commands in that file anymore. Doing so will throw an +error. + +[enum] Extended the generation of '#line' pragmas to use +[cmd {info frame}] (if available) to provide the C compiler with exact +line numbers into the [file .critcl] file for the reporting of +warnings and errors. + +[enum] Extended [cmd critcl::check] with logging to help with +debugging build-time checks of the environment, plus an additional +optional argument to provide labeling. + +[enum] Added a new command [cmd critcl::checklink] which not only +tries to check the environment via compiling the code, but also +its linkability. + +[enum] Added a new command [cmd critcl::msg] for messaging, like +command [cmd critcl::error] is for error reporting. Likewise this is a +hook a user of the package is allowed to override. The default +implementation, used by mode [term {compile & run}] does nothing. The +implementation for mode [term {generate package}] prints the message +to stdout. + +[para] Envisioned use is for the reporting of results determined by +[cmd critcl::check] and [cmd critcl::checklink] during building, to +help with debugging when something goes wrong with a check. + +[enum] Exposed the argument processing internals of [cmd critcl::proc] +for use by advanced users. The new commands are + +[list_begin enum] +[enum] [cmd critcl::argnames] +[enum] [cmd critcl::argcnames] +[enum] [cmd critcl::argcsignature] +[enum] [cmd critcl::argvardecls] +[enum] [cmd critcl::argconversion] +[list_end] + +Please see section [emph {Advanced Embedded C Code}] of the +[package critcl] package documentation for details. + +[enum] Extended the critcl package to intercept [cmd {package +provide}] and record the file -> package name mapping. Plus other +internal changes now allow the use of namespaced package names while +still using proper path names and init function. + +[enum] Dropped the unused commands [cmd critcl::optimize] and +[cmd critcl::include]. + +[enum] Dropped [option -lib] mode from the critcl application. + +[enum] Dropped remnants of support for Tcl 8.3 and before. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3.inc b/src/vfs/critcl.vfs/doc/include/changes/3.inc new file mode 100644 index 00000000..8fd8e431 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3.inc @@ -0,0 +1,91 @@ +[include 307.inc] +[include 306.inc] +[include 305.inc] +[include 304.inc] +[include 303.inc] +[include 302.inc] +[include 301.inc] + +[section {Changes for version 3}] +[list_begin enumerated] + +[enum] The command [cmd critcl::platform] was deprecated in version +2.1, superceded by [cmd critcl::targetplatform], yet kept for +compatibility. Now it has been removed. + +[enum] The command [cmd critcl::compiled] was kept with in version 2.1 +with semantics in contradiction to its, for compatibility. This +contradiction has been removed, changing the visible semantics of the +command to be in line with its name. + +[enum] The change to version 3 became necessary because of the two +incompatible visible changes above. + +[enum] Extended the application package with code handling a new +option [option -tea]. Specifying this option invokes a special mode +where critcl generates a TEA package, i.e. wraps the input into a +directory hierarchy and support files which provide it TEA-lookalike +buildsystem. + +[para] This new option, and [option -pkg], exclude each other. If +both are specified the last used option takes precedence. + +[para] The generated package directory hierarchy is mostly +self-contained, but not fully. It requires not only a working +installation of Tcl, but also working installations of the packages +[package md5] and [package cmdline]. Both of these are provided by the +[package Tcllib] bundle. Not required, but recommended to have +installed are any of the packages which can accelerate md5's +operation, i.e. [package cryptkit], [package tcllibc], or +[package Trf]. + +[enum] Extended the critcl package with a new command +[cmd critcl::scan] taking the path to a [file .critcl] file, +statically scanning it, and returning license, version, a list of its +companion files, list of imported APIs, and list of +developer-specified custom configuration options. This data is the +foundation for the TEA wrapping described above. + +[para] Note that this is a [emph static] scan. While the other build +modes can (must) execute the [file .critcl] file and make +platform-specific decisions regarding the assembled C code, companion +files, etc. the TEA wrap mode is not in a position to make +platform-specific decisions. It has to wrap everything which might +conceivably be needed when actually building. Hence the static scan. + +This has however its own set of problems, namely the inability to +figure out any dynamic construction of companion file paths, at least +on its own. Thus: + +[enum] Extended the API used by critcl-based packages with the command +[cmd critcl::owns]. While this command is ignored by the regular build +modes the static scanner described above takes its arguments as the +names of companion files which have to be wrapped into the TEA package +and could not be figured by the scanner otherwise, like because of +dynamic paths to [cmd critcl::tsources], [cmd critcl::csources], +getting sourced directly, or simply being adjunct datafiles. + +[enum] Extended the API used by critcl-based packages with the command +[cmd critcl::api] for the management of stubs tables, be it their use, +and/or declaration and export. + +[para] Please see section [emph {Stubs Table Management}] of the +[package critcl] package documentation for details. + +[enum] Extended the API used by critcl-based packages with the command +[cmd critcl::userconfig] for the management of developer-specified +custom configuration options, be it their use and/or declaration. + +[para] Please see section [emph {Custom Build Configuration}] of the +[package critcl] package documentation for details. + +[enum] Extended the API used by critcl-based packages with the +commands [cmd critcl::description], [cmd critcl::summary], +[cmd critcl::subject], [cmd critcl::meta], and +[cmd critcl::buildrequirement] for the declaration of TEApot meta data +for/about the package. + +[para] Please see section [emph {Package Meta Data}] of the +[package critcl] package documentation for details. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/301.inc b/src/vfs/critcl.vfs/doc/include/changes/301.inc new file mode 100644 index 00000000..d251e25d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/301.inc @@ -0,0 +1,41 @@ +[section {Changes for version 3.0.1}] +[list_begin enumerated] + +[enum] Bugfixes all around. In detail: + +[enum] Fixed recording of Tcl version requirements. Keep package name +and version together, unbreaking generated meta data and generated +package load command. + +[enum] Fixed the build scripts: When installing, or wrapping for TEA, +generate any missing directories + +[enum] Modified the build scripts to properly exit the application +when the window of their GUI is closed through the (X) button. + +[enum] Removed an 8.5-ism (open wb) which had slipped into the main +build script. + +[enum] Modified the example build scripts to separate the output for +the different examples (and packages) by adding empty lines. + +[enum] stack::c example bugfix: Include API declarations for use in +the companion files. + +[enum] Extended the documentation: Noted the need for a working +installation of a C compiler. + +[enum] Extended the Windows target definitions and code to handle the +manifest files used by modern MS development environments. Note that +this code handles both possibilities, environment using manifests, and +(old(er)) environments without. + +[enum] Extended the Windows 64bit target definitions and code to +auto-detect the need for the helper library "bufferoverflowU.lib" and +reconfigure the compile and link commands appropriately. We assume +that the library must be linked when present. This should be no harm +if the library is present, yet not needed. Just superfluous. We search +for the library in the paths specified by the environment variable +LIB. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/302.inc b/src/vfs/critcl.vfs/doc/include/changes/302.inc new file mode 100644 index 00000000..48bca053 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/302.inc @@ -0,0 +1,17 @@ +[section {Changes for version 3.0.2}] +[list_begin enumerated] + +[enum] Fixed issue in compile-and-run mode where commands put into the +auto_index are not found by Tcl's [lb]unknown[rb] command. + +[enum] Fixed an array key mismatch breaking usage of client data and +delete function for procedure. Reported by Jos DeCoster, with patch. + +[enum] Implemented a command line option [option -L], an equivalent of +option [option -I], just for library search paths. + +[enum] Fixed github issues 5 and 8. Working around a missing variable +::errorInfo. It should always be present, however there seem to be +revisions of Tcl around which violate this assumption. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/303.inc b/src/vfs/critcl.vfs/doc/include/changes/303.inc new file mode 100644 index 00000000..2944258e --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/303.inc @@ -0,0 +1,9 @@ +[section {Changes for version 3.0.3}] +[list_begin enumerated] + +[enum] Fixed github issues 5 and 8, for the example build.tcl +scripts. Working around a missing variable ::errorInfo. It should +always be present, however there seem to be revisions of Tcl around +which violate this assumption. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/304.inc b/src/vfs/critcl.vfs/doc/include/changes/304.inc new file mode 100644 index 00000000..47c28589 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/304.inc @@ -0,0 +1,38 @@ +[section {Changes for version 3.0.4}] +[list_begin enumerated] + +[enum] Fixed generation of the package's initname when the incoming + code is read from stdin and has no proper path. + +[enum] Fixed github issue 11. Now using /LIBPATH instead of -L + on Windows (libinclude configuration setting). + +[enum] Extended critcl to handle -l:path format of -l options. + GNU ld 2.22+ handles this by searching for the path as + is. Good when specifying static libraries, as plain -l looks + for shared libraries in preference over static. critcl handles + it now, as older GNU ld's do not understand it, nor the + various vendor-specific linkers. + +[enum] Fixed github issue #12. CriTcl now determines the version of + MSVC in use and uses it to switch between various link debug + options. Simplified the handling of bufferoverflowU.lib also, + making use of the same mechanism and collapsing the two + configurations sections we had back into one. + +[enum] Reworked the insertion of #line pragmas into the generated C + code to avoid limitations on the line number argument imposed + by various compilers, and be more accurate. + +[enum] Modified argument processing. Option -libdir now also + implies -L for its argument. + +[enum] Extended handling of option -show ([cmd critcl::showconfig]) + to list the path of the configuration file the data is coming + from. Good for debugging configuration processing. + +[enum] Extended the build script with targets to regenerate the + embedded documentation, and diagrams, and to generate a + release. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/305.inc b/src/vfs/critcl.vfs/doc/include/changes/305.inc new file mode 100644 index 00000000..f83e3cb2 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/305.inc @@ -0,0 +1,10 @@ +[section {Changes for version 3.0.5}] +[list_begin enumerated] + +[enum] Fixed bug in the new code for #line pragmas triggered when + specifying C code without leading whitespace. + +[enum] Extended the documentation to have manpages for the license, + source retrieval, installer, and developer's guides. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/306.inc b/src/vfs/critcl.vfs/doc/include/changes/306.inc new file mode 100644 index 00000000..4dd90439 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/306.inc @@ -0,0 +1,16 @@ +[section {Changes for version 3.0.6}] +[list_begin enumerated] + +[enum] Fixed github issue 10. The critcl application now delivers a + proper exit code (1) on build failure, instead of always + indicating success (status 0). + +[enum] Fixed github issue 13. Handling of bufferoverflowU.lib for + release builds was inconsistent with handling for debug + builds. It is now identically handled (conditional) by + both cases. + +[enum] Documentation cleanup, mainly in the installation guide, and + the README.md shown by github + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/307.inc b/src/vfs/critcl.vfs/doc/include/changes/307.inc new file mode 100644 index 00000000..5a9d0483 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/307.inc @@ -0,0 +1,11 @@ +[section {Changes for version 3.0.7}] +[list_begin enumerated] + +[enum] Fixed the code generated by [cmd critcl::c++command]. + The emitted code handed a non-static string table to + [fun Tcl_GetIndexFromObj], in violation of the contract, which + requires the table to have a fixed address. This was a memory + smash waiting to happen. Thanks to Brian Griffin for alrerting + us to the general problem. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/31.inc b/src/vfs/critcl.vfs/doc/include/changes/31.inc new file mode 100644 index 00000000..3f5dde95 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/31.inc @@ -0,0 +1,107 @@ +[include 31181.inc] +[include 3118.inc] +[include 3117.inc] +[include 3116.inc] +[include 3115.inc] +[include 3114.inc] +[include 3113.inc] +[include 3112.inc] +[include 3111.inc] +[include 3110.inc] +[include 319.inc] +[include 318.inc] +[include 317.inc] +[include 316.inc] +[include 315.inc] +[include 314.inc] +[include 313.inc] +[include 312.inc] +[include 311.inc] + +[section {Changes for version 3.1}] +[list_begin enumerated] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Added a new higher-level package [package critcl::iassoc]. + +[para] This package simplifies the creation of code associating data +with an interpreter via Tcl's [fun Tcl_(Get|Set)AssocData()] APIs. The +user can concentrate on his data while all the necessary boilerplate +C code to support this is generated by the package. + +[para] This package uses several of the new features which were added +to the core [package critcl] package, see below. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Added the higher-level package [package critcl::class]. + +[para] This package simplifies the creation of C level objects with +class and instance commands. The user can write a class definition +with class- and instance-variables and -methods similar to a TclOO +class, with all the necessary boilerplate C code to support this +generated by the package. + +[para] This package uses several of the new features which were added +to the core [package critcl] package, see below. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Extended the API for handling TEApot metadata. Added the +command [cmd critcl::meta?] to query the stored information. Main use +currently envisioned is retrieval of the current package's name by +utility commands, for use in constructed names. This particular +information is always available due to the static scan of the package +file on execution of the first critcl command. + +[para] The new packages [package critcl::iassoc] and +[package critcl::class] (see above) are users of this command. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Extended the API with a command, [cmd critcl::name2c], exposing +the process of converting a Tcl name into base name, namespace, and C +namespace. This enables higher-level code generators to generate the same +type of C identifiers as [package critcl] itself. + +[para] The new package [package critcl::class] (see above) is a user +of this command. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Extended the API with a command, [cmd critcl::source], +executing critcl commands found in a separate file in the context of +the current file. This enables easier management of larger bodies of +code as it allows the user to split such up into easier to digest +smaller chunks without causing the generation of multiple packages. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Related to the previous item, extended the API with commands to +divert collection of generated C code into memory. This makes it +easier to use the commands for embedded C code in higher-level code +generators. + +[para] See the section [sectref {Advanced: Diversions}] for details of +the provided commands. + +[para] The new package [package critcl::class] (see above) is a user +of these facilities. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Extended the API with commands helping developers with the +generation of proper C [term #line] directives. This allows +higher-level code generators to generate and insert their own +directives, ensuring that compile errors in their code are properly +attributed. + +[para] See the section [sectref {Advanced: Location management}] for +details of the provided commands. + +[para] The new packages [package critcl::iassoc] and +[package critcl::class] (see above) are users of these facilities. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[enum] Extended the API with commands giving users the ability to +define custom argument and result types for [cmd ::critcl::cproc]. + +[para] See the section [sectref {CriTcl cproc Type Reference}] for +details of the provided commands. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/311.inc b/src/vfs/critcl.vfs/doc/include/changes/311.inc new file mode 100644 index 00000000..f21f355e --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/311.inc @@ -0,0 +1,18 @@ +[section {Changes for version 3.1.1}] +[list_begin enumerated] + +[enum] Bugfixes all around. In detail: + +[enum] Fixed the generation of wrong#args errors for +[cmd critcl::cproc] and derived code ([package critcl::class] +cproc-based methods). Use NULL if there are no arguments, and +take the offset into account. + +[enum] Fixed the handling of package names by +[package critcl::class]. Forgot that they may contain namespace +separators. Bumped to version 1.0.1. + +[enum] Extended a [package critcl::class] generated error message in +instance creation for clarity. Bumped to version 1.0.2. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3110.inc b/src/vfs/critcl.vfs/doc/include/changes/3110.inc new file mode 100644 index 00000000..81c739d7 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3110.inc @@ -0,0 +1,20 @@ +[section {Changes for version 3.1.10}] +[list_begin enumerated] + +[enum] Fixed code version numbering forgotten with 3.1.9. + +[enum] Fixed issue #35. In package mode (-pkg) the object cache + directory is unique to the process, thus we do not need + content-hashing to generate unique file names. A simple + counter is sufficient and much faster. +[para] + Note that mode "compile & run" is not as blessed and still + uses content-hasing with md5 to ensure unique file names + in its per-user object cache. + +[enum] Fixed issue where the [cmd ccommand] forgot to use its body as + input for the UUID generation. Thus ignoring changes to it in + mode compile & run, and not rebuilding a library for changed + sources. Bug and fix reported by Peter Spjuth. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3111.inc b/src/vfs/critcl.vfs/doc/include/changes/3111.inc new file mode 100644 index 00000000..a568acc7 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3111.inc @@ -0,0 +1,27 @@ +[section {Changes for version 3.1.11}] +[list_begin enumerated] + +[enum] Fixed issue #37, via pull request #38, with thanks to + Jos DeCoster. Information was stored into the v::delproc + and v::clientdata arrays using a different key than when + retrieving the same information, thus failing the latter. + +[enum] New convenience command [cmd critcl::include] for easy + inclusion of headers and other C files. + +[enum] New command [cmd critcl::make] to generate a local header of + other C files for use by other parts of a package through + inclusion. + +[enum] New utility package [package critcl::literals] for quick and + easy setup of and access to pools of fixed Tcl_Obj* strings. + + Built on top of [package critcl::iassoc]. + +[enum] New utility package [package critcl::bitmap] for quick and easy + setup and use of mappings between C bitsets and Tcl lists whose + string elements represent that set. + + Built on top of [package critcl::iassoc]. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3112.inc b/src/vfs/critcl.vfs/doc/include/changes/3112.inc new file mode 100644 index 00000000..eac50adb --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3112.inc @@ -0,0 +1,36 @@ +[section {Changes for version 3.1.12}] +[list_begin enumerated] + +[enum] Fixed issue 42. Clear ::errorInfo immediately after startup to + prevent leakage of irrelevant (caught) errors into our script + and confusing the usage code. + +[enum] Fixed issue 40. Keep the order of libraries, and allow + duplicates. Both are things which are occasionally required for + proper linking. + +[enum] Extended the utility package [package critcl::literals] to + declare a cproc result-type for a pool. + +[para] Further fixed the generated header to handle multiple inclusion. + +[para] Bumped version to 1.1. + +[enum] Fixed issue with utility package [package critcl::bitmap]. + +[para] Fixed the generated header to handle multiple inclusion. + +[para] Bumped version to 1.0.1. + +[enum] Created new utility package [package critcl::enum] for the + quick and easy setup and use of mappings between C values + and Tcl strings. + + Built on top of [package critcl::literals]. + +[enum] Added examples demonstrating the use of the utility packages + [package critcl::literals], + [package critcl::bitmap], and + [package critcl::enum] + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3113.inc b/src/vfs/critcl.vfs/doc/include/changes/3113.inc new file mode 100644 index 00000000..446810a6 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3113.inc @@ -0,0 +1,69 @@ +[section {Changes for version 3.1.13}] +[list_begin enumerated] + +[enum] Merged PR #43. Fixed bug loading adjunct Tcl sources. + +[enum] Fixes in documentation and generated code of package + "critcl::enum". Bumped to version 1.0.1. + +[enum] Fixes in documentation of package "critcl::bitmap". + +[enum] New package "critcl::emap". In essence a variant or cross of + "critcl::bitmap" with behaviour like "critcl::enum". + +[enum] Merged PR #49. Fixed documentation typo. + +[enum] Merged PR #46. Fixed documentation typo. + +[enum] Merged PR #47. Fixes to test results to match the accumulated + code changes. Also made portable across Tcl versions (varying + error syntax). + +[enum] New predefined argument- and result-type "wideint" mapping to + Tcl_WideInt. + +[enum] New predefined argument-type "bytes" mapping to tuple of + byte-array data and length. Note: The existing "bytearray" + type (and its aliases) was left untouched, to keep backward + compatibility. + +[enum] Modified the internal interface between the Tcl shim and C + function underneath "critcl::cproc" with respect to the + handling of optional arguments. + + An optional argument "X" now induces the use of two C + arguments, "X" and "has_X". The new argument "has_X" is of + boolean (int) type. It is set to true when X is set, and set + to false when X has the default value. C code which cares + about knowing if the argument is default or not is now able to + check that quickly, without having to code the default value + inside. + + NOTE: This change is visible in the output of the advanced + commands "argcnames", "argcsignature", "argvardecls", + and "argconversion". + +[enum] Fixed issue #50 and documented the availability of variable + "interp" (type Tcl_Interp*) within "critcl::cinit" C code + fragments. + + Note that while the old, undocumented name of the variable, + "ip", is still usable, it is deprecated. It will be fully + removed in two releases, i.e. for release 3.1.15. + + The variable name was changed to be consistent with other code + environments. + +[enum] Fixed issue #51. Disabled the generation of #line directives + for "critcl::config lines 0" coming from template files, or + code generated with them before the final value of this + setting was known. + +[enum] Fixed issue with handling of namespaced package names in + "critcl::iassoc". Equivalent to a bug in "critcl::class" fixed + for critcl 3.1.1, critcl::class 1.0.1. + + Note: "literals", "enum", "emap", and "bitmap" do not require + a fix as they are all built on top of "iassoc". + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3114.inc b/src/vfs/critcl.vfs/doc/include/changes/3114.inc new file mode 100644 index 00000000..49b7eefb --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3114.inc @@ -0,0 +1,38 @@ +[section {Changes for version 3.1.14}] +[list_begin enumerated] + +[enum] Fixed issue #36. Added message to target [const all] of the + Makefile generated for TEA mode. Additionally tweaked other + parts of the output to be less noisy. + +[enum] Accepted request implied in issue #54. Unconditionally save + the compiler/linker build log into key [const log] of the + dictionary returned by [cmd cresults], and save a copy of only + the execution output in the new key [const exl] ("execution + log"). + +[enum] Fixed issue #53. Clarified the documentation of commands + [cmd critcl::load] and [cmd critcl::failed] with regard + to their results and the throwing of errors (does not happen). + +[enum] Fixed issue #48. Modified mode "compile & run" to allow new + declarations in a file, after it was build, instead of + erroring out. The new decls are build when needed. Mode + "precompile" is unchanged and will continue to trap the + situation. + +[enum] Fixed issue #52. Updated the local Tcl/Tk headers to + 8.4.20, 8.5.13, and 8.6.4. + +[enum] Fixed issue #45. New feature command [cmd critcl::cconst]. + +[enum] [package critcl::util]: New command [cmd locate] to find a + file across a set of paths, and report an error when not + found. This is for use in autoconf-like header-searches and + similar configuration tests. + +[enum] Modified 'AbortWhenCalledAfterBuild' to dump the entire stack + (info frame!). This should make it easier to determine the + location of the troubling declaration. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3115.inc b/src/vfs/critcl.vfs/doc/include/changes/3115.inc new file mode 100644 index 00000000..227ad30c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3115.inc @@ -0,0 +1,6 @@ +[section {Changes for version 3.1.15}] +[list_begin enumerated] + +[enum] Fixed version number bogosity with [const 3.1.14]. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3116.inc b/src/vfs/critcl.vfs/doc/include/changes/3116.inc new file mode 100644 index 00000000..7ad45543 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3116.inc @@ -0,0 +1,59 @@ +[section {Changes for version 3.1.16}] +[list_begin enumerated] + +[enum] New feature. Extended [cmd critcl::cproc]'s argument handling + to allow arbitrary mixing of required and optional arguments. + +[enum] New feature. + [emph {Potential Incompatibility}]. +[para] Extended [cmd critcl::cproc]'s argument handling to treat an + argument [const args] as variadic if it is the last argument of + the procedure. + +[enum] New feature. Added two introspection commands, + [cmd critcl::has-argtype] and [cmd critcl::has-resulttype]. + These enable a user to test if a specific (named) type + conversion is implemented or not. + +[enum] Added new result type [const Tcl_Obj*0], with alias + [const object0]. The difference to [const Tcl_Obj*] is in + the reference counting. + +[enum] Extended the command [cmd critcl::argtypesupport] with new + optional argument through which to explicitly specify the + identifier for guarding against multiple definitions. + +[enum] Bugfix: Fixed problem with the implementation of issue #54 (See + 3.1.14). Always create the secondary log file. Otherwise + end-of-log handling may break, unconditionally assuming its + existence. + +[enum] Bugfix: Fixed problem with the internal change to the hook + [const HandleDeclAfterBuild]. Corrected the forgotten + [cmd critcl::cconst]. + +[enum] Debugging aid: Added comment holding the name of the result + type when emitting result conversions. + +[enum] Bugfix: Fixed issue #60. Unbundled the package directories + containing multiple packages. All directories under [file lib/] + now contain exactly one package. + +[enum] Bugfix: Fixed issue #62, a few [cmd {dict exists}] commands + operating on a fixed string instead of a variable. + +[enum] Bugfix: Fixed issue #56. Release builders are reminded to run + the tests. + +[enum] Bugfix: Fixed issue #55. For FreeBSD critcl's platform package + now identifies the Kernel ABI version. Initialization of the + cache directory now also uses [cmd platform::identify] for the + default path, instead of [cmd platform::generic]. + +[enum] Bugfix: Fixed issue #58. Simplified the setup and use of + md5. CriTcl now makes use of its own package for md5, using + itself to built it. There is no chicken/egg problem with this + as the [option -pkg] mode used for this does not use md5. That + is limited to mode [term {compile & run}]. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3117.inc b/src/vfs/critcl.vfs/doc/include/changes/3117.inc new file mode 100644 index 00000000..fd9af293 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3117.inc @@ -0,0 +1,65 @@ +[section {Changes for version 3.1.17}] +[list_begin enumerated] + +[enum] Extension: Allow duplicate arg- and result-type definitions if + they are fully identical. + +[enum] Bugfix. The application mishandled the possibility of + identical-named [cmd critcl::tsource]s. Possible because + [cmd critcl::tsource]s can be in subdirectories, a structure + which is [emph not] retained in the assembled package, causing + such files to overwrite each other and at least one lost. Fixed + by adding a serial number to the file names in the assembled + package. + +[enum] Bugfix in the static scanner which made it loose requirement + information. Further added code to generally cleanup results at + the end (removal of duplicates, mainly). + +[enum] Bugfix: Fixed issue #76. + Support installation directories which are not in the [var auto_path]. + Without the patch the installed [cmd critcl] will not find its + own packages and fail. Thank you to + [uri https://github.com/lupylucke {Simon Bachmann}] for the + report and patch, and then his patience with me to getting to + actually apply it. + +[enum] Bugfix: Fixed issue #75. + Extended [cmd critcl::include] to now take multiple paths. + +[enum] Added new compatibility package [package lmap84]. + +[enum] Fixed typos in various documentation files. + +[enum] Fixed bug introduced by commit 86f415dd30 (3.1.16 release). The + separation of [cmd critcl::ccode] into user and work layers + means that location retrieval has to go one more level up to + find the user location. + +[enum] New supporting package [package critcl::cutil]. Provides common + C level facilities useful to packages (assertions, tracing, + memory allocation shorthands). + +[enum] Modified package [package critcl] to make use of the new + tracing facilities to provide tracing of arguments and results + for [cmd critcl::ccommand] and [cmd critcl::cproc] invokations. + +[enum] Modified packages [package critcl] and [package critcl::class] + to provide better function names for (class) method tracing. + Bumped package [package critcl::class] to version 1.0.7. + +[enum] Extended the support package [package critcl::literals] with + limited configurability. It is now able to generate code for + C-level access to the pool without Tcl types (Mode [const c]). + The previously existing functionality is accesssible under mode + [const tcl], which also is the default. Both modes can be used + together. + +[enum] Extended the support package [package critcl::emap] with + limited configurability. It is now able to generate code for + C-level access to the mapping without Tcl types + (Mode [const c]). The previously existing functionality is + accessible under mode [const tcl], which also is the + default. Both modes can be used together. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/3118.inc b/src/vfs/critcl.vfs/doc/include/changes/3118.inc new file mode 100644 index 00000000..f733b68f --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/3118.inc @@ -0,0 +1,100 @@ +[section {Changes for version 3.1.18}] +[list_begin enumerated] + +[enum] Feature (Developer support). Merged pull request #96 from + sebres/main-direct-invoke. Enables direct invokation of the + [file main.tcl] file for starkits from within a dev checkout, + i.e. outside of a starkit, or starpack. + +[enum] Feature. Added channel types to the set of builtin argument and + result types. The argument types are for simple channel access, + access requiring unshared channels, and taking the channel + fully into the C level, away from Tcl. The result type comes in + variants for newly created channels, known channels, and to + return taken channels back to Tcl. The first will register the + returned value in the interpreter, the second assumes that it + already is. + +[enum] Bugfix. Issue #96. Reworked the documentation around the + argument type [type Tcl_Interp*] to make its special status + more visible, explain uses, and call it out from result types + where its use will be necessary or at least useful. + +[enum] Feature. Package [package critcl::class] bumped to version 1.1. + Extended with the ability to create a C API for classes, and + the ability to disable the generation of the Tcl API. + +[enum] Bugfix. Merged pull request #99 from pooryorick/master. Fixes + to the target directory calculations done by the install code. + +[enum] Merged pull request #94 from andreas-kupries/documentation. + A larger documentation cleanup. The main work was done by + pooryorick, followed by tweaks done by myself. + +[enum] Extended the test suite with lots of cases based on the + examples for the various generator packages. IOW the new test + cases replicate/encapsulate the examples and demonstrate that + the packages used by the examples generate working code. + +[enum] Bugfix. Issue #95. Changed the field [const critcl_bytes.s] to + [type {unsigned char*}] to match Tcl's type. Further constified + the field to make clear that read-only usage is the common case + for it. + +[enum] Bugfix/Feature. Package [package critcl::cutil] bumped to + version 0.2. Fixed missing inclusion of header [file string.h] + in [file critcl_alloc.h], needed for [fun memcpy] in macro + [fun STREP]. Added macros [fun ALLOC_PLUS] and [fun STRDUP]. + Moved documentation of [fun STREP...] macros into proper place + (alloc section, not assert). + +[enum] Merged pull request #83 from apnadkarni/vc-fixes. + Removed deprecated -Gs for MSVC builds, and other Windows fixups. + +[enum] Feature. Package [package critcl::iassoc] bumped to version 1.1. + Refactored internals to generate an include header for use by .c files. + This now matches what other generator packages do. + The template file is inlined and removed. + +[enum] Merged pull request #82 from gahr/home-symlink + Modified tests to handle possibility of $HOME a symlink. + +[enum] Merged pull request #81 from gahr/test-not-installed + Modified test support to find uninstalled critcl packages when + running tests. Handles all but critcl::md5. + +[enum] Merged pull request #85 from snoe925/issue-84 + to fix Issue #84 breaking installation on OSX. + +[enum] Merged pull request #87 from apnadkarni/tea-fixes to fix Issue + #86, broken -tea option, generating an incomplete package. + +[enum] Feature. New package [package critcl::callback] providing + C-level functions and data structures to manage callbacks from + C to Tcl. + +[enum] Feature. Package [package critcl::literals] bumped to version + 1.3. Added mode [const +list] enabling the conversion of + multiple literals into a list of their strings. + +[enum] Feature. Package [package critcl::enum] bumped to version 1.1. + Added basic mode handling, supporting [const tcl] (default) and + [const +list] (extension enabling the conversion of multiple + enum values into a list of their strings). + +[enum] Feature. Package [package critcl::emap] bumped to version 1.2. + Extended existing mode handling with [const +list] extension + enabling the conversion of multiple emap values into a list of + their strings. + +[enum] Feature. Extended the set of available types by applying a few + range restrictions to the scalar types ([term int], + [term long], [term wideint], [term double], [term float]). + + [para] Example: [term {int > 0}] is now a viable type name. + + [para] This is actually more limited than the description might + let you believe. + + [para] See the package reference for the details. +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/31181.inc b/src/vfs/critcl.vfs/doc/include/changes/31181.inc new file mode 100644 index 00000000..8270ddb5 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/31181.inc @@ -0,0 +1,17 @@ +[section {Changes for version 3.1.18.1}] +[list_begin enumerated] + +[enum] [strong Attention]: While the overall version (of the bundle) + moves to 3.1.18.1 the versions of packages [package critcl] and + [package critcl::app] are [strong unchanged]. + +[enum] [strong Bugfix] Generally removed a number of 8.5-isms which + slipped into 3.1.18, breaking ability to use it with Tcl 8.4. + +[enum] [strong Bugfix] Corrected broken [strong {build.tcl uninstall}]. + +[enum] [strong Bugfix] Package [package critcl::class] bumped to + version 1.1.1. Fixed partial template substitution breaking + compilation of the generated code. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/312.inc b/src/vfs/critcl.vfs/doc/include/changes/312.inc new file mode 100644 index 00000000..89ccbd44 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/312.inc @@ -0,0 +1,14 @@ +[section {Changes for version 3.1.2}] +[list_begin enumerated] + +[enum] Enhancement. In detail: + +[enum] Extended [cmd critcl::cproc] to be able to handle optional + arguments, in a limited way. This is automatically available to + [package critcl::class] cproc-based methods as well. + +[enum] Bugfix in [cmd lassign] emulation for Tcl 8.4. Properly set + unused variables to the empty string. Bumped version of + emulation package [package lassign84] to 1.0.1. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/313.inc b/src/vfs/critcl.vfs/doc/include/changes/313.inc new file mode 100644 index 00000000..34fccc8d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/313.inc @@ -0,0 +1,20 @@ +[section {Changes for version 3.1.3}] +[list_begin enumerated] + +[enum] Enhancement. In detail: + +[enum] Added new argument type "pstring", for "Pascal String", a + counted string, i.e. a combination of string pointer and string + length. + +[enum] Added new methods [cmd critcl::argtypesupport] and + [cmd ::critcl::argsupport] to define and use additional + supporting code for an argument type, here used by "pstring" + above to define the necessary structure. + +[enum] Semi-bugfixes in the packages [package critcl::class] and + [package critcl::iassoc]. Pragmas for the AS meta data scanner + to ensure that the template files are made part of the package. + Versions bumped to 1.0.4 and 1.0.1 respectively. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/314.inc b/src/vfs/critcl.vfs/doc/include/changes/314.inc new file mode 100644 index 00000000..9e4bb114 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/314.inc @@ -0,0 +1,14 @@ +[section {Changes for version 3.1.4}] +[list_begin enumerated] + +[enum] Bugfix in package [package critcl::class]. Generate a dummy + field in the class structure if the class has no class + variables. Without this change the structure would be empty, + and a number of compilers are not able to handle such a type. + +[enum] Fixed a typo which broke the win64 configuration. + +[enum] Fixed issue #16, a typo in the documentation of command + [cmd critcl::class]. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/315.inc b/src/vfs/critcl.vfs/doc/include/changes/315.inc new file mode 100644 index 00000000..e66e02e9 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/315.inc @@ -0,0 +1,12 @@ +[section {Changes for version 3.1.5}] +[list_begin enumerated] + +[enum] Fixed issue #19. Made the regular expression extracting the + MSVC version number more general to make it work on german + language systems. This may have to be revisited in the future, + for other Windows locales. + +[enum] Fixed issue #20. Made option -tea work on windows, at least in + a unix emulation environment like msys/mingw. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/316.inc b/src/vfs/critcl.vfs/doc/include/changes/316.inc new file mode 100644 index 00000000..b7307ab5 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/316.inc @@ -0,0 +1,28 @@ +[section {Changes for version 3.1.6}] +[list_begin enumerated] + +[enum] Fixed issue #21. While the multi-definition of the stub-table + pointer variables was ok with for all the C linkers seen so far + C++ linkers did not like this at all. Reworked the code to + ensure that this set of variables is generated only once, in + the wrapper around all the pieces to assemble. + +[enum] Fixed issue #22, the handling of the command identifier + arguments of [cmd critcl::ccommand], [cmd critcl::cproc], and + [cmd critcl::cdata]. We now properly allow any Tcl identifier + and generate proper internal C identifiers from them. + +[para] As part of this the signature of command [cmd critcl::name2c] + changed. The command now delivers a list of four values instead + of three. The new value was added at the end. + +[para] Further adapted the implementation of package + [package critcl::class], a user of [cmd critcl::name2c]. + This package is now at version 1.0.6 and requires critcl 3.1.6 + +[para] Lastly fixed the mis-handling of option [option -cname] in + [cmd critcl::ccommand], and [cmd critcl::cproc]. + +[enum] Fixed issue #23. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/317.inc b/src/vfs/critcl.vfs/doc/include/changes/317.inc new file mode 100644 index 00000000..5c36440e --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/317.inc @@ -0,0 +1,16 @@ +[section {Changes for version 3.1.7}] +[list_begin enumerated] + +[enum] Fixed issue #24. Extract and unconditionally display compiler + warnings found in the build log. Prevents users from missing + warnings which, while not causing the build to fail, may + still indicate problems. + +[enum] New feature. Output hook. All non-messaging user output is now + routed through the command [cmd critcl::print], and users are + allowed to override it when using the critcl application-as-package. + +[enum] New feature, by Ashok P. Nadkarni. Platform configurations can + inherit values from configurations defined before them. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/318.inc b/src/vfs/critcl.vfs/doc/include/changes/318.inc new file mode 100644 index 00000000..8dd6961c --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/318.inc @@ -0,0 +1,10 @@ +[section {Changes for version 3.1.8}] +[list_begin enumerated] + +[enum] Fixed issue with package indices generated for Tcl 8.4. + Join the list of commands with semi-colon, not newline. + +[enum] Fixed issue #26 which brought up use-cases I had forgotten to + consider while fixing bug #21 (see critcl 3.1.6). + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/319.inc b/src/vfs/critcl.vfs/doc/include/changes/319.inc new file mode 100644 index 00000000..b7eb7c44 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/319.inc @@ -0,0 +1,31 @@ +[section {Changes for version 3.1.9}] +[list_begin enumerated] + +[enum] Fixed issue #27. Added missing platform definitions for + various alternate linux and OS X targets. + +[enum] Fixed issue #28. Added missing -mXX flags for linking at the + linux-{32,64}-* targets. + +[enum] Fixed issue #29. Replaced the use of raw "cheaders" + information in the processing of "cdefines" with the proper + include directives derived from it. + +[enum] Fixed the issue behind rejected pull request #30 by Andrew + Shadura. Dynamically extract the stubs variable declarations + from the Tcl header files and generate matching variable + definitions for use in the package code. The generated code + will now be always consistent with the headers, even when + critcl's own copy of them is replaced by system headers. + +[enum] Fixed issue #31. Accepted patch by Andrew Shadura, with + changes (comments), for easier integration of critcl with + OS package systems, replacing critcl's copies of Tcl headers + with their own. + +[enum] Fixed issue #32. Merged pull request by Andrew Shadura. + Various typos in documentation and comments. + +[enum] Fixed issue #34. Handle files starting with a dot better. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/32.inc b/src/vfs/critcl.vfs/doc/include/changes/32.inc new file mode 100644 index 00000000..479713ae --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/32.inc @@ -0,0 +1,103 @@ +[include 321.inc] + +[comment {-*- mode: tcl ; fill-column: 90 -*-}] +[section {Changes for version 3.2}] + +[list_begin enumerated] + +[enum] [strong BREAKING] [vset critcl] now requires Tcl 8.6 to be run. + +[para] It also generates Tcl 8.6 extensions by default. + +[para] It is still possible to generates extensions for Tcl 8.4 and 8.5, + properly setting it via [cmd critcl::tcl]. + +[para] [strong ATTENTION] It is planned to completely remove 8.4 and 8.5 + support with [vset critcl] 3.3. + + No date has been set for that release yet. + +[para] All utility packages have their versions and requirements bumped accordingly as + well. + +[enum] [strong BREAKING] [strong {Bug Fix}] + Issue [uri https://github.com/andreas-kupries/critcl/issues/115 #115]. + +[para] Distributions using [syscmd build.tcl] for installation of critcl in their + packaging scripts have to be updated to the changed command signature of + [syscmd build.tcl] install, etc. See the details below. + +[para] Redone the argument handling for [method install], [method uninstall], and + [method targets]. The destination argument is gone. All commands now take options + similar to what is known from GNU [syscmd configure], i.e. + +[list_begin options] +[opt_def --prefix path] +[opt_def --exec-prefix path] +[opt_def --bin-dir path] +[opt_def --lib-dir path] +[opt_def --include-dir path] +[list_end] + +[para] They now also respect the environment variable [var DESTDIR], and the associated + option [option --dest-dir]. + +[para] The [option --prefix] defaults to the topdir from the bin directory holding the + + [syscmd tclsh] running [syscmd build.tcl]. As Tcl command: [example { + file dirname [file dirname [info nameofexecutable]] +}] + +[para] Added a command [method dirs] doing the same argument handling, for debugging. + +[enum] Removed the irrelevant packages [package autoscroll], [package cmdline], + [package dict84], [package lassign84], [package lmap84], [package snit], + [package snitbutton], and [package wikit]. + +[enum] [strong {Documentation Redo}] Issue + [uri https://github.com/andreas-kupries/critcl/issues/116 #116]. + Reworked the documentation to use the system of 4 quadrants. + Reworked the introduction (How To Use Critcl) to be strongly + based on a series of examples. + +[enum] [strong {Bug Fix}] Issue + [uri https://github.com/andreas-kupries/critcl/issues/125 #125]. + Added missing method [method create] in object creation example + of installer documentation. + +[enum] [strong Feature]. Extended [cmd cproc] argument type processing. Now able to + auto-create restricted scalar types. I.e. types derived from [term int], etc. and + limited in the range of allowed values. + +[para] Further able to auto-create restricted list types, i.e. types derived from + [term list] and either limited in length, or in the type of the elements, or both. + +[enum] [strong {Bug Fix / Enhancement}] Issue + [uri https://github.com/andreas-kupries/critcl/issues/118 #118]. Modified + [cmd critcl::cproc] to accept C syntax for arguments, i.e. Trailing comma on + argument names, leading comma on type names, and lone comma characters. + +[enum] [strong {Performance Fix}] for [term {compile & run}] mode. + Issue [uri https://github.com/andreas-kupries/critcl/issues/112 #112]. + +[para] Moved the command activating more precise code location tracking out of package + [package critcl] into package [package critcl::app]. + +[para] Because generating packages ahead of time can bear the performance penalty invoked + by this [strong global] setting. + +[para] Arbitrary libraries and applications using critcl dynamically + ([term {compile & run}]) on the other hand likely cannot, and should not. + +[enum] [strong Fix] + Issue [uri https://github.com/andreas-kupries/critcl/issues/109 #109]. + + Ignore [syscmd clang] suffices when computing the target identifier from a + configuration identifier. + +[enum] [strong Feature]. Bumped package [package critcl::cutil] to version 0.2.1. + Simplified the implementation of macro [cmd ASSERT] by taking the underlying + [fun Tcl_Panic]'s printf ability into account and added a new macro [cmd ASSERT_VA] + exporting the same ability to the user. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/321.inc b/src/vfs/critcl.vfs/doc/include/changes/321.inc new file mode 100644 index 00000000..ffc08884 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/321.inc @@ -0,0 +1,52 @@ +[section {Changes for version 3.2.1 (to come)}] +[list_begin enumerated] + +[enum] As announced with 3.2: +[list_begin enumerated] + +[enum] Removed support for Tcl 8.4 and 8.5. + +[enum] Removed support for the argument types + [type int*], + [type float*], + [type double*], + [type bytearray], + [type rawchar], and + [type rawchar*]. +[list_end] + +[enum] Modified packages to accept operation under Tcl 9. + Bumped package versions appropriately. + Bumped copyrights. + +[para] The [term {How To Adapt Critcl Packages for Tcl 9}] + contains the details relevant to writers of [vset critcl]-based packages. + +[enum] Set different minimum Tcl requirements for the 8.x and 9.x series. + +[para] If no minimum is declared the minimum depends on the Tcl version + used to run the critcl package or application. + +[para] When running under Tcl 9 the default minimum is version [const 9]. + For anything else the new default minimum is [const 8.6]. + +[para] [strong Reminder]: Support for Tcl 8.4 and 8.5 was removed. + +[enum] Made [file ~]-handling portable across the 8.x and 9 boundary + (via [const HOME] environment variable). + +[enum] Bumped embedded [package tclconfig] to version 2.67. Patch supplied by Paul Obermeier. + +[enum] [strong {Bug Fix}] [uri https://github.com/andreas-kupries/critcl/issues/127 #127] +[enum] [strong {Bug Fix}] [uri https://github.com/andreas-kupries/critcl/issues/128 #128] +[enum] [strong {Bug Fix}] [uri https://github.com/andreas-kupries/critcl/issues/129 #129] + +Fixed various typos in the documentation. + +[enum] Reworked internals of [package critcl::cutil]'s tracer to support operation in a + multi-threaded environment. This new mode is also default. The old single-threaded + mode can be (re)activated by defining [const CRITCL_TRACE_NOTHREADS]. + +[para] Package bumped to version 0.4. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changes/X.inc b/src/vfs/critcl.vfs/doc/include/changes/X.inc new file mode 100644 index 00000000..9e7004f2 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changes/X.inc @@ -0,0 +1,10 @@ +[section {Changes for version X}] +[list_begin enumerated] + +[enum] [strong Feature]. Bumped [Package critcl::cutil] to version + 0.2.1. Simplified the implementation of macro [cmd ASSERT] by + taking the underlying Tcl_Panic's printf ability into account + and added a new macro [cmd ASSERT_VA] exporting the same + ability to the user. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/changesX.inc b/src/vfs/critcl.vfs/doc/include/changesX.inc new file mode 100644 index 00000000..9e7004f2 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/changesX.inc @@ -0,0 +1,10 @@ +[section {Changes for version X}] +[list_begin enumerated] + +[enum] [strong Feature]. Bumped [Package critcl::cutil] to version + 0.2.1. Simplified the implementation of macro [cmd ASSERT] by + taking the underlying Tcl_Panic's printf ability into account + and added a new macro [cmd ASSERT_VA] exporting the same + ability to the user. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/class_example.inc b/src/vfs/critcl.vfs/doc/include/class_example.inc new file mode 100644 index 00000000..fe55d958 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_example.inc @@ -0,0 +1,79 @@ + +The example shown below is the specification of queue data structure, +with most of the method implementations and support code omitted to +keep the size down. + +[para] The full implementation can be found in the directory +[file examples/queue] of the critcl source distribution/repository. + +[example { +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::class ; # DSL, easy spec of Tcl class/object commands. +} + +critcl::cheaders util.h + +critcl::class::define ::queuec { + include util.h + + insvariable Tcl_Obj* unget { + List object unget elements + } { + instance->unget = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->unget); + } { + Tcl_DecrRefCount (instance->unget); + } + + insvariable Tcl_Obj* queue { + List object holding the main queue + } { + instance->queue = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->queue); + } { + Tcl_DecrRefCount (instance->queue); + } + + insvariable Tcl_Obj* append { + List object holding new elements + } { + instance->append = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->append); + } { + Tcl_DecrRefCount (instance->append); + } + + insvariable int at { + Index of next element to return from the main queue + } { + instance->at = 0; + } + + support {... queue_peekget, queue_size, etc.} + + method clear {} {...} + method destroy {...} + + method get as queue_peekget 1 + method peek as queue_peekget 0 + + method put {item ...} + + method size {} { + if ((objc != 2)) { + Tcl_WrongNumArgs (interp, 2, objv, NULL); + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, Tcl_NewIntObj (queue_size (instance, NULL, NULL, NULL))); + return TCL_OK; + } + + method unget {item} {...} +} + +package provide queuec 1 +}] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec.inc b/src/vfs/critcl.vfs/doc/include/class_spec.inc new file mode 100644 index 00000000..4a788a90 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec.inc @@ -0,0 +1,10 @@ + +Here we documents all class specification commands available inside of +the class definition script argument of [cmd ::critcl::class::define]. + +[subsection {General configuration}] [include include/class_spec_general.inc] +[subsection {Class lifetime management}] [include include/class_spec_clife.inc] +[subsection {Instance lifetime management}] [include include/class_spec_ilife.inc] +[subsection {Class variables and methods}] [include include/class_spec_cvarm.inc] +[subsection {Instance variables and methods}] [include include/class_spec_ivarm.inc] +[subsection {Context dependent interactions}] [include include/class_spec_cdin.inc] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec_cdin.inc b/src/vfs/critcl.vfs/doc/include/class_spec_cdin.inc new file mode 100644 index 00000000..bb370975 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec_cdin.inc @@ -0,0 +1,52 @@ + +This section documents the various interactions between the +specification commands. While these are are all documented with the +individual commands here they are pulled together to see at a glance. + +[list_begin enum] +[comment {- - -- --- ----- -------- ------------- ---------------------}] + +[enum] If you are using the command [cmd type] to specify an external + C type to use for the instance structure you are subject to + the following constraints and rules: + +[list_begin enum] +[enum] You cannot define your own instance variables. +[enum] You cannot define your own class variables. +[enum] You cannot use [cmd method_introspection]. +[enum] You have to allocate and release the instance structure on your + own, through [cmd constructor] and [cmd destructor] code blocks. +[list_end] +[comment {-- type done}] +[comment {- - -- --- ----- -------- ------------- ---------------------}] + +[enum] If you declare class variables you are subject to the + following constraints and rules: + +[list_begin enum] +[enum] You cannot use [cmd type]. +[enum] The system generates an instance variable [const class] for + you, which points from instance to class structure. This makes + you also subject to the rules below, for instance variables. +[list_end] +[comment {-- class variable done}] +[comment {- - -- --- ----- -------- ------------- ---------------------}] + +[enum] If you declare instance variables (possibly automatic, see + above) you are subject to following constraints and rules: + +[list_begin enum] +[enum] You cannot use [cmd type]. +[enum] The system generates and manages an instance variable + [const cmd] for you, which holds the Tcl_Command token + of the instance command. +[enum] The system generates an instance method [const destroy] for + you. +[enum] The system manages allocation and release of the instance + structure for you. You have to care only about the instance + variables themselves. +[list_end] +[comment {-- instance variable done}] +[comment {- - -- --- ----- -------- ------------- ---------------------}] + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec_clife.inc b/src/vfs/critcl.vfs/doc/include/class_spec_clife.inc new file mode 100644 index 00000000..f2fc72ea --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec_clife.inc @@ -0,0 +1,77 @@ + +[list_begin definitions] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd classconstructor] [arg body]] + +This command specifies a C code block surrounding the initialization +of the class variables, i.e. the fields of the class structure. + +[emph Note] that allocation and release of the class structure itself +is done by the system andf not the responsibility of the user. + +[para] For the initialization (and release) of a class variable it is +recommended to use the [arg constructor] and [arg destructor] +arguments of the variable's definition (See command +[cmd classvariable]) for this instead of using a separate +[cmd classconstructor]. + +[para] This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate. + +[para] The C code blocks of multiple calls (including the constructors +of classvariable definitions) are executed in order of specification. + +[para] The result of the command is the empty string. + +[para] The C code in [arg body] has access to the following +environment: + +[list_begin definitions] + +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure will be associated with. It enables the generation +of a Tcl error message should construction fail. + +[def [var class]] Pointer to the class structure to initialize. + +[def error] A C code label the constructor can jump to should it have +to signal a construction failure. It is the responsibility of the +constructor to release any variables already initialized before +jumping to this label. This also why the 'execution in order of +specification' is documented and can be relied on. It gives us the +knowledge which other constructors have already been run and +initialized what other fields. + +[list_end] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd classdestructor] [arg body]] + +This command specifies a C code block surrounding the release of the +class variables, i.e. the fields of the class structure. + +[emph Note] that allocation and release of the class structure itself +is done by the system and not the responsibility of the user. + +[para] For the initialization (and release) of a class variable it is +recommended to use the [arg constructor] and [arg destructor] +arguments of the variable's definition (See command +[cmd classvariable]) for this instead of using a separate +[cmd classconstructor]. + +[para] This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate. + +[para] The C code blocks of multiple calls (including the constructors +of class variable definitions) are executed in order of specification. + +[para] The result of the command is the empty string. + +[para] The C code in [arg body] has access to the same +environment as the class constructor code blocks. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec_cvarm.inc b/src/vfs/critcl.vfs/doc/include/class_spec_cvarm.inc new file mode 100644 index 00000000..76c89066 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec_cvarm.inc @@ -0,0 +1,112 @@ + +[list_begin definitions] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd classvariable] [arg ctype] [arg name] [opt [arg comment]] \ + [opt [arg constructor]] [opt [arg destructor]]] + +This command specifies a field in the class structure of the class. + +Multiple fields can be specified, and are saved in the order +specified. + +[para] [emph Attention:] Specification of a class variable precludes +the use of an external C [cmd type] for the instance structure. + +[para] [emph Attention:] Specification of a class variable +automatically causes the definition of an instance variable named +[const class], pointing to the class structure. + +[para] Beyond the basic [arg name] and C type of the new variable the +definition may also contain a [arg comment] describing it, and C code +blocks to initialize and release the variable. + +These are effectively local forms of the commands +[cmd classconstructor] and [cmd classdestructor]. Please read their +descriptions for details regarding the C environment available to the +code. + +[para] The comment, if specified will be embedded into the generated C +code for easier cross-referencing from generated [file .c] file to +class specification. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd classmethod] [arg name] [method command] [arg arguments] \ + [arg body]] + +This command specifies a class method and the C code block +implementing its functionality. This is the first of three forms. The +method is specified like a [cmd critcl::ccommand], with a fixed set of +C-level arguments. The [arg body] has to perform everything +(i.e. argument extraction, checking, result return, and of course the +actual functionality) by itself. + +[para] For this the [arg body] has access to + +[list_begin definitions] +[def [var class]] Pointer to the class structure. +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure is associated with +[def [var objc]] The number of method arguments. +[def [var objv]] The method arguments, as C array of Tcl_Obj pointers. +[list_end] + +The [arg arguments] of the definition are only a human readable form +of the method arguments and syntax and are not used in the C code, +except as comments put into the generated code. Again, it is the +responsibility of the [arg body] to check the number of arguments, +extract them, check their types, etc. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd classmethod] [arg name] [method proc] [arg arguments] \ + [arg resulttype] [arg body]] + +This command specifies a class method and the C code block +implementing its functionality. This is the second of three forms. The +method is specified like a [cmd critcl::cproc]. + +Contrary to the first variant here the [arg arguments] are computer +readable, expected to be in the same format as the [arg arguments] of +[cmd critcl::cproc]. The same is true for the [arg resulttype]. + +The system automatically generates a wrapper doing argument checking +and conversion, and result conversion, like for [cmd critcl::cproc]. + +[para] The [arg body] has access to + +[list_begin definitions] +[def [var class]] Pointer to the class structure. +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure is associated with +[def ...] All [arg arguments] under their specified names and C types +as per their definition. +[list_end] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd classmethod] [arg name] [method as] [arg funname] \ + [opt [arg arg]...]] + +This command specifies a class method and the C code block +implementing its functionality. This is the third and last of three +forms. + +[para] The class method is implemented by the external function +[arg funname], i.e. a function which is declared outside of the class +code itself, or in a [cmd support] block. + +[para] It is assumed that the first four arguments of that function +represent the parameters + +[list_begin definitions] +[def [var class]] Pointer to the class structure. +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure is associated with +[def [var objc]] The number of method arguments. +[def [var objv]] The method arguments, as C array of Tcl_Obj pointers. +[list_end] + +Any additional arguments specified will be added after these and are +passed into the C code as is, i.e. are considered to be C expressions. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec_general.inc b/src/vfs/critcl.vfs/doc/include/class_spec_general.inc new file mode 100644 index 00000000..8358ce03 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec_general.inc @@ -0,0 +1,56 @@ + +[list_begin definitions] +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd include] [arg path]] + +This command specifies the path of a header file to include within the +code generated for the class. This is separate from the [cmd support] +because the generated include directives will be put at the very +beginning of the generated code. This is done to allow the use of the +imported declarations within the instance type, and elsewhere. + +[para] [vset cumulative] + +It is of course possible to not use this command at all, for classes +not making use of external definitions. + +[para] The result is the empty string. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd support] [arg code]] + +This command specifies supporting C code, i.e. any definitions (types, +functions, etc.) needed by the [emph whole] class and not fitting into +class- and instance-methods. The code is embedded at global level, +outside of any function or other definition. + +[para] [vset cumulative] + +It is of course possible to not use this command at all, for classes +not requiring supporting code. + +[para] The result of the command is the empty string. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd type] [arg name]] + +This command specifies the name of an external C type to be used as +the type of the instance structure. + +[para] Initialization and release of the structure with the given type +are the responsibility of the user, through [cmd constructor] and +[cmd destructor] code fragments. + +[para][emph Attention:] Using this command precludes the use of +regular class- and instance variables. It further precludes the use of +[cmd method-introspection] as well, as this make use of generated +instance-variables. + +[para] If class- and/or instance-variable have to be used in +conjunction with an external C type, simply create and use a class- or +instance-variable with that type. + +[para] The result of the command is the empty string. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec_ilife.inc b/src/vfs/critcl.vfs/doc/include/class_spec_ilife.inc new file mode 100644 index 00000000..819545fa --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec_ilife.inc @@ -0,0 +1,112 @@ + +[list_begin definitions] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd constructor] [arg body] [opt [arg postbody]]] + +This command specifies a C code block surrounding the initialization +of the instance variables, i.e. the fields of the instance structure. + +[emph Note] that allocation and release of the instance structure +itself is done by the system and not the responsibility of the user. + +[emph {On the other hand}], if an external [cmd type] was specified +for the instance structure, then instance variables are not possible, +and the system has no knowledge of the type's structure. In that case +it is the responsibility of the [arg body] to allocate and free the +structure itself too. + +[para] For the initialization (and release) of an instance variable it +is recommended to use the [arg constructor] and [arg destructor] +arguments of the variable's definition (See command [cmd insvariable]) +for this instead of using a separate [cmd constructor]. + +[para] This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate. + +[para] The C code blocks of multiple calls (including the constructors +of instance variable definitions) are executed in order of specification. + +[para] The result of the command is the empty string. + +[para] The C code in [arg body] has access to the following +environment: + +[list_begin definitions] + +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure will be associated with. It enables the generation +of a Tcl error message should construction fail. + +[def [var instance]] Pointer to the instance structure to initialize. + +[def error] A C code label the constructor can jump to should it have +to signal a construction failure. It is the responsibility of the +constructor to release any variables already initialized before +jumping to this label. This also why the 'execution in order of +specification' is documented and can be relied on. It gives us the +knowledge which other constructors have already been run and +initialized what other fields. + +[list_end] + +[para] The C code in [arg postbody] is responsible for construction +actions to be done after the primary construction was done and the +Tcl-level instance command was successfully created. It has access to +a slightly different environment: + +[list_begin definitions] + +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure will be associated with. It enables the generation +of a Tcl error message should construction fail. + +[def [var instance]] Pointer to the instance structure to initialize. + +[def [var cmd]] The Tcl_Command token of the Tcl-level instance +command. + +[def [var fqn]] The fully qualified name of the instance command, +stored in a Tcl_Obj*. + +[list_end] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd destructor] [arg body]] + +This command specifies a C code block surrounding the release of the +instance variables, i.e. the fields of the instance structure. + +[emph Note] that allocation and release of the instance structure +itself is done by the system and not the responsibility of the user. + +[emph {On the other hand}], if an external [cmd type] was specified +for the instance structure, then instance variables are not possible, +and the system has no knowledge of the type's structure. In that case +it is the responsibility of the [arg body] to allocate and free the +structure itself too. + +[para] For the initialization (and release) of an instance variable it +is recommended to use the [arg constructor] and [arg destructor] +arguments of the variable's definition (See command [cmd insvariable]) +for this instead of using a separate [cmd constructor]. + +[para] This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate. + +[para] The C code blocks of multiple calls (including the constructors +of instance variable definitions) are executed in order of specification. + +[para] The result of the command is the empty string. + +[para] The C code in [arg body] has access to the following +environment: + +[list_begin definitions] +[def [var instance]] Pointer to the instance structure to release. +[list_end] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/class_spec_ivarm.inc b/src/vfs/critcl.vfs/doc/include/class_spec_ivarm.inc new file mode 100644 index 00000000..8a4b85f1 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/class_spec_ivarm.inc @@ -0,0 +1,126 @@ + +[list_begin definitions] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd insvariable] [arg ctype] [arg name] [opt [arg comment]] \ + [opt [arg constructor]] [opt [arg destructor]]] + +This command specifies a field in the instance structure of the class. + +Multiple fields can be specified, and are saved in the order +specified. + +[para] [emph Attention:] Specification of an instance variable +precludes the use of an external C [cmd type] for the instance +structure. + +[para] [emph Attention:] Specification of an instance variable +automatically causes the definition of an instance variable of type +[const Tcl_Command], and named [const cmd], holding the token of the +instance command, and the definition of an instance method named +[const destroy]. This implicit instance variable is managed by the +system. + +[para] Beyond the basic [arg name] and C type of the new variable the +definition may also contain a [arg comment] describing it, and C code +blocks to initialize and release the variable. + +These are effectively local forms of the commands [cmd constructor] +and [cmd destructor]. Please read their descriptions for details +regarding the C environment available to the code. + +[para] The comment, if specified will be embedded into the generated C +code for easier cross-referencing from generated [file .c] file to +class specification. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd method] [arg name] [method command] [arg arguments] \ + [arg body]] + +This command specifies an instance method and the C code block +implementing its functionality. This is the first of three forms. The +method is specified like a [cmd critcl::ccommand], with a fixed set of +C-level arguments. The [arg body] has to perform everything +(i.e. argument extraction, checking, result return, and of course the +actual functionality) by itself. + +[para] For this the [arg body] has access to + +[list_begin definitions] +[def [var instance]] Pointer to the instance structure. +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure is associated with +[def [var objc]] The number of method arguments. +[def [var objv]] The method arguments, as C array of Tcl_Obj pointers. +[list_end] + +The [arg arguments] of the definition are only a human readable form +of the method arguments and syntax and are not used in the C code, +except as comments put into the generated code. Again, it is the +responsibility of the [arg body] to check the number of arguments, +extract them, check their types, etc. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd method] [arg name] [method proc] [arg arguments] \ + [arg resulttype] [arg body]] + +This command specifies an instance method and the C code block +implementing its functionality. This is the second of three +forms. The method is specified like a [cmd critcl::cproc]. + +Contrary to the first variant here the [arg arguments] are computer +readable, expected to be in the same format as the [arg arguments] of +[cmd critcl::cproc]. The same is true for the [arg resulttype]. + +The system automatically generates a wrapper doing argument checking +and conversion, and result conversion, like for [cmd critcl::cproc]. + +[para] The [arg body] has access to + +[list_begin definitions] +[def [var instance]] Pointer to the instance structure. +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure is associated with +[def ...] All [arg arguments] under their specified names and C types +as per their definition. +[list_end] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd method] [arg name] [method as] [arg funname] \ + [opt [arg arg]...]] + +This command specifies an instance method and the C code block +implementing its functionality. This is the third and last of three +forms. + +[para] The instance method is implemented by the external function +[arg funname], i.e. a function which is declared outside of the instance +code itself, or in a [cmd support] block. + +[para] It is assumed that the first four arguments of that function +represent the parameters + +[list_begin definitions] +[def [var instance]] Pointer to the instance structure. +[def [var interp]] Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure is associated with +[def [var objc]] The number of method arguments. +[def [var objv]] The method arguments, as C array of Tcl_Obj pointers. +[list_end] + +Any additional arguments specified will be added after these and are +passed into the C code as is, i.e. are considered to be C expressions. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd method_introspection]] + +This command generates one class- and one instance-method both of +which will return a list of the instance methods of the class, and +supporting structures, like the function to compute the information, +and a class variable caching it. + +[para] The two methods and the class variable are all named +[const methods]. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/concepts.inc b/src/vfs/critcl.vfs/doc/include/concepts.inc new file mode 100644 index 00000000..46c59e92 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/concepts.inc @@ -0,0 +1,14 @@ +[comment { + CriTcl concepts necessary to understand the various commands. +}] +[subsection {Modes Of Operation/Use}] [include include/modes.inc] + +[para] Regarding the caching of results please read the section about +the [sectref {Result Cache}] fore more details. + +[subsection {Runtime Behaviour}] [include include/runtime.inc] +[subsection {File Mapping}] [include include/mapping.inc] +[subsection {Result Cache}] [include include/rcache.inc] +[subsection {Preloading functionality}] [include include/preload.inc] +[subsection {Configuration Internals}] [include include/iconfig.inc] +[subsection {Stubs Tables}] [include include/stubs.inc] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc.inc b/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc.inc new file mode 100644 index 00000000..e59e2ec9 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc.inc @@ -0,0 +1,162 @@ + +[para] To get around this limitation the commands in this section +enable users of [package critcl] to extend the set of argument and +result types understood by [cmd critcl::cproc]. In other words, they +allow them to define their own, custom, types. + +[list_begin definitions] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::has-resulttype] [arg name]] + +This command tests if the named result-type is known or not. + +It returns a boolean value, [const true] if the type is known and +[const false] otherwise. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::resulttype] [arg name] [arg body] [opt [arg ctype]]] + +This command defines the result type [arg name], and associates it +with the C code doing the conversion ([arg body]) from C to Tcl. + +The C return type of the associated function, also the C type of the +result variable, is [arg ctype]. This type defaults to [arg name] if +it is not specified. + +[para] If [arg name] is already declared an error is thrown. + +[emph Attention!] The standard result type [const void] is special as +it has no accompanying result variable. This cannot be expressed +by this extension command. + +[para] The [arg body]'s responsibility is the conversion of the +functions result into a Tcl result and a Tcl status. The first has to +be set into the interpreter we are in, and the second has to be +returned. + +[para] The C code of [arg body] is guaranteed to be called last in the +wrapper around the actual implementation of the [cmd cproc] in +question and has access to the following environment: + +[list_begin definitions] +[def [var interp]] A Tcl_Interp* typed C variable referencing the + interpreter the result has to be stored into. +[def [var rv]] The C variable holding the result to convert, of type + [arg ctype]. +[list_end] + +As examples here are the definitions of two standard result types: + +[example { + resulttype int { + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; + } + + resulttype ok { + /* interp result must be set by cproc body */ + return rv; + } int +}] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::resulttype] [arg name] [method =] [arg origname]] + +This form of the [cmd resulttype] command declares [arg name] as an +alias of result type [arg origname], which has to be defined +already. If this is not the case an error is thrown. + + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::has-argtype] [arg name]] + +This command tests if the named argument-type is known or not. + +It returns a boolean value, [const true] if the type is known and +[const false] otherwise. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::argtype] [arg name] [arg body] [opt [arg ctype]] [opt [arg ctypefun]]] + +This command defines the argument type [arg name], and associates it +with the C code doing the conversion ([arg body]) from Tcl to C. + +[arg ctype] is the C type of the variable to hold the conversion result +and [arg ctypefun] is the type of the function argument itself. +Both types default to [arg name] if they are the empty string or are not +provided. + +[para] If [arg name] is already declared an error is thrown. + +[para] [arg body] is a C code fragment that converts a Tcl_Obj* into a +C value which is stored in a helper variable in the underlying function. + +[para] [arg body] is called inside its own code block to isolate local +variables, and the following items are in scope: + +[list_begin definitions] +[def [var interp]] A variable of type [const Tcl_Interp*] which is the + interpreter the code is running in. +[def [const @@]] A placeholder for an expression that evaluates to the + [const Tcl_Obj*] to convert. + +[def [const @A]] A placeholder for the name of the variable to store the + converted argument into. +[list_end] + +As examples, here are the definitions of two standard argument types: + +[example { + argtype int { + if (Tcl_GetIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR; + } + + argtype float { + double t; + if (Tcl_GetDoubleFromObj(interp, @@, &t) != TCL_OK) return TCL_ERROR; + @A = (float) t; + } +}] + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[call [cmd ::critcl::argtype] [arg name] [method =] [arg origname]] + +This form of the [cmd argtype] command declares [arg name] as an alias +of argument type [arg origname], which has to be defined already. If +this is not the case an error is thrown. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argtypesupport] [arg name] [arg code] [opt [arg guard]]] + +This command defines a C code fragment for the already defined +argument type [arg name] which is inserted before all functions +using that type. Its purpose is the definition of any supporting C +types needed by the argument type. + +If the type is used by many functions the system ensures that only the +first of the multiple insertions of the code fragment is active, and +the others disabled. + +The guard identifier is normally derived from [arg name], but can also +be set explicitly, via [arg guard]. This latter allows different +custom types to share a common support structure without having to +perform their own guarding. + +[comment ---------------------------------------------------------------------] +[call [cmd ::critcl::argtyperelease] [arg name] [arg code]] + +This command defines a C code fragment for the already defined +argument type [arg name] which is inserted whenever the worker +function of a [cmd critcl::cproc] returns to the shim. It is the +responsibility of this fragment to unconditionally release any +resources the [cmd critcl::argtype] conversion code allocated. + +An example of this are the [emph variadic] types for the support of +the special, variadic [arg args] argument to [cmd critcl::cproc]'s. +They allocate a C array for the collected arguments which has to be +released when the worker returns. This command defines the C code +for doing that. + +[comment {- - -- --- ----- -------- ------------- ---------------------}] +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc1.inc b/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc1.inc new file mode 100644 index 00000000..fe80855b --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc1.inc @@ -0,0 +1,6 @@ + +While the [cmd critcl::cproc] command understands the most common C +types (see section [sectref {Embedded C Code}]), sometimes this is not +enough. + +[include api_extcproc.inc] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc2.inc b/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc2.inc new file mode 100644 index 00000000..11c07f57 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/api_extcproc2.inc @@ -0,0 +1,5 @@ + +While the [cmd critcl::cproc] command understands the most common C +types (as per the previous 2 sections), sometimes this is not enough. + +[include api_extcproc.inc] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/api_stdat_cproc.inc b/src/vfs/critcl.vfs/doc/include/cproc/api_stdat_cproc.inc new file mode 100644 index 00000000..c2d8aae4 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/api_stdat_cproc.inc @@ -0,0 +1,369 @@ +[comment {-*- mode: tcl ; fill-column: 90 -*-}] +[comment { + Standard argument types for use with cproc and cclass methods. +}] + + +Before going into the details first a quick overview: + +[include atypes_table.inc] + +And now the details: + +[list_begin definitions] +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] + +[def Tcl_Interp*] + +[strong Attention]: This is a [strong special] argument type. It can +[strong only] be used by the [strong first] argument of a function. +Any other argument using it will cause critcl to throw an error. + +[para] When used, the argument will contain a reference to the current +interpreter that the function body may use. Furthermore the argument +will [strong not] be an argument of the Tcl command for the function. + +[para] This is useful when the function has to do more than simply +returning a value. Examples would be setting up error messages on +failure, or querying the interpreter for variables and other data. + +[def Tcl_Obj*] +[def object] + +The function takes an argument of type [type Tcl_Obj*]. +No argument checking is done. +The Tcl level word is passed to the argument as-is. + +Note that this value must be treated as [strong read-only] (except for +hidden changes to its intrep, i.e. [term shimmering]). + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def pstring] + +The function takes an argument of type [type critcl_pstring] +containing the original [type Tcl_Obj*] reference of the Tcl argument, +plus the length of the string and a pointer to the character array. + +[example { +typedef struct critcl_pstring { + Tcl_Obj* o; + const char* s; + int len; +} critcl_pstring; +}] + +Note the [strong const]. The string is [strong read-only]. Any +modification can have arbitrary effects, from pulling out the rug +under the script because of string value and internal representation +not matching anymore, up to crashes anytime later. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def list] +[def {[]}] +[def {[*]}] + +The function takes an argument of type [type critcl_list] containing the original [type Tcl_Obj*] +reference of the Tcl argument, plus the length of the Tcl list and a pointer to the array of the +list elements. + +[example { +typedef struct critcl_list { + Tcl_Obj* o; + Tcl_Obj* const* v; + int c; +} critcl_list; +}] + +The Tcl argument must be convertible to [type List], an error is thrown otherwise. + +[para] Note the [strong const]. The list is [strong read-only]. Any modification can have arbitrary +effects, from pulling out the rug under the script because of string value and internal +representation not matching anymore, up to crashes anytime later. + +[para] Further note that the system understands a number of more complex syntactical forms which all +translate into forms of lists under the hood, as described by the following points. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def {[N]}] + +A [term list] type with additional checks limiting the length to [const N], an integer +number greater than zero. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def {[]type}] +[def {type[]}] + +A [term list] type whose elements all have to be convertible for [term type]. All known +types, including user-defined, are allowed, except for [type list] and derivates. In other +words, multi-dimensional lists are not supported. + +[para] The function will take a structure argument of the general form + +[example { +typedef struct critcl_list_... { + Tcl_Obj* o; + int c; + (Ctype)* v; +} critcl_list_...; +}] + +where [const (Ctype)] represents the C type for values of type [type type]. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def {[N]type}] +[def {type[N]}] + +These are [type list] types combining the elements of [example {[N]}] and +[example {[]type}]. + +[para] As an example, the specification of [example {int[3] a}] describes argument [arg a] +as a list of exactly 3 elements, all of which have to be of type [type int]. + +[para] Note that this example can also be written in the more C-like form of +[example {int a[3]}]. The system will translate this internally to the first shown form. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def bytes] + +This is the [emph new] and usable [type ByteArray] type. + +[para] The function takes an argument of type [type critcl_bytes] +containing the original [type Tcl_Obj*] reference of the Tcl argument, +plus the length of the byte array and a pointer to the byte data. + +[example { +typedef struct critcl_bytes { + Tcl_Obj* o; + const unsigned char* s; + int len; +} critcl_list; +}] + +The Tcl argument must be convertible to [type ByteArray], an error is +thrown otherwise. + +[para] Note the [strong const]. The bytes are [strong read-only]. Any +modification can have arbitrary effects, from pulling out the rug +under the script because of string value and internal representation +not matching anymore, up to crashes anytime later. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def char*] + +The function takes an argument of type [type {const char*}]. +The string representation of the Tcl argument is passed in. + +[para] Note the [strong const]. The string is [strong read-only]. Any +modification can have arbitrary effects, from pulling out the rug +under the script because of string value and internal representation +not matching anymore, up to crashes anytime later. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def double] + +The function takes an argument of type [type double]. + +The Tcl argument must be convertible to [type Double], an error is thrown otherwise. + +[def {double > N}] +[def {double >= N}] +[def {double < N}] +[def {double <= N}] + +These are variants of [term double] above, restricting the argument value to the shown relation. + +An error is thrown for Tcl arguments outside of the specified range. + +[para] The limiter [arg N] has to be a constant floating point value. + +[para] It is possible to use multiple limiters. + +For example [term {double > A > B <= C}]. + +The system will fuse them to a single upper/lower limit (or both). + +[para] The system will reject limits describing an empty range of values, or a range containing only +a single value. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def float] + +The function takes an argument of type [type float]. + +The Tcl argument must be convertible to [type Double], an error is thrown otherwise. + +[def {float > N}] +[def {float >= N}] +[def {float < N}] +[def {float <= N}] + +These are variants of [term float] above, restricting the argument value to the shown relation. + +An error is thrown for Tcl arguments outside of the specified range. + +[para] The limiter [arg N] has to be a constant floating point value. + +[para] It is possible to use multiple limiters. + +For example [term {float > A > B <= C}]. + +The system will fuse them to a single upper/lower limit (or both). + +[para] The system will reject limits describing an empty range of values, or a range containing only +a single value. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def boolean] +[def bool] + +The function takes an argument of type [type int]. + +The Tcl argument must be convertible to [type Boolean], an error is +thrown otherwise. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def channel] + +The function takes an argument of type [type Tcl_Channel]. + +The Tcl argument must be convertible to type [type Channel], an error +is thrown otherwise. + +The channel is further assumed to be [strong {already registered}] +with the interpreter. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def unshared-channel] + +This type is an extension of [type channel] above. + +All of the information above applies. + +[para] Beyond that the channel must not be shared by multiple +interpreters, an error is thrown otherwise. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def take-channel] + +This type is an extension of [type unshared-channel] above. + +All of the information above applies. + +[para] Beyond that the code removes the channel from the current +interpreter without closing it, and disables all pre-existing event +handling for it. + +[para] With this the function takes full ownership of the channel in +question, taking it away from the interpreter invoking it. It is then +responsible for the lifecycle of the channel, up to and including +closing it. + +[para] Should the system the function is a part of wish to return +control of the channel back to the interpeter it then has to use the +result type [type return-channel]. This will undo the registration +changes made by this argument type. + +[strong Note] however that the removal of pre-existing event handling +done here cannot be undone. + +[para] [strong Attention] Removal from the interpreter without closing +the channel is effected by incrementing the channel's reference count +without providing an interpreter, before decrementing the same for the +current interpreter. This leaves the overall reference count intact +without causing Tcl to close it when it is removed from the +interpreter structures. At this point the channel is effectively a +globally-owned part of the system not associated with any interpreter. + +[para] The complementary result type then runs this sequence in +reverse. And if the channel is never returned to Tcl either the +function or the system it is a part of have to unregister the global +reference when they are done with it. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def int] + +The function takes an argument of type [type int]. + +The Tcl argument must be convertible to [type Int], an error is thrown otherwise. + +[def {int > N}] +[def {int >= N}] +[def {int < N}] +[def {int <= N}] + +These are variants of [term int] above, restricting the argument value to the shown +relation. + +An error is thrown for Tcl arguments outside of the specified range. + +[para] The limiter [arg N] has to be a constant integer value. + +[para] It is possible to use multiple limiters. + +For example [term {int > A > B <= C}]. + +The system will fuse them to a single upper/lower limit (or both). + +[para] The system will reject limits describing an empty range of values, or a range +containing only a single value. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def long] + +The function takes an argument of type [type {long int}]. + +The Tcl argument must be convertible to [type Long], an error is thrown otherwise. + +[def {long > N}] +[def {long >= N}] +[def {long < N}] +[def {long <= N}] + +These are variants of [term long] above, restricting the argument value to the shown +relation. + +An error is thrown for Tcl arguments outside of the specified range. + +[para] The limiter [arg N] has to be a constant integer value. + +[para] It is possible to use multiple limiters. + +For example [term {long > A > B <= C}]. + +The system will fuse them to a single upper/lower limit (or both). + +[para] The system will reject limits describing an empty range of values, or a range +containing only a single value. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def wideint] + +The function takes an argument of type [type Tcl_WideInt]. + +The Tcl argument must be convertible to [type WideInt], an error is thrown otherwise. + +[def {wideint > N}] +[def {wideint >= N}] +[def {wideint < N}] +[def {wideint <= N}] + +These are variants of [term wideint] above, restricting the argument value to the shown +relation. + +An error is thrown for Tcl arguments outside of the specified range. + +[para] The limiter [arg N] has to be a constant integer value. + +[para] It is possible to use multiple limiters. + +For example [term {wideint > A > B <= C}]. + +The system will fuse them to a single upper/lower limit (or both). + +[para] The system will reject limits describing an empty range of values, or a range +containing only a single value. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def void*] + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/api_stdrt_cproc.inc b/src/vfs/critcl.vfs/doc/include/cproc/api_stdrt_cproc.inc new file mode 100644 index 00000000..d7ca8c2d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/api_stdrt_cproc.inc @@ -0,0 +1,172 @@ +[comment { + Standard result types for use with + cproc and cconst. +}] + +Before going into the details first a quick overview: + +[include rtypes_table.inc] + +And now the details: + +[list_begin definitions] +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def Tcl_Obj*] +[def object] + +If the returned [type Tcl_Obj*] is [const NULL], the Tcl return code +is [const TCL_ERROR] and the function should [uri \ + https://www.tcl-lang.org/man/tcl/TclLib/SetResult.htm \ + {set an error mesage}] +as the interpreter result. Otherwise, the returned [type Tcl_Obj*] is +set as the interpreter result. + +[para] Note that setting an error message requires the function body +to have access to the interpreter the function is running in. See the +argument type [type Tcl_Interp*] for the details on how to make that +happen. + +[para] Note further that the returned [type Tcl_Obj*] should have a +reference count greater than [const 0]. This is because the converter +decrements the reference count to release possession after setting the +interpreter result. It assumes that the function incremented the +reference count of the returned [type Tcl_Obj*]. + +If a [type Tcl_Obj*] with a reference count of [const 0] were +returned, the reference count would become [const 1] when set as the +interpreter result, and immediately thereafter be decremented to +[const 0] again, causing the memory to be freed. The system is then +likely to crash at some point after the return due to reuse of the +freed memory. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def Tcl_Obj*0] +[def object0] + +Like [const Tcl_Obj*] except that this conversion assumes that the +returned value has a reference count of [const 0] and +[emph {does not}] decrement it. Returning a value whose reference +count is greater than [const 0] is therefore likely to cause a memory +leak. + +[para] Note that setting an error message requires the function body +to have access to the interpreter the function is running in. See the +argument type [type Tcl_Interp*] for the details on how to make that +happen. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def new-channel] + +A [type String] Tcl_Obj holding the name of the returned +[type Tcl_Channel] is set as the interpreter result. + +The channel is further assumed to be [strong new], and therefore +registered with the interpreter to make it known. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def known-channel] + +A [type String] Tcl_Obj holding the name of the returned +[type Tcl_Channel] is set as the interpreter result. + +The channel is further assumed to be [strong {already registered}] +with the interpreter. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def return-channel] + +This type is a variant of [type new-channel] above. + +It varies slightly from it in the registration sequence to be properly +complementary to the argument type [type take-channel]. + + +A [type String] Tcl_Obj holding the name of the returned +[type Tcl_Channel] is set as the interpreter result. + +The channel is further assumed to be [strong new], and therefore +registered with the interpreter to make it known. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def char*] +[def vstring] + +A [type String] Tcl_Obj holding a [strong copy] of the returned +[type char*] is set as the interpreter result. If the value is +allocated then the function itself and the extension it is a part of +are responsible for releasing the memory when the data is not in use +any longer. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def {const char*}] + +Like [const char*] above, except that the returned string is +[const const]-qualified. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def string] +[def dstring] + +The returned [type char*] is directly set as the interpreter result +[strong {without making a copy}]. Therefore it must be dynamically +allocated via [fun Tcl_Alloc]. Release happens automatically when the +Interpreter finds that the value is not required any longer. + + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def double] +[def float] + +The returned [type double] or [type float] is converted to a [type Double] +Tcl_Obj and set as the interpreter result. + + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def boolean] +[def bool] + +The returned [type int] value is converted to an [type Int] Tcl_Obj and set as +the interpreter result. + + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def int] + +The returned [type int] value is converted to an [type Int] Tcl_Obj and set as +the interpreter result. + + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def long] + +The returned [type {long int}] value is converted to a [type Long] Tcl_Obj and +set as the interpreter result. + + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def wideint] + +The returned [type Tcl_WideInt] value is converted to a [type WideInt] Tcl_Obj +and set as the interpreter result. + + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def ok] + +The returned [type int] value becomes the Tcl return code. + +The interpreter result is left untouched and can be set by the +function if desired. Note that doing this requires the function body +to have access to the interpreter the function is running in. See the +argument type [type Tcl_Interp*] for the details on how to make that +happen. + +[comment {% % %% %%% %%%%% %%%%%%%% %%%%%%%%%%%%%}] +[def void] + +The function does not return a value. + +The interpreter result is left untouched and can be set by the function if +desired. + +[list_end] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/atypes_table.inc b/src/vfs/critcl.vfs/doc/include/cproc/atypes_table.inc new file mode 100644 index 00000000..2eed7d08 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/atypes_table.inc @@ -0,0 +1,50 @@ +[comment { + Table of the standard argument types, for a quick overview + of the names, associated C types, behaviour and limits. +}] +[example_begin] +CriTcl type | C type | Tcl type | Notes +---------------- | -------------- | --------- | ------------------------------ +Tcl_Interp* | Tcl_Interp* | n/a | [strong Special], only first +---------------- | -------------- | --------- | ------------------------------ +Tcl_Obj* | Tcl_Obj* | Any | [strong Read-only] +object | | | Alias of [type Tcl_Obj*] above +list | critcl_list | List | [strong Read-only] +[lb][rb], [lb]*[rb] | | | Alias of [type list] above +---------------- | -------------- | --------- | ------------------------------ +[lb]N[rb] | | | Restricted [type list]-types. +type[lb][rb], type[lb]N[rb] | | | Length-limited ([lb]..[rb]), expected +[lb][rb]type, [lb]N[rb]type | | | element type, or both. + | | | + | | | Element types can be all known argument + | | | types, except for any kind of list. + | | | IOW multi-dimensional lists are not + | | | supported. +---------------- | -------------- | --------- | ------------------------------ +char* | const char* | Any | [strong Read-only], [strong {string rep}] +pstring | critcl_pstring | Any | [strong Read-only] +bytes | critcl_bytes | ByteArray | [strong Read-only] +---------------- | -------------- | --------- | ------------------------------ +int | int | Int | +long | long | Long | +wideint | Tcl_WideInt | WideInt | +double | double | Double | +float | float | Double | +---------------- | -------------- | --------- | ------------------------------ +X > N | | | For X in [type int] ... [type float] above. +X >= N | | | The C types are as per the base type X. +X < N | | | N, A, B are expected to be constant integer +X <= N | | | numbers for types [type int], [type long], +X > A < B | | | and [type wideint]. For types [type double] +etc. | | | and [type float] the N, A, and B can be floating + | | | point numbers. Multiple restrictions are + | | | fused as much as possible to yield at most + | | | both upper and lower limits. +---------------- | -------------- | --------- | ------------------------------ +boolean | int | Boolean | +bool | | | Alias of [type boolean] above +---------------- | -------------- | --------- | ------------------------------ +channel | Tcl_Channel | String | Assumed to be registered +unshared-channel | Tcl_Channel | String | As above, limited to current interpreter +take-channel | Tcl_Channel | String | As above, C code takes ownership +[example_end] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/rtypes_table.inc b/src/vfs/critcl.vfs/doc/include/cproc/rtypes_table.inc new file mode 100644 index 00000000..53beea4d --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/rtypes_table.inc @@ -0,0 +1,37 @@ +[comment { + Table of the standard result types, for a quick overview + of the names, associated C types, behaviour and limits. +}] +[example_begin] +CriTcl type | C type | Tcl type | Notes +-------------- | -------------- | --------- | ------------------------------ +void | n/a | n/a | Always OK. Body sets result +ok | int | n/a | Result code. Body sets result +-------------- | -------------- | --------- | ------------------------------ +int | int | Int | +boolean | | | Alias of [type int] above +bool | | | Alias of [type int] above +long | long | Long | +wideint | Tcl_WideInt | WideInt | +double | double | Double | +float | float | Double | +-------------- | -------------- | --------- | ------------------------------ +char* | char* | String | [strong {Makes a copy}] +vstring | | | Alias of [type char*] above +const char* | const char* | | Behavior of [type char*] above +-------------- | -------------- | --------- | ------------------------------ +string | | String | Freeable string set directly + | | | [strong {No copy is made}] +dstring | | | Alias of [type string] above +-------------- | -------------- | --------- | ------------------------------ + | | | For all below: Null is ERROR + | | | Body has to set any message +Tcl_Obj* | Tcl_Obj* | Any | [strong {refcount --}] +object | | | Alias of [type Tcl_Obj*] above +Tcl_Obj*0 | | Any | [strong {refcount unchanged}] +object0 | | | Alias of [type Tcl_Obj*0] above +-------------- | -------------- | --------- | ------------------------------ +known-channel | Tcl_Channel | String | Assumes to already be registered +new-channel | Tcl_Channel | String | New channel, will be registered +return-channel | Tcl_Channel | String | Inversion of take-channel +[example_end] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/using_eproc.inc b/src/vfs/critcl.vfs/doc/include/cproc/using_eproc.inc new file mode 100644 index 00000000..868e0491 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/using_eproc.inc @@ -0,0 +1,69 @@ +[subsection {A Simple Procedure}] + +Starting simple, let us assume that the Tcl code in question is +something like + +[example { + proc math {x y z} { + return [expr {(sin($x)*rand())/$y**log($z)}] + } +}] + +with the expression pretending to be something very complex and +slow. Converting this to C we get: + +[example { + critcl::cproc math {double x double y double z} double { + double up = rand () * sin (x); + double down = pow(y, log (z)); + return up/down; + } +}] + +Notable about this translation: + +[list_begin enumerated] +[enum] All the arguments got type information added to them, here + "double". Like in C the type precedes the argument name. Other + than that it is pretty much a Tcl dictionary, with keys and + values swapped. +[enum] We now also have to declare the type of the result, here + "double", again. +[enum] The reference manpage lists all the legal C types supported as + arguments and results. +[list_end] + +[para] While the above example was based on type [type double] for +both arguments and result we have a number of additional types in the +same category, i.e. simple types. These are: + +[example_begin] +CriTcl type | C type | Tcl type | Notes +----------- | -------------- | --------- | ------------------------------ +bool | | | Alias of [type boolean] below +boolean | int | Boolean | +double | double | Double | +float | float | Double | +int | int | Int | +long | long | Long | +wideint | Tcl_WideInt | WideInt | +[example_end] + +[para] A slightly advanced form of these simple types are a limited +set of constraints on the argument value. Note that [type bool] and +alias do not support this. + +[example { + critcl::cproc sqrt {{double >= 0} x} double { + return sqrt(x); + } +}] + +[para] In the example above CriTcl's argument handling will reject +calling the command with a negative number, without ever invoking the +C code. + +[para] These constraints are called [strong limited] because only +[const 0] and [const 1] can be used as the borders, although all the +operators [const <], [const <=], [const >], and [const >=] are +possible. It is also not possible to combine restrictions. diff --git a/src/vfs/critcl.vfs/doc/include/cproc/using_eprocstr.inc b/src/vfs/critcl.vfs/doc/include/cproc/using_eprocstr.inc new file mode 100644 index 00000000..d134f297 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/using_eprocstr.inc @@ -0,0 +1,98 @@ +[subsection {More Builtin Types: Strings}] + +[para] Given that "Everything is a String" is a slogan of Tcl the ability of [cmd cproc]s +to receive strings as arguments, and return them as results is quite important. + +[para] We actually have a variety of builtin string types, all alike, yet different. + +[para] For arguments we have: + +[example_begin] +CriTcl type | C type | Tcl type | Notes +----------- | -------------- | --------- | ------------------------------ +char* | const char* | Any | [strong Read-only], [strong {string rep}] +pstring | critcl_pstring | Any | [strong Read-only] +bytes | critcl_bytes | ByteArray | [strong Read-only] +[example_end] + +In C + +[example { + critcl::cproc takeStrings { + char* cstring + pstring pstring + bytes barray + } void { + printf ("len %d = %s\n", strlen(cstring), cstring); + printf ("len %d = %s\n", pstring.len, pstring.s); + printf ("len %d = %s\n", barray.len, barray.s); + return; // void result, no result + } +}] + +Notable about the above: + +[list_begin enumerated] + +[enum] The [var cstring] is a plain [type {const char*}]. It [strong {points directly}] +into the [type Tcl_Obj*] holding the argument in the script. + +[enum] The [var pstring] is a slight extension to that. The value is actually a structure +containing the string pointer like [var cstring] (field [const .s]), the length of the +string (field [const .len]), and a pointer to the [type Tcl_Obj*] these came from. + +[enum] The last, [var barray] is like [var pstring], however it has ensured that the +[type Tcl_Obj*] is a Tcl ByteArray, i.e. binary data. + +[list_end] + +[para] Treat all of them as [strong {Read Only}]. Do not modify ever. + +[para] On the other side, string results, we have: + +[example_begin] +CriTcl type | C type | Tcl type | Notes +------------- | -------------- | --------- | ------------------------------ +char* | char* | String | [strong {Makes a copy}] +vstring | | | Alias of [type char*] above +const char* | const char* | | Behavior of [type char*] above +------------- | -------------- | --------- | ------------------------------ +string | char* | String | Freeable string set directly + | | | [strong {No copy is made}] +dstring | | | Alias of [type string] above +[example_end] + +[example { + critcl::cproc returnCString {} char* { + return "a string"; + } + critcl::cproc returnString {} string { + char* str = Tcl_Alloc (200); + sprintf (str, "hello world"); + return str; + } +}] + +Notable about the above: + +[list_begin enumerated] + +[enum] The type [type char*] is best used for static strings, or strings in some kind +fixed buffer. + +[para] CriTcl's translation layer makes a copy of it for the result of the command. While +it is possible to return heap-allocated strings it is the C code who is responsible for +freeing such at some point. If that is not done they will leak. + +[enum] The type [type string] on the other hand is exactly for returning strings allocated +with [fun Tcl_Alloc] and associates. + +[para] For these the translation layer makes no copy at all, and sets them directly as the +result of the command. A [strong {very important effect}] of this is that the ownership of +the string pointer moves from the function to Tcl. + +[para] [strong Tcl] will release the allocated memory when it does not need it any +longer. The C code has no say in that. + +[list_end] + diff --git a/src/vfs/critcl.vfs/doc/include/cproc/using_eproctypes.inc b/src/vfs/critcl.vfs/doc/include/cproc/using_eproctypes.inc new file mode 100644 index 00000000..508dc4e4 --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/using_eproctypes.inc @@ -0,0 +1,45 @@ +[subsection {Custom Types, Introduction}] + +When writing bindings to external libraries [cmd critcl::cproc] is +usually the most convenient way of writing the lower layers. This is +however hampered by the fact that critcl on its own only supports a +few standard (arguably the most import) standard types, whereas the +functions we wish to bind most certainly will use much more, specific +to the library's function. + +[para] The critcl commands [cmd argtype], [cmd resulttype] and their +adjuncts are provided to help here, by allowing a developer to extend +critcl's type system with custom conversions. + +[para] This and the three following sections will demonstrate this, +from trivial to complex. + +[para] The most trivial use is to create types which are aliases of +existing types, standard or other. As an alias it simply copies and +uses the conversion code from the referenced types. + +[para] Our example is pulled from an incomplete project of mine, a +binding to [term {Jeffrey Kegler}]'s [term libmarpa] library managing +Earley parsers. Several custom types simply reflect the typedef's done +by the library, to make the [cmd critcl::cproc]s as self-documenting +as the underlying library functions themselves. + +[example { + critcl::argtype Marpa_Symbol_ID = int + critcl::argtype Marpa_Rule_ID = int + critcl::argtype Marpa_Rule_Int = int + critcl::argtype Marpa_Rank = int + critcl::argtype Marpa_Earleme = int + critcl::argtype Marpa_Earley_Set_ID = int + + ... + + method sym-rank: proc { + Marpa_Symbol_ID sym + Marpa_Rank rank + } Marpa_Rank { + return marpa_g_symbol_rank_set (instance->grammar, sym, rank); + } + + ... +}] diff --git a/src/vfs/critcl.vfs/doc/include/cproc/using_eproctypes2.inc b/src/vfs/critcl.vfs/doc/include/cproc/using_eproctypes2.inc new file mode 100644 index 00000000..0acde0fd --- /dev/null +++ b/src/vfs/critcl.vfs/doc/include/cproc/using_eproctypes2.inc @@ -0,0 +1,100 @@ +[subsection {Custom Types, Semi-trivial}] + +A more involved custom argument type would be to map from Tcl strings +to some internal representation, like an integer code. + +[para] The first example is taken from the [package tclyaml] package, +a binding to the [package libyaml] library. In a few places we have to +map readable names for block styles, scalar styles, etc. to the +internal enumeration. + +[example { + critcl::argtype yaml_sequence_style_t { + if (!encode_sequence_style (interp, @@, &@A)) return TCL_ERROR; + } + + ... + + critcl::ccode { + static const char* ty_block_style_names [] = { + "any", "block", "flow", NULL + }; + + static int + encode_sequence_style (Tcl_Interp* interp, Tcl_Obj* style, + yaml_sequence_style_t* estyle) + { + int value; + if (Tcl_GetIndexFromObj (interp, style, ty_block_style_names, + "sequence style", 0, &value) != TCL_OK) { + return 0; + } + *estyle = value; + return 1; + } + } + + ... + + method sequence_start proc { + pstring anchor + pstring tag + int implicit + yaml_sequence_style_t style + } ok { + /* Syntax: seq_start + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl - Introduction To CriTcl

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

Adding C code to Tcl/Tk has never been easier.

+

Improve performance by rewriting the performance bottlenecks in C.

+

Import the functionality of shared libraries into Tcl scripts.

+
+

History & Motivation

+

CriTcl started life as an experiment by Jean-Claude Wippler and was a self-contained +Tcl package to build C code into a Tcl/Tk extension on the fly. It was somewhat inspired +by Brian Ingerson's Inline for Perl, but is considerably more lightweight.

+

It is for the last 5% to 10% when pure Tcl, which does go a long way, is not +sufficient anymore. I.e. for

+
    +
  1. when the last bits of performance are needed,

  2. +
  3. access to 3rd party libraries,

  4. +
  5. hiding critical pieces of your library or application, and

  6. +
  7. simply needing features provided only by C.

  8. +
+
+

Overview

+

To make the reader's topics of interest easy to find this documentation is roughly +organized by Quadrants, i.e.

+
+            | Study           | Work
+----------- + --------------- + -----------------
+Practical   | Tutorials       | How-To Guides
+            | (Learning)      | (Problem solving)
+----------- + --------------- + -----------------
+Theoretical | Explanations    | References
+            | (Understanding) | (Knowledge)
+
+

Note: At this point in time the documentation consists mainly of references, and +a few how-to guides. Tutorials and Explanations are in need of expansion, this is planned.

+
+ +

Tutorials - Practical Study - To Learn

+

This section is currently empty.

+
+

Explanations - Theoretical Knowledge - To Understand

+

This section is currently empty.

+
+ + +

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_application.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_application.html new file mode 100644 index 00000000..aaa28e1a --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_application.html @@ -0,0 +1,434 @@ + +critcl_application - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_application(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_application - CriTcl Application Reference

+
+ +

Synopsis

+
+
    +
  • critcl ?option...? ?file...?
  • +
+
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the critcl command. +Its intended audience are people having to build packages using +critcl for deployment. Writers of packages with embedded C +code can ignore this document. + If you are in need of an overview of the whole system instead, please + go and read the Introduction To CriTcl.

+

This application resides in the Application Layer of CriTcl.

+

arch_application

+

. +The application supports the following general command line:

+
+
critcl ?option...? ?file...?
+

The exact set of options supported, their meaning, and interaction is +detailed in section Application Options below. +For a larger set of examples please see section "Building CriTcl Packages" +in the document about Using CriTcl.

+
+
+

Application Options

+

The following options are understood:

+
+
-v
+
+
--version
+

Print the version to stdout and exit.

+
-I path
+

Arranges for the compiler to search path for headers. +Uses of this option are cumulative.

+

Ignored when generating a TEA package +(see option -tea below).

+
-L path
+

Arranges for the linker to search path. +Uses of this option are cumulative.

+

Ignored when generating a TEA package +(see option -tea below).

+
-cache path
+

Sets path as the directory to use as the result cache. The default is +"~/.critcl/<platform>", or "~/.critcl/<pid>.<epoch>" when generating +a package. See option -pkg, below.

+

Ignored when generating a TEA package +(see option -tea below).

+
-clean
+

Arranges for all files and directories in the result cache to be deleted before +compilation begins.

+

Ignored when generating a package because this mode starts out with a +unique and empty result cache. See option -pkg, below.

+

Ignored when generating a TEA package +(see option -tea below).

+
-config path
+

Provides a custom configuration file. By default a configuration included in +the system core is used. +When specified multiple times the last value is used.

+

Ignored when generating a TEA package +(see option -tea below).

+
-debug mode
+

Activates one of the following debugging modes:

+
+
memory
+

Track and report memory allocations made by the Tcl core.

+
symbols
+

Compile all ".c" files with debugging symbols.

+
all
+

Both memory and symbols.

+
+

Ignored when generating a TEA package +(see option -tea below). +Uses of this option are cumulative.

+
-disable name
+

Sets the value of the custom build configuration option +name to false. It is equivalent to "-with-name 0".

+

Validated only if one of the input files for the CriTcl script +actually defines and uses a custom build configuration option with that +name.

+

Ignored when generating a TEA package +(see option -tea below).

+
-enable name
+

Sets the value of the custom build configuration option +name to true. It is equivalent to "-with-name 1".

+

Validated only if one of the input files for the CriTcl script +actually defines and uses a custom build configuration option with that +name.

+

Ignored when generating a TEA package +(see option -tea below).

+
-force
+

Forces compilation even if a shared library for the file already exists. +Unlike cleaning the cache, this is lazy in the destruction of files and only +affects relevant files.

+

Ignored when generating a package (see option -pkg, below), +which starts out with a unique and empty result cache.

+

Ignored when generating a TEA package +(see option -tea below).

+
-help
+

Prints a short description of command line syntax and options and then exits +the application.

+
-keep
+

Causes the system to cache compiled ".c" files. +Also prevents the deletion of the unique result cache used by the run when +generating a package (see option -pkg below), +Intended for debugging of critcl itself, where it may be necessary to +inspect the generated C code.

+

Ignored when generating a TEA package +(see option -tea below).

+
-libdir directory
+

Adds directory to the list of directories the linker searches for +libraries in (like -L). With -pkg, generated packages are +saved in directory. +When specified multiple times the last value is used. +The default is "lib", resolved relative to the current working directory.

+
-includedir directory
+

Adds directory to the list of directories the compiler searches for +headers in. With -pkg, generated header files are saved in +directory. +Uses of this option are cumulative. +The last value is used as the destination for generated header files. +The default is the relative directory "include", resolved relative to the +current working directory.

+

Ignored when generating a TEA package +(see option -tea below).

+
-pkg
+

Generates a package from the CriTcl script files. Input files are +processed first as usual, but are then bundled into a single library, with +additional generated files to form the library into a standard Tcl package.

+

generation. If both options, i.e. -pkg and -tea are +specified the last one specified wins.

+

Options -clean and -force are ignored. -libdir is +relevant in both this and -tea mode.

+

The basename of the first file is the name of the package to generate. If +its file extension indicates a shared library (".so", ".sl", +".dylib", and ".dll") it is also removed from the set of input +files. Each CriTcl script file is kept as part of the input. A single +file without a suffix is assumed to be a CriTcl script. A file without +a suffix, but other input files following is treated like the name of a +shared library proper, and removed from the set of input files.

+

Examples:

+
+	... -pkg ... foo
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -pkg ... foo bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+	... -pkg ... foo.tcl
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -pkg ... foo.so bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+
-show
+

Prints the configuration of the chosen target to stdout and then exits. +Set -target, below.

+
-showall
+

Prints the whole chosen configuration file to stdout and then exits. +See -config, above.

+
-target name
+

Overrides the default choice of build target. +Only the last occurrence of this option is used. +The named target must exist in the chosen configuration file. +Use -targets (see below) to get a list of the +acceptable targets. +Use -config to select the configuration file.

+

Ignored when generating a TEA package +(see option -tea below).

+
-targets
+

Prints the list of all known targets from the chosen configuration file to +stdout and then exits. +Use -config to select the configuration file.

+
-tea
+

Like -pkg, except no binaries are generated. Creates a directory +hierarchy containing the CriTcl script, its companion files, and a +TEA-conformant build system with most of the needed support code, including +copies of the critcl packages.

+

If both -pkg and -tea are specified the last occurrence wins.

+

-I, -L, -clean, +-force, -cache, -includedir, -enable, +-disable, and -with-FOO are +ignored. In contrast, the option -libdir is relevant in both +this and -pkg mode.

+

The basename of the first file is the name of the package to generate. If +its file extension indicates a shared library (".so", ".sl", +".dylib", and ".dll") it is also removed from the set of input +files. Each CriTcl script file is kept as part of the input. A single +file without a suffix is assumed to be a CriTcl script. A file without +a suffix, but other input files following is treated like the name of a +shared library proper, and removed from the set of input files.

+

Examples:

+
+	... -tea ... foo
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -tea ... foo bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+	... -tea ... foo.tcl
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -tea ... foo.so bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+
-with-name value
+

This option sets the value of the custom build configuration option +name to value.

+

The information is validated only if one of the ".critcl" +input files actually defines and uses a custom build configuration +option with that name.

+

Ignored when generating a TEA package +(see option -tea below).

+
+
+

Package Structure

+

Packages generated by critcl have the following basic structure:

+
+<TOP>
++- pkgIndex.tcl
++- critcl-rt.tcl
++- license.terms (optional)
+|
++- tcl (optional)
+|  +- <tsources files>
+|
++- <platform>
+   +- <shared library>
+
+

Notes

+
    +
  1. The file "pkgIndex.tcl" is the standard package index file +expected by Tcl's package management. It is sourced during a search +for packages, and declares the package to Tcl with its files, and how +to handle them.

  2. +
  3. The file "critcl-rt.tcl" is a helper file containing the +common code used by "pkgIndex.tcl" to perform its tasks.

  4. +
  5. The file "license.terms" is optional and appears only if +the ".critcl" file the package is generated from used the command +critcl::license to declare package author and license.

  6. +
  7. All files declared with the command critcl::tsources are +put into the sub-directory "tcl".

  8. +
  9. The shared library generated by critcl is put into a +platform-specific sub-directory.

  10. +
+

The whole structure, and especially the last point, enable us +to later merge the results (for the same package, and version) for +multiple target platforms into a single directory structure without +conflict, by simply copying the top directories over each other. The +only files which can conflict are in the <TOP> and "tcl" +directories, and for these we know that they are identical across +targets. The result of such a merge would look like:

+
+<TOP>
++- pkgIndex.tcl
++- critcl-rt.tcl
++- license.terms (optional)
+|
++- tcl (optional)
+|  +- <tsources files>
+|
++- <platform1>
+|  +- <shared library1>
++- <platform2>
+|  +- <shared library2>
+...
++- <platformN>
+   +- <shared libraryN>
+
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_application_package.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_application_package.html new file mode 100644 index 00000000..550ad3ab --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_application_package.html @@ -0,0 +1,481 @@ + +critcl_application_package - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_application_package(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_application_package - CriTcl Application Package Reference

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl::app ?3.2.1?
  • +
  • package require critcl ?3.2.1?
  • +
  • package require platform ?1.0.2?
  • +
  • package require cmdline
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the critcl::app +package. Its intended audience are developers working on critcl's +internals. +These commands are not needed to simply write a CriTcl script. + If you are in need of an overview of the whole system instead, please + go and read the Introduction To CriTcl.

+

This package resides in the Application Layer of CriTcl.

+

arch_application

+

, +implementing the functionality of the CriTcl Application, +and through this, the mode generate package. +The actual application is (only) a shim wrapping around this +package. It itself is build on top of the core package +critcl.

+
+

API

+

The package exports a single command

+
+
::critcl::app::main commandline
+

The commandline is a list of zero or more options followed by zero or +more CriTcl script files. By default, the CriTcl script files +are build and the results cached. This cuts down on the time needed to +load the package. The last occurrence of -pkg and -tea, if +provided, selects the corresponding alternative mode of operations. +For a larger set of examples please see section "Building CriTcl Packages" +in the document about Using CriTcl.

+
+

The options are:

+
+

Options

+

The following options are understood:

+
+
-v
+
+
--version
+

Print the version to stdout and exit.

+
-I path
+

Arranges for the compiler to search path for headers. +Uses of this option are cumulative.

+

Ignored when generating a TEA package +(see option -tea below).

+
-L path
+

Arranges for the linker to search path. +Uses of this option are cumulative.

+

Ignored when generating a TEA package +(see option -tea below).

+
-cache path
+

Sets path as the directory to use as the result cache. The default is +"~/.critcl/<platform>", or "~/.critcl/<pid>.<epoch>" when generating +a package. See option -pkg, below.

+

Ignored when generating a TEA package +(see option -tea below).

+
-clean
+

Arranges for all files and directories in the result cache to be deleted before +compilation begins.

+

Ignored when generating a package because this mode starts out with a +unique and empty result cache. See option -pkg, below.

+

Ignored when generating a TEA package +(see option -tea below).

+
-config path
+

Provides a custom configuration file. By default a configuration included in +the system core is used. +When specified multiple times the last value is used.

+

Ignored when generating a TEA package +(see option -tea below).

+
-debug mode
+

Activates one of the following debugging modes:

+
+
memory
+

Track and report memory allocations made by the Tcl core.

+
symbols
+

Compile all ".c" files with debugging symbols.

+
all
+

Both memory and symbols.

+
+

Ignored when generating a TEA package +(see option -tea below). +Uses of this option are cumulative.

+
-disable name
+

Sets the value of the custom build configuration option +name to false. It is equivalent to "-with-name 0".

+

Validated only if one of the input files for the CriTcl script +actually defines and uses a custom build configuration option with that +name.

+

Ignored when generating a TEA package +(see option -tea below).

+
-enable name
+

Sets the value of the custom build configuration option +name to true. It is equivalent to "-with-name 1".

+

Validated only if one of the input files for the CriTcl script +actually defines and uses a custom build configuration option with that +name.

+

Ignored when generating a TEA package +(see option -tea below).

+
-force
+

Forces compilation even if a shared library for the file already exists. +Unlike cleaning the cache, this is lazy in the destruction of files and only +affects relevant files.

+

Ignored when generating a package (see option -pkg, below), +which starts out with a unique and empty result cache.

+

Ignored when generating a TEA package +(see option -tea below).

+
-help
+

Prints a short description of command line syntax and options and then exits +the application.

+
-keep
+

Causes the system to cache compiled ".c" files. +Also prevents the deletion of the unique result cache used by the run when +generating a package (see option -pkg below), +Intended for debugging of critcl itself, where it may be necessary to +inspect the generated C code.

+

Ignored when generating a TEA package +(see option -tea below).

+
-libdir directory
+

Adds directory to the list of directories the linker searches for +libraries in (like -L). With -pkg, generated packages are +saved in directory. +When specified multiple times the last value is used. +The default is "lib", resolved relative to the current working directory.

+
-includedir directory
+

Adds directory to the list of directories the compiler searches for +headers in. With -pkg, generated header files are saved in +directory. +Uses of this option are cumulative. +The last value is used as the destination for generated header files. +The default is the relative directory "include", resolved relative to the +current working directory.

+

Ignored when generating a TEA package +(see option -tea below).

+
-pkg
+

Generates a package from the CriTcl script files. Input files are +processed first as usual, but are then bundled into a single library, with +additional generated files to form the library into a standard Tcl package.

+

generation. If both options, i.e. -pkg and -tea are +specified the last one specified wins.

+

Options -clean and -force are ignored. -libdir is +relevant in both this and -tea mode.

+

The basename of the first file is the name of the package to generate. If +its file extension indicates a shared library (".so", ".sl", +".dylib", and ".dll") it is also removed from the set of input +files. Each CriTcl script file is kept as part of the input. A single +file without a suffix is assumed to be a CriTcl script. A file without +a suffix, but other input files following is treated like the name of a +shared library proper, and removed from the set of input files.

+

Examples:

+
+	... -pkg ... foo
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -pkg ... foo bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+	... -pkg ... foo.tcl
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -pkg ... foo.so bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+
-show
+

Prints the configuration of the chosen target to stdout and then exits. +Set -target, below.

+
-showall
+

Prints the whole chosen configuration file to stdout and then exits. +See -config, above.

+
-target name
+

Overrides the default choice of build target. +Only the last occurrence of this option is used. +The named target must exist in the chosen configuration file. +Use -targets (see below) to get a list of the +acceptable targets. +Use -config to select the configuration file.

+

Ignored when generating a TEA package +(see option -tea below).

+
-targets
+

Prints the list of all known targets from the chosen configuration file to +stdout and then exits. +Use -config to select the configuration file.

+
-tea
+

Like -pkg, except no binaries are generated. Creates a directory +hierarchy containing the CriTcl script, its companion files, and a +TEA-conformant build system with most of the needed support code, including +copies of the critcl packages.

+

If both -pkg and -tea are specified the last occurrence wins.

+

-I, -L, -clean, +-force, -cache, -includedir, -enable, +-disable, and -with-FOO are +ignored. In contrast, the option -libdir is relevant in both +this and -pkg mode.

+

The basename of the first file is the name of the package to generate. If +its file extension indicates a shared library (".so", ".sl", +".dylib", and ".dll") it is also removed from the set of input +files. Each CriTcl script file is kept as part of the input. A single +file without a suffix is assumed to be a CriTcl script. A file without +a suffix, but other input files following is treated like the name of a +shared library proper, and removed from the set of input files.

+

Examples:

+
+	... -tea ... foo
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -tea ... foo bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+	... -tea ... foo.tcl
+	=> Package name is: foo
+	=> Input file is:   foo.tcl
+
+
+	... -tea ... foo.so bar.tcl
+	=> Package name is: foo
+	=> Input file is:   bar.tcl
+
+
+
-with-name value
+

This option sets the value of the custom build configuration option +name to value.

+

The information is validated only if one of the ".critcl" +input files actually defines and uses a custom build configuration +option with that name.

+

Ignored when generating a TEA package +(see option -tea below).

+
+
+

Modes Of Operation/Use

+

CriTcl can be used in three different modes of operation, called

+
    +
  1. Compile & Run, and

  2. +
  3. Generate Package

  4. +
  5. Generate TEA Package

  6. +
+

Compile & Run was the original mode and is the default for +critcl_pkg. Collects the C fragments from the +CriTcl script, builds them as needed, and caches the results to +improve load times later.

+

The second mode, Generate Package, was introduced to enable +the creation of (prebuilt) deliverable packages which do not depend on +the existence of a build system, i.e. C compiler, on the target +machine. +This was originally done through the experimental Critbind tool, +and is now handled by the CriTcl Application, also named +critcl.

+

Newly introduced with CriTcl version 3 is +Generate TEA Package. This mode constructs a directory +hierarchy from the package which can later be built like a regular TEA +package, i.e. using

+
+	.../configure --prefix ...
+	make all isntall
+
+
+

Package Structure

+

Packages generated by critcl have the following basic structure:

+
+<TOP>
++- pkgIndex.tcl
++- critcl-rt.tcl
++- license.terms (optional)
+|
++- tcl (optional)
+|  +- <tsources files>
+|
++- <platform>
+   +- <shared library>
+
+

Notes

+
    +
  1. The file "pkgIndex.tcl" is the standard package index file +expected by Tcl's package management. It is sourced during a search +for packages, and declares the package to Tcl with its files, and how +to handle them.

  2. +
  3. The file "critcl-rt.tcl" is a helper file containing the +common code used by "pkgIndex.tcl" to perform its tasks.

  4. +
  5. The file "license.terms" is optional and appears only if +the ".critcl" file the package is generated from used the command +critcl::license to declare package author and license.

  6. +
  7. All files declared with the command critcl::tsources are +put into the sub-directory "tcl".

  8. +
  9. The shared library generated by critcl is put into a +platform-specific sub-directory.

  10. +
+

The whole structure, and especially the last point, enable us +to later merge the results (for the same package, and version) for +multiple target platforms into a single directory structure without +conflict, by simply copying the top directories over each other. The +only files which can conflict are in the <TOP> and "tcl" +directories, and for these we know that they are identical across +targets. The result of such a merge would look like:

+
+<TOP>
++- pkgIndex.tcl
++- critcl-rt.tcl
++- license.terms (optional)
+|
++- tcl (optional)
+|  +- <tsources files>
+|
++- <platform1>
+|  +- <shared library1>
++- <platform2>
+|  +- <shared library2>
+...
++- <platformN>
+   +- <shared libraryN>
+
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_bitmap.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_bitmap.html new file mode 100644 index 00000000..83e52a8d --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_bitmap.html @@ -0,0 +1,271 @@ + +critcl::bitmap - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::bitmap(n) 1.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::bitmap - CriTcl - Wrap Support - Bitset en- and decoding

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2?
  • +
  • package require critcl::bitmap ?1.1?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the +critcl::bitmap package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package critcl::iassoc.

+

C level libraries often use bit-sets to encode many flags into a +single value. Tcl bindings to such libraries now have the task of +converting a Tcl representation of such flags (like a list of strings) +into such bit-sets, and back. +Note here that the C-level information has to be something which +already exists. The package does not create these values. This is +in contrast to the package critcl::enum which creates an +enumeration based on the specified symbolic names.

+

This package was written to make the declaration and management +of such bit-sets and their associated conversions functions easy, +hiding all attendant complexity from the user.

+

Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::bitmap::def name definition ?exclusions?
+

This command defines two C functions for the conversion of the +named bit-set into Tcl lists, and vice versa. +The underlying mapping tables are automatically initialized on first +access, and finalized on interpreter destruction.

+

The definition dictionary provides the mapping from the +Tcl-level symbolic names of the flags to their C expressions (often +the name of the macro specifying the actual value). +Note here that the C-level information has to be something which +already exists. The package does not create these values. This is +in contrast to the package critcl::enum which creates an +enumeration based on the specified symbolic names.

+

The optional exlusion list is for the flags/bit-sets for +which conversion from bit-set to flag, i.e. decoding makes no +sense. One case for such, for example, are flags representing a +combination of other flags.

+

The package generates multiple things (declarations and +definitions) with names derived from name, which has to be a +proper C identifier.

+
+
name_encode
+

The function for encoding a Tcl list of strings into the equivalent +bit-set. +Its signature is

+
+int name_encode (Tcl_Interp* interp, Tcl_Obj* flags, int* result);
+
+

The return value of the function is a Tcl error code, +i.e. TCL_OK, TCL_ERROR, etc.

+
name_decode
+

The function for decoding a bit-set into the equivalent Tcl list of +strings. +Its signature is

+
+Tcl_Obj* name_decode (Tcl_Interp* interp, int flags);
+
+
+
name.h
+

A header file containing the declarations for the two conversion +functions, for use by other parts of the system, if necessary.

+

The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files (csources).

+
name
+

The name of a critcl argument type encapsulating the encoder function +for use by critcl::cproc.

+
name
+

The name of a critcl result type encapsulating the decoder function +for use by critcl::cproc.

+
+
+
+

Example

+

The example shown below is the specification of the event flags pulled +from the draft work on a Tcl binding to Linux's inotify APIs.

+
+package require Tcl 8.6
+package require critcl 3.2
+critcl::buildrequirement {
+    package require critcl::bitmap
+}
+critcl::bitmap::def tcl_inotify_events {
+    accessed       IN_ACCESS
+    all            IN_ALL_EVENTS
+    attribute      IN_ATTRIB
+    closed         IN_CLOSE
+    closed-nowrite IN_CLOSE_NOWRITE
+    closed-write   IN_CLOSE_WRITE
+    created        IN_CREATE
+    deleted        IN_DELETE
+    deleted-self   IN_DELETE_SELF
+    dir-only       IN_ONLYDIR
+    dont-follow    IN_DONT_FOLLOW
+    modified       IN_MODIFY
+    move           IN_MOVE
+    moved-from     IN_MOVED_FROM
+    moved-self     IN_MOVE_SELF
+    moved-to       IN_MOVED_TO
+    oneshot        IN_ONESHOT
+    open           IN_OPEN
+    overflow       IN_Q_OVERFLOW
+    unmount        IN_UNMOUNT
+} {
+    all closed move oneshot
+}
+# Declarations:          tcl_inotify_events.h
+# Encoder:      int      tcl_inotify_events_encode (Tcl_Interp* interp, Tcl_Obj* flags, int* result);
+# Decoder:      Tcl_Obj* tcl_inotify_events_decode (Tcl_Interp* interp, int flags);
+# crit arg-type          tcl_inotify_events
+# crit res-type          tcl_inotify_events
+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_build.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_build.html new file mode 100644 index 00000000..aff87975 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_build.html @@ -0,0 +1,152 @@ + +critcl_build_tool - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_build_tool(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_build_tool - CriTcl build.tcl Tool Reference

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts. +The script "build.tcl" found in the top directory of the CriTcl sources is the +main tool of use to a developer or maintainer of CriTcl itself.

+

Invoking it a via

+
./build.tcl help
+

provides the online help for this +tool, explaining the operations available, and their arguments.

+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_callback.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_callback.html new file mode 100644 index 00000000..733e8956 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_callback.html @@ -0,0 +1,277 @@ + +critcl::callback - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::callback(n) 1.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::callback - CriTcl - C-level Callback Utilities

+
+ + +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the +critcl::callback package. +This package provides, via a stubs API table, data structures and +functions to manage callbacks from C to Tcl. The package has no +Tcl-level facilities. +Its intended audience are mainly developers wishing to write Tcl +packages with embedded C code who have to invoke user-specified +command (prefixes) in Tcl.

+

This package resides in the Support Package Layer of CriTcl.

+

arch_support

+
+

API

+

The package API consist of one opaque data structure +(critcl_callback_p) and four functions operating on the same. +These functions are

+
+
critcl_callback_p critcl_callback_new interp objc objv nargs
+

This function creates a new callback (manager) and returns it as its result.

+

The callback is initialized with the Tcl_Interp* interp +specifying where to run the callback, the fixed part of the command to +run in standard objc/objv notation, plus the number of +free arguments to expect after the fixed part.

+

The fixed part is the essentially the command prefix of the callback.

+

All Tcl_Obj* elements of objv are protected against early +release by incrementing their reference counts. The callback +effectively takes ownership of these objects.

+
void critcl_callback_extend callback argument
+

This function takes a callback of type critcl_callback_p +and extends its fixed part with the argument, taking the first +free slot for arguments to do so. +This means that after the application of this function the specified +callback has one free argument less.

+

With assertions active attempting to extend beyond the number of free +arguments will cause a panic. Without assertions active expect a crash +at some point.

+

This allows the user to extend the fixed part of the callback with +semi-fixed elements, like method names (See Multiple methods).

+

The argument is protected against early release by incrementing +its reference count. The callback effectively takes ownership of this +object.

+
void critcl_callback_destroy callback
+

This function takes a callback of type critcl_callback_p +and releases all memory associated with it. +After application of this function the callback cannot be used anymore.

+

All fixed elements of the callback (owned by it) are released by +decrementing their reference counts.

+
int critcl_callback_invoke callback objc objv
+

This function invokes the callback in the Tcl interpreter specified at +the time of construction, in the global level and namespace, with the +free arguments filled by the Tcl_Obj* objects specified via +objc/objv.

+

It returns the Tcl status of the invoked command as its result. +Any further results or error messages will be found in the result area +of the Tcl interpreter in question. The exact nature of such is +dependent on the callback itself.

+

With assertions active attempting to use more arguments than available +will cause a panic. Without assertions active expect a crash at some +point.

+

While the callback is running all Tcl_Obj* elements of the +command, fixed and arguments, are protected against early release by +temporarily incrementing their reference counts.

+
+
+

Examples

+

Simple callback

+

The example here shows the important parts of using the functions of +this package for a simple callback which is invoked with a single +argument, some kind of data to hand to the Tcl level.

+
+    // Create the callback with interpreter and command prefix in
+    // oc/ov, plus space for the argument
+    critcl_callback_p cb = critcl_callback_new (interp, oc, ov, 1);
+    // Invoke the callback somewhere in the C package using this one,
+    // with Tcl_Obj* data holding the information to pass up.
+    critcl_callback_invoke (cb, 1, &data);
+    // At the end of the lifetime, release the callback.
+    critcl_callback_destroy (cb);
+
+

Note that the functions of this package are designed for the case +where the created callback (cb above) is kept around for a +long time, and many different invokations.

+

Using the sequence above as is, creating and destroying the callback +each time it is invoked will yield very poor performance and lots of +undesirable memory churn.

+
+

Multiple methods

+

While we can use the methodology of the previous section when a single +(Tcl-level) callback is invoked from different places in C, with +different methods, simply having another argument slot and filling it +an invokation time with the method object, a second methodology is +open to us due to critcl_callback_extend.

+
+    // Create one callback manager per different method the callback
+    // will be used with. Fill the first of the two declared arguments
+    // with the different methods.
+    critcl_callback_p cb_a = critcl_callback_new (interp, oc, ov, 2);
+    critcl_callback_p cb_b = critcl_callback_new (interp, oc, ov, 2);
+    critcl_callback_extend (cb_a, Tcl_NewStringObj ("method1", -1));
+    critcl_callback_extend (cb_b, Tcl_NewStringObj ("method2", -1));
+    // After the extension we have one free argument left, for use in
+    // the invokations.
+    critcl_callback_invoke (cb_a, 1, &dataX);
+    critcl_callback_invoke (cb_b, 1, &dataY);
+    // At the end release both managers again
+    critcl_callback_destroy (cb_a);
+    critcl_callback_destroy (cb_b);
+
+

The nice thing here is that the method objects are allocated only once +and automatically shared by all the calls. No memory churn to +repeatedly allocate the same string objects over and over again.

+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_changes.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_changes.html new file mode 100644 index 00000000..5ad2909f --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_changes.html @@ -0,0 +1,1100 @@ + +critcl_changes - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_changes(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_changes - CriTcl Releases & Changes

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

Adding C code to Tcl/Tk has never been easier.

+

Improve performance by rewriting the performance bottlenecks in C.

+

Import the functionality of shared libraries into Tcl scripts. +See the changes done in each release of CriTcl, from the latest at the top to the +beginning of the project.

+

The latest changes are found at the top.

+
+

Changes for version 3.2.1 (to come)

+
    +
  1. As announced with 3.2:

    +
      +
    1. Removed support for Tcl 8.4 and 8.5.

    2. +
    3. Removed support for the argument types + int*, + float*, + double*, + bytearray, + rawchar, and + rawchar*.

    4. +
    +
  2. +
  3. Modified packages to accept operation under Tcl 9. + Bumped package versions appropriately. + Bumped copyrights.

    +

    The How To Adapt Critcl Packages for Tcl 9 + contains the details relevant to writers of CriTcl-based packages.

  4. +
  5. Set different minimum Tcl requirements for the 8.x and 9.x series.

    +

    If no minimum is declared the minimum depends on the Tcl version + used to run the critcl package or application.

    +

    When running under Tcl 9 the default minimum is version 9. + For anything else the new default minimum is 8.6.

    +

    Reminder: Support for Tcl 8.4 and 8.5 was removed.

  6. +
  7. Made "~"-handling portable across the 8.x and 9 boundary + (via HOME environment variable).

  8. +
  9. Bumped embedded tclconfig to version 2.67. Patch supplied by Paul Obermeier.

  10. +
  11. Bug Fix #127

  12. +
  13. Bug Fix #128

  14. +
  15. Bug Fix #129 +Fixed various typos in the documentation.

  16. +
  17. Reworked internals of critcl::cutil's tracer to support operation in a + multi-threaded environment. This new mode is also default. The old single-threaded + mode can be (re)activated by defining CRITCL_TRACE_NOTHREADS.

    +

    Package bumped to version 0.4.

  18. +
+
+

Changes for version 3.2

+
    +
  1. BREAKING CriTcl now requires Tcl 8.6 to be run.

    +

    It also generates Tcl 8.6 extensions by default.

    +

    It is still possible to generates extensions for Tcl 8.4 and 8.5, + properly setting it via critcl::tcl.

    +

    ATTENTION It is planned to completely remove 8.4 and 8.5 + support with CriTcl 3.3. + No date has been set for that release yet.

    +

    All utility packages have their versions and requirements bumped accordingly as + well.

  2. +
  3. BREAKING Bug Fix + Issue #115.

    +

    Distributions using build.tcl for installation of critcl in their + packaging scripts have to be updated to the changed command signature of + build.tcl install, etc. See the details below.

    +

    Redone the argument handling for install, uninstall, and + targets. The destination argument is gone. All commands now take options + similar to what is known from GNU configure, i.e.

    +
    +
    --prefix path
    +
    +
    --exec-prefix path
    +
    +
    --bin-dir path
    +
    +
    --lib-dir path
    +
    +
    --include-dir path
    +
    +
    +

    They now also respect the environment variable DESTDIR, and the associated + option --dest-dir.

    +

    The --prefix defaults to the topdir from the bin directory holding the + tclsh running build.tcl. As Tcl command:

    +
    +    file dirname [file dirname [info nameofexecutable]]
    +
    +

    Added a command dirs doing the same argument handling, for debugging.

  4. +
  5. Removed the irrelevant packages autoscroll, cmdline, + dict84, lassign84, lmap84, snit, + snitbutton, and wikit.

  6. +
  7. Documentation Redo Issue + #116. + Reworked the documentation to use the system of 4 quadrants. + Reworked the introduction (How To Use Critcl) to be strongly + based on a series of examples.

  8. +
  9. Bug Fix Issue + #125. + Added missing method create in object creation example + of installer documentation.

  10. +
  11. Feature. Extended cproc argument type processing. Now able to + auto-create restricted scalar types. I.e. types derived from int, etc. and + limited in the range of allowed values.

    +

    Further able to auto-create restricted list types, i.e. types derived from + list and either limited in length, or in the type of the elements, or both.

  12. +
  13. Bug Fix / Enhancement Issue + #118. Modified + critcl::cproc to accept C syntax for arguments, i.e. Trailing comma on + argument names, leading comma on type names, and lone comma characters.

  14. +
  15. Performance Fix for compile & run mode. + Issue #112.

    +

    Moved the command activating more precise code location tracking out of package + critcl into package critcl::app.

    +

    Because generating packages ahead of time can bear the performance penalty invoked + by this global setting.

    +

    Arbitrary libraries and applications using critcl dynamically + (compile & run) on the other hand likely cannot, and should not.

  16. +
  17. Fix + Issue #109. + Ignore clang suffices when computing the target identifier from a + configuration identifier.

  18. +
  19. Feature. Bumped package critcl::cutil to version 0.2.1. + Simplified the implementation of macro ASSERT by taking the underlying + Tcl_Panic's printf ability into account and added a new macro ASSERT_VA + exporting the same ability to the user.

  20. +
+
+

Changes for version 3.1.18.1

+
    +
  1. Attention: While the overall version (of the bundle) + moves to 3.1.18.1 the versions of packages critcl and + critcl::app are unchanged.

  2. +
  3. Bugfix Generally removed a number of 8.5-isms which + slipped into 3.1.18, breaking ability to use it with Tcl 8.4.

  4. +
  5. Bugfix Corrected broken build.tcl uninstall.

  6. +
  7. Bugfix Package critcl::class bumped to + version 1.1.1. Fixed partial template substitution breaking + compilation of the generated code.

  8. +
+
+

Changes for version 3.1.18

+
    +
  1. Feature (Developer support). Merged pull request #96 from + sebres/main-direct-invoke. Enables direct invokation of the + "main.tcl" file for starkits from within a dev checkout, + i.e. outside of a starkit, or starpack.

  2. +
  3. Feature. Added channel types to the set of builtin argument and + result types. The argument types are for simple channel access, + access requiring unshared channels, and taking the channel + fully into the C level, away from Tcl. The result type comes in + variants for newly created channels, known channels, and to + return taken channels back to Tcl. The first will register the + returned value in the interpreter, the second assumes that it + already is.

  4. +
  5. Bugfix. Issue #96. Reworked the documentation around the + argument type Tcl_Interp* to make its special status + more visible, explain uses, and call it out from result types + where its use will be necessary or at least useful.

  6. +
  7. Feature. Package critcl::class bumped to version 1.1. + Extended with the ability to create a C API for classes, and + the ability to disable the generation of the Tcl API.

  8. +
  9. Bugfix. Merged pull request #99 from pooryorick/master. Fixes + to the target directory calculations done by the install code.

  10. +
  11. Merged pull request #94 from andreas-kupries/documentation. + A larger documentation cleanup. The main work was done by + pooryorick, followed by tweaks done by myself.

  12. +
  13. Extended the test suite with lots of cases based on the + examples for the various generator packages. IOW the new test + cases replicate/encapsulate the examples and demonstrate that + the packages used by the examples generate working code.

  14. +
  15. Bugfix. Issue #95. Changed the field critcl_bytes.s to + unsigned char* to match Tcl's type. Further constified + the field to make clear that read-only usage is the common case + for it.

  16. +
  17. Bugfix/Feature. Package critcl::cutil bumped to + version 0.2. Fixed missing inclusion of header "string.h" + in "critcl_alloc.h", needed for memcpy in macro + STREP. Added macros ALLOC_PLUS and STRDUP. + Moved documentation of STREP... macros into proper place + (alloc section, not assert).

  18. +
  19. Merged pull request #83 from apnadkarni/vc-fixes. + Removed deprecated -Gs for MSVC builds, and other Windows fixups.

  20. +
  21. Feature. Package critcl::iassoc bumped to version 1.1. + Refactored internals to generate an include header for use by .c files. + This now matches what other generator packages do. + The template file is inlined and removed.

  22. +
  23. Merged pull request #82 from gahr/home-symlink + Modified tests to handle possibility of $HOME a symlink.

  24. +
  25. Merged pull request #81 from gahr/test-not-installed + Modified test support to find uninstalled critcl packages when + running tests. Handles all but critcl::md5.

  26. +
  27. Merged pull request #85 from snoe925/issue-84 + to fix Issue #84 breaking installation on OSX.

  28. +
  29. Merged pull request #87 from apnadkarni/tea-fixes to fix Issue + #86, broken -tea option, generating an incomplete package.

  30. +
  31. Feature. New package critcl::callback providing + C-level functions and data structures to manage callbacks from + C to Tcl.

  32. +
  33. Feature. Package critcl::literals bumped to version + 1.3. Added mode +list enabling the conversion of + multiple literals into a list of their strings.

  34. +
  35. Feature. Package critcl::enum bumped to version 1.1. + Added basic mode handling, supporting tcl (default) and + +list (extension enabling the conversion of multiple + enum values into a list of their strings).

  36. +
  37. Feature. Package critcl::emap bumped to version 1.2. + Extended existing mode handling with +list extension + enabling the conversion of multiple emap values into a list of + their strings.

  38. +
  39. Feature. Extended the set of available types by applying a few + range restrictions to the scalar types (int, + long, wideint, double, float).

    +

    Example: int > 0 is now a viable type name.

    +

    This is actually more limited than the description might + let you believe.

    +

    See the package reference for the details.

  40. +
+
+

Changes for version 3.1.17

+
    +
  1. Extension: Allow duplicate arg- and result-type definitions if + they are fully identical.

  2. +
  3. Bugfix. The application mishandled the possibility of + identical-named critcl::tsources. Possible because + critcl::tsources can be in subdirectories, a structure + which is not retained in the assembled package, causing + such files to overwrite each other and at least one lost. Fixed + by adding a serial number to the file names in the assembled + package.

  4. +
  5. Bugfix in the static scanner which made it loose requirement + information. Further added code to generally cleanup results at + the end (removal of duplicates, mainly).

  6. +
  7. Bugfix: Fixed issue #76. + Support installation directories which are not in the auto_path. + Without the patch the installed critcl will not find its + own packages and fail. Thank you to + Simon Bachmann for the + report and patch, and then his patience with me to getting to + actually apply it.

  8. +
  9. Bugfix: Fixed issue #75. + Extended critcl::include to now take multiple paths.

  10. +
  11. Added new compatibility package lmap84.

  12. +
  13. Fixed typos in various documentation files.

  14. +
  15. Fixed bug introduced by commit 86f415dd30 (3.1.16 release). The + separation of critcl::ccode into user and work layers + means that location retrieval has to go one more level up to + find the user location.

  16. +
  17. New supporting package critcl::cutil. Provides common + C level facilities useful to packages (assertions, tracing, + memory allocation shorthands).

  18. +
  19. Modified package critcl to make use of the new + tracing facilities to provide tracing of arguments and results + for critcl::ccommand and critcl::cproc invokations.

  20. +
  21. Modified packages critcl and critcl::class + to provide better function names for (class) method tracing. + Bumped package critcl::class to version 1.0.7.

  22. +
  23. Extended the support package critcl::literals with + limited configurability. It is now able to generate code for + C-level access to the pool without Tcl types (Mode c). + The previously existing functionality is accesssible under mode + tcl, which also is the default. Both modes can be used + together.

  24. +
  25. Extended the support package critcl::emap with + limited configurability. It is now able to generate code for + C-level access to the mapping without Tcl types + (Mode c). The previously existing functionality is + accessible under mode tcl, which also is the + default. Both modes can be used together.

  26. +
+
+

Changes for version 3.1.16

+
    +
  1. New feature. Extended critcl::cproc's argument handling + to allow arbitrary mixing of required and optional arguments.

  2. +
  3. New feature. + Potential Incompatibility.

    +

    Extended critcl::cproc's argument handling to treat an + argument args as variadic if it is the last argument of + the procedure.

  4. +
  5. New feature. Added two introspection commands, + critcl::has-argtype and critcl::has-resulttype. + These enable a user to test if a specific (named) type + conversion is implemented or not.

  6. +
  7. Added new result type Tcl_Obj*0, with alias + object0. The difference to Tcl_Obj* is in + the reference counting.

  8. +
  9. Extended the command critcl::argtypesupport with new + optional argument through which to explicitly specify the + identifier for guarding against multiple definitions.

  10. +
  11. Bugfix: Fixed problem with the implementation of issue #54 (See + 3.1.14). Always create the secondary log file. Otherwise + end-of-log handling may break, unconditionally assuming its + existence.

  12. +
  13. Bugfix: Fixed problem with the internal change to the hook + HandleDeclAfterBuild. Corrected the forgotten + critcl::cconst.

  14. +
  15. Debugging aid: Added comment holding the name of the result + type when emitting result conversions.

  16. +
  17. Bugfix: Fixed issue #60. Unbundled the package directories + containing multiple packages. All directories under "lib/" + now contain exactly one package.

  18. +
  19. Bugfix: Fixed issue #62, a few dict exists commands + operating on a fixed string instead of a variable.

  20. +
  21. Bugfix: Fixed issue #56. Release builders are reminded to run + the tests.

  22. +
  23. Bugfix: Fixed issue #55. For FreeBSD critcl's platform package + now identifies the Kernel ABI version. Initialization of the + cache directory now also uses platform::identify for the + default path, instead of platform::generic.

  24. +
  25. Bugfix: Fixed issue #58. Simplified the setup and use of + md5. CriTcl now makes use of its own package for md5, using + itself to built it. There is no chicken/egg problem with this + as the -pkg mode used for this does not use md5. That + is limited to mode compile & run.

  26. +
+
+

Changes for version 3.1.15

+
    +
  1. Fixed version number bogosity with 3.1.14.

  2. +
+
+

Changes for version 3.1.14

+
    +
  1. Fixed issue #36. Added message to target all of the + Makefile generated for TEA mode. Additionally tweaked other + parts of the output to be less noisy.

  2. +
  3. Accepted request implied in issue #54. Unconditionally save + the compiler/linker build log into key log of the + dictionary returned by cresults, and save a copy of only + the execution output in the new key exl ("execution + log").

  4. +
  5. Fixed issue #53. Clarified the documentation of commands + critcl::load and critcl::failed with regard + to their results and the throwing of errors (does not happen).

  6. +
  7. Fixed issue #48. Modified mode "compile & run" to allow new + declarations in a file, after it was build, instead of + erroring out. The new decls are build when needed. Mode + "precompile" is unchanged and will continue to trap the + situation.

  8. +
  9. Fixed issue #52. Updated the local Tcl/Tk headers to + 8.4.20, 8.5.13, and 8.6.4.

  10. +
  11. Fixed issue #45. New feature command critcl::cconst.

  12. +
  13. critcl::util: New command locate to find a + file across a set of paths, and report an error when not + found. This is for use in autoconf-like header-searches and + similar configuration tests.

  14. +
  15. Modified 'AbortWhenCalledAfterBuild' to dump the entire stack + (info frame!). This should make it easier to determine the + location of the troubling declaration.

  16. +
+
+

Changes for version 3.1.13

+
    +
  1. Merged PR #43. Fixed bug loading adjunct Tcl sources.

  2. +
  3. Fixes in documentation and generated code of package + "critcl::enum". Bumped to version 1.0.1.

  4. +
  5. Fixes in documentation of package "critcl::bitmap".

  6. +
  7. New package "critcl::emap". In essence a variant or cross of + "critcl::bitmap" with behaviour like "critcl::enum".

  8. +
  9. Merged PR #49. Fixed documentation typo.

  10. +
  11. Merged PR #46. Fixed documentation typo.

  12. +
  13. Merged PR #47. Fixes to test results to match the accumulated + code changes. Also made portable across Tcl versions (varying + error syntax).

  14. +
  15. New predefined argument- and result-type "wideint" mapping to + Tcl_WideInt.

  16. +
  17. New predefined argument-type "bytes" mapping to tuple of + byte-array data and length. Note: The existing "bytearray" + type (and its aliases) was left untouched, to keep backward + compatibility.

  18. +
  19. Modified the internal interface between the Tcl shim and C + function underneath "critcl::cproc" with respect to the + handling of optional arguments. + An optional argument "X" now induces the use of two C + arguments, "X" and "has_X". The new argument "has_X" is of + boolean (int) type. It is set to true when X is set, and set + to false when X has the default value. C code which cares + about knowing if the argument is default or not is now able to + check that quickly, without having to code the default value + inside. + NOTE: This change is visible in the output of the advanced + commands "argcnames", "argcsignature", "argvardecls", + and "argconversion".

  20. +
  21. Fixed issue #50 and documented the availability of variable + "interp" (type Tcl_Interp*) within "critcl::cinit" C code + fragments. + Note that while the old, undocumented name of the variable, + "ip", is still usable, it is deprecated. It will be fully + removed in two releases, i.e. for release 3.1.15. + The variable name was changed to be consistent with other code + environments.

  22. +
  23. Fixed issue #51. Disabled the generation of #line directives + for "critcl::config lines 0" coming from template files, or + code generated with them before the final value of this + setting was known.

  24. +
  25. Fixed issue with handling of namespaced package names in + "critcl::iassoc". Equivalent to a bug in "critcl::class" fixed + for critcl 3.1.1, critcl::class 1.0.1. + Note: "literals", "enum", "emap", and "bitmap" do not require + a fix as they are all built on top of "iassoc".

  26. +
+
+

Changes for version 3.1.12

+
    +
  1. Fixed issue 42. Clear ::errorInfo immediately after startup to + prevent leakage of irrelevant (caught) errors into our script + and confusing the usage code.

  2. +
  3. Fixed issue 40. Keep the order of libraries, and allow + duplicates. Both are things which are occasionally required for + proper linking.

  4. +
  5. Extended the utility package critcl::literals to + declare a cproc result-type for a pool.

    +

    Further fixed the generated header to handle multiple inclusion.

    +

    Bumped version to 1.1.

  6. +
  7. Fixed issue with utility package critcl::bitmap.

    +

    Fixed the generated header to handle multiple inclusion.

    +

    Bumped version to 1.0.1.

  8. +
  9. Created new utility package critcl::enum for the + quick and easy setup and use of mappings between C values + and Tcl strings. + Built on top of critcl::literals.

  10. +
  11. Added examples demonstrating the use of the utility packages + critcl::literals, + critcl::bitmap, and + critcl::enum

  12. +
+
+

Changes for version 3.1.11

+
    +
  1. Fixed issue #37, via pull request #38, with thanks to + Jos DeCoster. Information was stored into the v::delproc + and v::clientdata arrays using a different key than when + retrieving the same information, thus failing the latter.

  2. +
  3. New convenience command critcl::include for easy + inclusion of headers and other C files.

  4. +
  5. New command critcl::make to generate a local header of + other C files for use by other parts of a package through + inclusion.

  6. +
  7. New utility package critcl::literals for quick and + easy setup of and access to pools of fixed Tcl_Obj* strings. + Built on top of critcl::iassoc.

  8. +
  9. New utility package critcl::bitmap for quick and easy + setup and use of mappings between C bitsets and Tcl lists whose + string elements represent that set. + Built on top of critcl::iassoc.

  10. +
+
+

Changes for version 3.1.10

+
    +
  1. Fixed code version numbering forgotten with 3.1.9.

  2. +
  3. Fixed issue #35. In package mode (-pkg) the object cache + directory is unique to the process, thus we do not need + content-hashing to generate unique file names. A simple + counter is sufficient and much faster.

    +

    Note that mode "compile & run" is not as blessed and still + uses content-hasing with md5 to ensure unique file names + in its per-user object cache.

  4. +
  5. Fixed issue where the ccommand forgot to use its body as + input for the UUID generation. Thus ignoring changes to it in + mode compile & run, and not rebuilding a library for changed + sources. Bug and fix reported by Peter Spjuth.

  6. +
+
+

Changes for version 3.1.9

+
    +
  1. Fixed issue #27. Added missing platform definitions for + various alternate linux and OS X targets.

  2. +
  3. Fixed issue #28. Added missing -mXX flags for linking at the + linux-{32,64}-* targets.

  4. +
  5. Fixed issue #29. Replaced the use of raw "cheaders" + information in the processing of "cdefines" with the proper + include directives derived from it.

  6. +
  7. Fixed the issue behind rejected pull request #30 by Andrew + Shadura. Dynamically extract the stubs variable declarations + from the Tcl header files and generate matching variable + definitions for use in the package code. The generated code + will now be always consistent with the headers, even when + critcl's own copy of them is replaced by system headers.

  8. +
  9. Fixed issue #31. Accepted patch by Andrew Shadura, with + changes (comments), for easier integration of critcl with + OS package systems, replacing critcl's copies of Tcl headers + with their own.

  10. +
  11. Fixed issue #32. Merged pull request by Andrew Shadura. + Various typos in documentation and comments.

  12. +
  13. Fixed issue #34. Handle files starting with a dot better.

  14. +
+
+

Changes for version 3.1.8

+
    +
  1. Fixed issue with package indices generated for Tcl 8.4. + Join the list of commands with semi-colon, not newline.

  2. +
  3. Fixed issue #26 which brought up use-cases I had forgotten to + consider while fixing bug #21 (see critcl 3.1.6).

  4. +
+
+

Changes for version 3.1.7

+
    +
  1. Fixed issue #24. Extract and unconditionally display compiler + warnings found in the build log. Prevents users from missing + warnings which, while not causing the build to fail, may + still indicate problems.

  2. +
  3. New feature. Output hook. All non-messaging user output is now + routed through the command critcl::print, and users are + allowed to override it when using the critcl application-as-package.

  4. +
  5. New feature, by Ashok P. Nadkarni. Platform configurations can + inherit values from configurations defined before them.

  6. +
+
+

Changes for version 3.1.6

+
    +
  1. Fixed issue #21. While the multi-definition of the stub-table + pointer variables was ok with for all the C linkers seen so far + C++ linkers did not like this at all. Reworked the code to + ensure that this set of variables is generated only once, in + the wrapper around all the pieces to assemble.

  2. +
  3. Fixed issue #22, the handling of the command identifier + arguments of critcl::ccommand, critcl::cproc, and + critcl::cdata. We now properly allow any Tcl identifier + and generate proper internal C identifiers from them.

    +

    As part of this the signature of command critcl::name2c + changed. The command now delivers a list of four values instead + of three. The new value was added at the end.

    +

    Further adapted the implementation of package + critcl::class, a user of critcl::name2c. + This package is now at version 1.0.6 and requires critcl 3.1.6

    +

    Lastly fixed the mis-handling of option -cname in + critcl::ccommand, and critcl::cproc.

  4. +
  5. Fixed issue #23.

  6. +
+
+

Changes for version 3.1.5

+
    +
  1. Fixed issue #19. Made the regular expression extracting the + MSVC version number more general to make it work on german + language systems. This may have to be revisited in the future, + for other Windows locales.

  2. +
  3. Fixed issue #20. Made option -tea work on windows, at least in + a unix emulation environment like msys/mingw.

  4. +
+
+

Changes for version 3.1.4

+
    +
  1. Bugfix in package critcl::class. Generate a dummy + field in the class structure if the class has no class + variables. Without this change the structure would be empty, + and a number of compilers are not able to handle such a type.

  2. +
  3. Fixed a typo which broke the win64 configuration.

  4. +
  5. Fixed issue #16, a typo in the documentation of command + critcl::class.

  6. +
+
+

Changes for version 3.1.3

+
    +
  1. Enhancement. In detail:

  2. +
  3. Added new argument type "pstring", for "Pascal String", a + counted string, i.e. a combination of string pointer and string + length.

  4. +
  5. Added new methods critcl::argtypesupport and + ::critcl::argsupport to define and use additional + supporting code for an argument type, here used by "pstring" + above to define the necessary structure.

  6. +
  7. Semi-bugfixes in the packages critcl::class and + critcl::iassoc. Pragmas for the AS meta data scanner + to ensure that the template files are made part of the package. + Versions bumped to 1.0.4 and 1.0.1 respectively.

  8. +
+
+

Changes for version 3.1.2

+
    +
  1. Enhancement. In detail:

  2. +
  3. Extended critcl::cproc to be able to handle optional + arguments, in a limited way. This is automatically available to + critcl::class cproc-based methods as well.

  4. +
  5. Bugfix in lassign emulation for Tcl 8.4. Properly set + unused variables to the empty string. Bumped version of + emulation package lassign84 to 1.0.1.

  6. +
+
+

Changes for version 3.1.1

+
    +
  1. Bugfixes all around. In detail:

  2. +
  3. Fixed the generation of wrong#args errors for +critcl::cproc and derived code (critcl::class +cproc-based methods). Use NULL if there are no arguments, and +take the offset into account.

  4. +
  5. Fixed the handling of package names by +critcl::class. Forgot that they may contain namespace +separators. Bumped to version 1.0.1.

  6. +
  7. Extended a critcl::class generated error message in +instance creation for clarity. Bumped to version 1.0.2.

  8. +
+
+

Changes for version 3.1

+
    +
  1. Added a new higher-level package critcl::iassoc.

    +

    This package simplifies the creation of code associating data +with an interpreter via Tcl's Tcl_(Get|Set)AssocData() APIs. The +user can concentrate on his data while all the necessary boilerplate +C code to support this is generated by the package.

    +

    This package uses several of the new features which were added +to the core critcl package, see below.

  2. +
  3. Added the higher-level package critcl::class.

    +

    This package simplifies the creation of C level objects with +class and instance commands. The user can write a class definition +with class- and instance-variables and -methods similar to a TclOO +class, with all the necessary boilerplate C code to support this +generated by the package.

    +

    This package uses several of the new features which were added +to the core critcl package, see below.

  4. +
  5. Extended the API for handling TEApot metadata. Added the +command critcl::meta? to query the stored information. Main use +currently envisioned is retrieval of the current package's name by +utility commands, for use in constructed names. This particular +information is always available due to the static scan of the package +file on execution of the first critcl command.

    +

    The new packages critcl::iassoc and +critcl::class (see above) are users of this command.

  6. +
  7. Extended the API with a command, critcl::name2c, exposing +the process of converting a Tcl name into base name, namespace, and C +namespace. This enables higher-level code generators to generate the same +type of C identifiers as critcl itself.

    +

    The new package critcl::class (see above) is a user +of this command.

  8. +
  9. Extended the API with a command, critcl::source, +executing critcl commands found in a separate file in the context of +the current file. This enables easier management of larger bodies of +code as it allows the user to split such up into easier to digest +smaller chunks without causing the generation of multiple packages.

  10. +
  11. Related to the previous item, extended the API with commands to +divert collection of generated C code into memory. This makes it +easier to use the commands for embedded C code in higher-level code +generators.

    +

    See the section Advanced: Diversions for details of +the provided commands.

    +

    The new package critcl::class (see above) is a user +of these facilities.

  12. +
  13. Extended the API with commands helping developers with the +generation of proper C #line directives. This allows +higher-level code generators to generate and insert their own +directives, ensuring that compile errors in their code are properly +attributed.

    +

    See the section Advanced: Location management for +details of the provided commands.

    +

    The new packages critcl::iassoc and +critcl::class (see above) are users of these facilities.

  14. +
  15. Extended the API with commands giving users the ability to +define custom argument and result types for ::critcl::cproc.

    +

    See the section CriTcl cproc Type Reference for +details of the provided commands.

  16. +
+
+

Changes for version 3.0.7

+
    +
  1. Fixed the code generated by critcl::c++command. + The emitted code handed a non-static string table to + Tcl_GetIndexFromObj, in violation of the contract, which + requires the table to have a fixed address. This was a memory + smash waiting to happen. Thanks to Brian Griffin for alrerting + us to the general problem.

  2. +
+
+

Changes for version 3.0.6

+
    +
  1. Fixed github issue 10. The critcl application now delivers a + proper exit code (1) on build failure, instead of always + indicating success (status 0).

  2. +
  3. Fixed github issue 13. Handling of bufferoverflowU.lib for + release builds was inconsistent with handling for debug + builds. It is now identically handled (conditional) by + both cases.

  4. +
  5. Documentation cleanup, mainly in the installation guide, and + the README.md shown by github

  6. +
+
+

Changes for version 3.0.5

+
    +
  1. Fixed bug in the new code for #line pragmas triggered when + specifying C code without leading whitespace.

  2. +
  3. Extended the documentation to have manpages for the license, + source retrieval, installer, and developer's guides.

  4. +
+
+

Changes for version 3.0.4

+
    +
  1. Fixed generation of the package's initname when the incoming + code is read from stdin and has no proper path.

  2. +
  3. Fixed github issue 11. Now using /LIBPATH instead of -L + on Windows (libinclude configuration setting).

  4. +
  5. Extended critcl to handle -l:path format of -l options. + GNU ld 2.22+ handles this by searching for the path as + is. Good when specifying static libraries, as plain -l looks + for shared libraries in preference over static. critcl handles + it now, as older GNU ld's do not understand it, nor the + various vendor-specific linkers.

  6. +
  7. Fixed github issue #12. CriTcl now determines the version of + MSVC in use and uses it to switch between various link debug + options. Simplified the handling of bufferoverflowU.lib also, + making use of the same mechanism and collapsing the two + configurations sections we had back into one.

  8. +
  9. Reworked the insertion of #line pragmas into the generated C + code to avoid limitations on the line number argument imposed + by various compilers, and be more accurate.

  10. +
  11. Modified argument processing. Option -libdir now also + implies -L for its argument.

  12. +
  13. Extended handling of option -show (critcl::showconfig) + to list the path of the configuration file the data is coming + from. Good for debugging configuration processing.

  14. +
  15. Extended the build script with targets to regenerate the + embedded documentation, and diagrams, and to generate a + release.

  16. +
+
+

Changes for version 3.0.3

+
    +
  1. Fixed github issues 5 and 8, for the example build.tcl +scripts. Working around a missing variable ::errorInfo. It should +always be present, however there seem to be revisions of Tcl around +which violate this assumption.

  2. +
+
+

Changes for version 3.0.2

+
    +
  1. Fixed issue in compile-and-run mode where commands put into the +auto_index are not found by Tcl's [unknown] command.

  2. +
  3. Fixed an array key mismatch breaking usage of client data and +delete function for procedure. Reported by Jos DeCoster, with patch.

  4. +
  5. Implemented a command line option -L, an equivalent of +option -I, just for library search paths.

  6. +
  7. Fixed github issues 5 and 8. Working around a missing variable +::errorInfo. It should always be present, however there seem to be +revisions of Tcl around which violate this assumption.

  8. +
+
+

Changes for version 3.0.1

+
    +
  1. Bugfixes all around. In detail:

  2. +
  3. Fixed recording of Tcl version requirements. Keep package name +and version together, unbreaking generated meta data and generated +package load command.

  4. +
  5. Fixed the build scripts: When installing, or wrapping for TEA, +generate any missing directories

  6. +
  7. Modified the build scripts to properly exit the application +when the window of their GUI is closed through the (X) button.

  8. +
  9. Removed an 8.5-ism (open wb) which had slipped into the main +build script.

  10. +
  11. Modified the example build scripts to separate the output for +the different examples (and packages) by adding empty lines.

  12. +
  13. stack::c example bugfix: Include API declarations for use in +the companion files.

  14. +
  15. Extended the documentation: Noted the need for a working +installation of a C compiler.

  16. +
  17. Extended the Windows target definitions and code to handle the +manifest files used by modern MS development environments. Note that +this code handles both possibilities, environment using manifests, and +(old(er)) environments without.

  18. +
  19. Extended the Windows 64bit target definitions and code to +auto-detect the need for the helper library "bufferoverflowU.lib" and +reconfigure the compile and link commands appropriately. We assume +that the library must be linked when present. This should be no harm +if the library is present, yet not needed. Just superfluous. We search +for the library in the paths specified by the environment variable +LIB.

  20. +
+
+

Changes for version 3

+
    +
  1. The command critcl::platform was deprecated in version +2.1, superceded by critcl::targetplatform, yet kept for +compatibility. Now it has been removed.

  2. +
  3. The command critcl::compiled was kept with in version 2.1 +with semantics in contradiction to its, for compatibility. This +contradiction has been removed, changing the visible semantics of the +command to be in line with its name.

  4. +
  5. The change to version 3 became necessary because of the two +incompatible visible changes above.

  6. +
  7. Extended the application package with code handling a new +option -tea. Specifying this option invokes a special mode +where critcl generates a TEA package, i.e. wraps the input into a +directory hierarchy and support files which provide it TEA-lookalike +buildsystem.

    +

    This new option, and -pkg, exclude each other. If +both are specified the last used option takes precedence.

    +

    The generated package directory hierarchy is mostly +self-contained, but not fully. It requires not only a working +installation of Tcl, but also working installations of the packages +md5 and cmdline. Both of these are provided by the +Tcllib bundle. Not required, but recommended to have +installed are any of the packages which can accelerate md5's +operation, i.e. cryptkit, tcllibc, or +Trf.

  8. +
  9. Extended the critcl package with a new command +critcl::scan taking the path to a ".critcl" file, +statically scanning it, and returning license, version, a list of its +companion files, list of imported APIs, and list of +developer-specified custom configuration options. This data is the +foundation for the TEA wrapping described above.

    +

    Note that this is a static scan. While the other build +modes can (must) execute the ".critcl" file and make +platform-specific decisions regarding the assembled C code, companion +files, etc. the TEA wrap mode is not in a position to make +platform-specific decisions. It has to wrap everything which might +conceivably be needed when actually building. Hence the static scan. +This has however its own set of problems, namely the inability to +figure out any dynamic construction of companion file paths, at least +on its own. Thus:

  10. +
  11. Extended the API used by critcl-based packages with the command +critcl::owns. While this command is ignored by the regular build +modes the static scanner described above takes its arguments as the +names of companion files which have to be wrapped into the TEA package +and could not be figured by the scanner otherwise, like because of +dynamic paths to critcl::tsources, critcl::csources, +getting sourced directly, or simply being adjunct datafiles.

  12. +
  13. Extended the API used by critcl-based packages with the command +critcl::api for the management of stubs tables, be it their use, +and/or declaration and export.

    +

    Please see section Stubs Table Management of the +critcl package documentation for details.

  14. +
  15. Extended the API used by critcl-based packages with the command +critcl::userconfig for the management of developer-specified +custom configuration options, be it their use and/or declaration.

    +

    Please see section Custom Build Configuration of the +critcl package documentation for details.

  16. +
  17. Extended the API used by critcl-based packages with the +commands critcl::description, critcl::summary, +critcl::subject, critcl::meta, and +critcl::buildrequirement for the declaration of TEApot meta data +for/about the package.

    +

    Please see section Package Meta Data of the +critcl package documentation for details.

  18. +
+
+

Changes for version 2.1

+
    +
  1. Fixed bug where critcl::tsources interpreted relative +paths as relative to the current working directory instead of +relative to the ".critcl" file using the command, as all other +commands of this type do.

  2. +
  3. Fixed internals, preventing information collected for multiple +".critcl" files to leak between them. Notably, critcl::tk +is not a global configuration option anymore.

  4. +
  5. Fixed the command critcl::license to be a null-operation +in mode "compile & run", instead of throwing an error.

  6. +
  7. Fixed the critcl application's interference with the "compile & +run" result cache in -pkg mode by having it use a wholly +separate (and by default transient) directory for that mode.

  8. +
  9. Fixed bug where changes to a ".critcl" file did not result +in a rebuild for mode "compile & run". All relevant API commands now +ensure UUID changes.

  10. +
  11. Fixed bug in the backend handling of critcl::debug where +the companion c-sources of a ".critcl" file were not compiled +with debug options, although the ".critcl" file was.

  12. +
  13. Fixed bug in critcl::debug which prevented recognition of +mode "all" when it was not the first argument to the command.

  14. +
  15. Fixed bug in "preload.c" preventing its compilation on +non-windows platforms.

  16. +
  17. Fixed long-standing bug in the handling of namespace qualifiers +in the command name argument of critcl::cproc and +critcl::ccommand. It is now possible to specify a fully +qualified command name without issues.

  18. +
  19. Extended/reworked critcl::tsources to be the canonical +way of declaring ".tcl" companion files even for mode "compile & +run".

  20. +
  21. Extended/reworked critcl::tsources to allow the use of a +".critcl" file as its own Tcl companion file.

  22. +
  23. Extended critcl::framework to internally check for OS X +build target, and to ignore the declaration if its not.

  24. +
  25. Extended critcl::failed to be callable more than once in +a ".critcl" file. The first call forces the build, if it was not +done already, to get the result. Further calls return the cached +result of the first call.

  26. +
  27. Extended the handling of environment variable CC in the code +determining the compiler to use to deal with (i.e. remove) paths to +the compiler, compiler file extensions, and compiler options specified +after the compiler itself, leaving only the bare name of the compiler.

  28. +
  29. Extended the code handling the search for preloaded libraries +to print the paths it searched, making debugging of a search failure +easier.

  30. +
  31. A new command critcl::tcl can be used to declare the +version of Tcl minimally needed to build and run the ".critcl" +file and package. Defaults to 8.4 if not declared. Extended critcl to +have the stubs and headers for all of Tcl 8.4, 8.5, and 8.6.

  32. +
  33. A new command critcl::load forces the build and load of a +".critcl" file. This is the official way for overriding critcl's +default lazy-build-&-load-on-demand scheme for mode "compile & run".

    +

    Note that after using critcl::load / +critcl::failed in a ".critcl" file it is not possible to +use critcl commands in that file anymore. Doing so will throw an +error.

  34. +
  35. Extended the generation of '#line' pragmas to use +info frame (if available) to provide the C compiler with exact +line numbers into the ".critcl" file for the reporting of +warnings and errors.

  36. +
  37. Extended critcl::check with logging to help with +debugging build-time checks of the environment, plus an additional +optional argument to provide labeling.

  38. +
  39. Added a new command critcl::checklink which not only +tries to check the environment via compiling the code, but also +its linkability.

  40. +
  41. Added a new command critcl::msg for messaging, like +command critcl::error is for error reporting. Likewise this is a +hook a user of the package is allowed to override. The default +implementation, used by mode compile & run does nothing. The +implementation for mode generate package prints the message +to stdout.

    +

    Envisioned use is for the reporting of results determined by +critcl::check and critcl::checklink during building, to +help with debugging when something goes wrong with a check.

  42. +
  43. Exposed the argument processing internals of critcl::proc +for use by advanced users. The new commands are

    +
      +
    1. critcl::argnames

    2. +
    3. critcl::argcnames

    4. +
    5. critcl::argcsignature

    6. +
    7. critcl::argvardecls

    8. +
    9. critcl::argconversion

    10. +
    +

    Please see section Advanced Embedded C Code of the +critcl package documentation for details.

  44. +
  45. Extended the critcl package to intercept package +provide and record the file -> package name mapping. Plus other +internal changes now allow the use of namespaced package names while +still using proper path names and init function.

  46. +
  47. Dropped the unused commands critcl::optimize and +critcl::include.

  48. +
  49. Dropped -lib mode from the critcl application.

  50. +
  51. Dropped remnants of support for Tcl 8.3 and before.

  52. +
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_class.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_class.html new file mode 100644 index 00000000..52cb5ffd --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_class.html @@ -0,0 +1,683 @@ + +critcl::class - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::class(n) 1.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::class - CriTcl - Code Gen - C Classes

+
+ + +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the critcl::class +package. This package provides convenience commands for advanced +functionality built on top of the core.

+

With it a user wishing to create a C level object with class +and instance commands can concentrate on specifying the class- and +instance-variables and -methods in a manner similar to a TclOO class, +while all the necessary boilerplate around it is managed by this +package.

+

Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::class::define name script
+

This is the main command to define a new class name, where +name is the name of the Tcl command representing the class, +i.e. the class command. The script provides the +specification of the class, i.e. information about included headers, +class- and instance variables, class- and instance-methods, etc. +See the section Class Specification API below for the +detailed list of the available commands and their semantics.

+
+
+

Class Specification API

+

Here we documents all class specification commands available inside of +the class definition script argument of ::critcl::class::define.

+

General configuration

+
+
include path
+

This command specifies the path of a header file to include within the +code generated for the class. This is separate from the support +because the generated include directives will be put at the very +beginning of the generated code. This is done to allow the use of the +imported declarations within the instance type, and elsewhere.

+

Calls to this command are cumulative. +It is of course possible to not use this command at all, for classes +not making use of external definitions.

+

The result is the empty string.

+
support code
+

This command specifies supporting C code, i.e. any definitions (types, +functions, etc.) needed by the whole class and not fitting into +class- and instance-methods. The code is embedded at global level, +outside of any function or other definition.

+

Calls to this command are cumulative. +It is of course possible to not use this command at all, for classes +not requiring supporting code.

+

The result of the command is the empty string.

+
type name
+

This command specifies the name of an external C type to be used as +the type of the instance structure.

+

Initialization and release of the structure with the given type +are the responsibility of the user, through constructor and +destructor code fragments.

+

Attention: Using this command precludes the use of +regular class- and instance variables. It further precludes the use of +method-introspection as well, as this make use of generated +instance-variables.

+

If class- and/or instance-variable have to be used in +conjunction with an external C type, simply create and use a class- or +instance-variable with that type.

+

The result of the command is the empty string.

+
+
+

Class lifetime management

+
+
classconstructor body
+

This command specifies a C code block surrounding the initialization +of the class variables, i.e. the fields of the class structure. +Note that allocation and release of the class structure itself +is done by the system andf not the responsibility of the user.

+

For the initialization (and release) of a class variable it is +recommended to use the constructor and destructor +arguments of the variable's definition (See command +classvariable) for this instead of using a separate +classconstructor.

+

This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate.

+

The C code blocks of multiple calls (including the constructors +of classvariable definitions) are executed in order of specification.

+

The result of the command is the empty string.

+

The C code in body has access to the following +environment:

+
+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure will be associated with. It enables the generation +of a Tcl error message should construction fail.

+
class
+

Pointer to the class structure to initialize.

+
error
+

A C code label the constructor can jump to should it have +to signal a construction failure. It is the responsibility of the +constructor to release any variables already initialized before +jumping to this label. This also why the 'execution in order of +specification' is documented and can be relied on. It gives us the +knowledge which other constructors have already been run and +initialized what other fields.

+
+
classdestructor body
+

This command specifies a C code block surrounding the release of the +class variables, i.e. the fields of the class structure. +Note that allocation and release of the class structure itself +is done by the system and not the responsibility of the user.

+

For the initialization (and release) of a class variable it is +recommended to use the constructor and destructor +arguments of the variable's definition (See command +classvariable) for this instead of using a separate +classconstructor.

+

This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate.

+

The C code blocks of multiple calls (including the constructors +of class variable definitions) are executed in order of specification.

+

The result of the command is the empty string.

+

The C code in body has access to the same +environment as the class constructor code blocks.

+
+
+

Instance lifetime management

+
+
constructor body ?postbody?
+

This command specifies a C code block surrounding the initialization +of the instance variables, i.e. the fields of the instance structure. +Note that allocation and release of the instance structure +itself is done by the system and not the responsibility of the user. +On the other hand, if an external type was specified +for the instance structure, then instance variables are not possible, +and the system has no knowledge of the type's structure. In that case +it is the responsibility of the body to allocate and free the +structure itself too.

+

For the initialization (and release) of an instance variable it +is recommended to use the constructor and destructor +arguments of the variable's definition (See command insvariable) +for this instead of using a separate constructor.

+

This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate.

+

The C code blocks of multiple calls (including the constructors +of instance variable definitions) are executed in order of specification.

+

The result of the command is the empty string.

+

The C code in body has access to the following +environment:

+
+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure will be associated with. It enables the generation +of a Tcl error message should construction fail.

+
instance
+

Pointer to the instance structure to initialize.

+
error
+

A C code label the constructor can jump to should it have +to signal a construction failure. It is the responsibility of the +constructor to release any variables already initialized before +jumping to this label. This also why the 'execution in order of +specification' is documented and can be relied on. It gives us the +knowledge which other constructors have already been run and +initialized what other fields.

+
+

The C code in postbody is responsible for construction +actions to be done after the primary construction was done and the +Tcl-level instance command was successfully created. It has access to +a slightly different environment:

+
+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure will be associated with. It enables the generation +of a Tcl error message should construction fail.

+
instance
+

Pointer to the instance structure to initialize.

+
cmd
+

The Tcl_Command token of the Tcl-level instance +command.

+
fqn
+

The fully qualified name of the instance command, +stored in a Tcl_Obj*.

+
+
destructor body
+

This command specifies a C code block surrounding the release of the +instance variables, i.e. the fields of the instance structure. +Note that allocation and release of the instance structure +itself is done by the system and not the responsibility of the user. +On the other hand, if an external type was specified +for the instance structure, then instance variables are not possible, +and the system has no knowledge of the type's structure. In that case +it is the responsibility of the body to allocate and free the +structure itself too.

+

For the initialization (and release) of an instance variable it +is recommended to use the constructor and destructor +arguments of the variable's definition (See command insvariable) +for this instead of using a separate constructor.

+

This is an optional command. Using it more than once is allowed +too and each use will add another C code fragment to use during +construction. I.e. multiple calls aggregate.

+

The C code blocks of multiple calls (including the constructors +of instance variable definitions) are executed in order of specification.

+

The result of the command is the empty string.

+

The C code in body has access to the following +environment:

+
+
instance
+

Pointer to the instance structure to release.

+
+
+
+

Class variables and methods

+
+
classvariable ctype name ?comment? ?constructor? ?destructor?
+

This command specifies a field in the class structure of the class. +Multiple fields can be specified, and are saved in the order +specified.

+

Attention: Specification of a class variable precludes +the use of an external C type for the instance structure.

+

Attention: Specification of a class variable +automatically causes the definition of an instance variable named +class, pointing to the class structure.

+

Beyond the basic name and C type of the new variable the +definition may also contain a comment describing it, and C code +blocks to initialize and release the variable. +These are effectively local forms of the commands +classconstructor and classdestructor. Please read their +descriptions for details regarding the C environment available to the +code.

+

The comment, if specified will be embedded into the generated C +code for easier cross-referencing from generated ".c" file to +class specification.

+
classmethod name command arguments body
+

This command specifies a class method and the C code block +implementing its functionality. This is the first of three forms. The +method is specified like a critcl::ccommand, with a fixed set of +C-level arguments. The body has to perform everything +(i.e. argument extraction, checking, result return, and of course the +actual functionality) by itself.

+

For this the body has access to

+
+
class
+

Pointer to the class structure.

+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure is associated with

+
objc
+

The number of method arguments.

+
objv
+

The method arguments, as C array of Tcl_Obj pointers.

+
+

The arguments of the definition are only a human readable form +of the method arguments and syntax and are not used in the C code, +except as comments put into the generated code. Again, it is the +responsibility of the body to check the number of arguments, +extract them, check their types, etc.

+
classmethod name proc arguments resulttype body
+

This command specifies a class method and the C code block +implementing its functionality. This is the second of three forms. The +method is specified like a critcl::cproc. +Contrary to the first variant here the arguments are computer +readable, expected to be in the same format as the arguments of +critcl::cproc. The same is true for the resulttype. +The system automatically generates a wrapper doing argument checking +and conversion, and result conversion, like for critcl::cproc.

+

The body has access to

+
+
class
+

Pointer to the class structure.

+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure is associated with

+
...
+

All arguments under their specified names and C types +as per their definition.

+
+
classmethod name as funname ?arg...?
+

This command specifies a class method and the C code block +implementing its functionality. This is the third and last of three +forms.

+

The class method is implemented by the external function +funname, i.e. a function which is declared outside of the class +code itself, or in a support block.

+

It is assumed that the first four arguments of that function +represent the parameters

+
+
class
+

Pointer to the class structure.

+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +class structure is associated with

+
objc
+

The number of method arguments.

+
objv
+

The method arguments, as C array of Tcl_Obj pointers.

+
+

Any additional arguments specified will be added after these and are +passed into the C code as is, i.e. are considered to be C expressions.

+
+
+

Instance variables and methods

+
+
insvariable ctype name ?comment? ?constructor? ?destructor?
+

This command specifies a field in the instance structure of the class. +Multiple fields can be specified, and are saved in the order +specified.

+

Attention: Specification of an instance variable +precludes the use of an external C type for the instance +structure.

+

Attention: Specification of an instance variable +automatically causes the definition of an instance variable of type +Tcl_Command, and named cmd, holding the token of the +instance command, and the definition of an instance method named +destroy. This implicit instance variable is managed by the +system.

+

Beyond the basic name and C type of the new variable the +definition may also contain a comment describing it, and C code +blocks to initialize and release the variable. +These are effectively local forms of the commands constructor +and destructor. Please read their descriptions for details +regarding the C environment available to the code.

+

The comment, if specified will be embedded into the generated C +code for easier cross-referencing from generated ".c" file to +class specification.

+
method name command arguments body
+

This command specifies an instance method and the C code block +implementing its functionality. This is the first of three forms. The +method is specified like a critcl::ccommand, with a fixed set of +C-level arguments. The body has to perform everything +(i.e. argument extraction, checking, result return, and of course the +actual functionality) by itself.

+

For this the body has access to

+
+
instance
+

Pointer to the instance structure.

+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure is associated with

+
objc
+

The number of method arguments.

+
objv
+

The method arguments, as C array of Tcl_Obj pointers.

+
+

The arguments of the definition are only a human readable form +of the method arguments and syntax and are not used in the C code, +except as comments put into the generated code. Again, it is the +responsibility of the body to check the number of arguments, +extract them, check their types, etc.

+
method name proc arguments resulttype body
+

This command specifies an instance method and the C code block +implementing its functionality. This is the second of three +forms. The method is specified like a critcl::cproc. +Contrary to the first variant here the arguments are computer +readable, expected to be in the same format as the arguments of +critcl::cproc. The same is true for the resulttype. +The system automatically generates a wrapper doing argument checking +and conversion, and result conversion, like for critcl::cproc.

+

The body has access to

+
+
instance
+

Pointer to the instance structure.

+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure is associated with

+
...
+

All arguments under their specified names and C types +as per their definition.

+
+
method name as funname ?arg...?
+

This command specifies an instance method and the C code block +implementing its functionality. This is the third and last of three +forms.

+

The instance method is implemented by the external function +funname, i.e. a function which is declared outside of the instance +code itself, or in a support block.

+

It is assumed that the first four arguments of that function +represent the parameters

+
+
instance
+

Pointer to the instance structure.

+
interp
+

Pointer to the Tcl interpreter (Tcl_Interp*) the +instance structure is associated with

+
objc
+

The number of method arguments.

+
objv
+

The method arguments, as C array of Tcl_Obj pointers.

+
+

Any additional arguments specified will be added after these and are +passed into the C code as is, i.e. are considered to be C expressions.

+
method_introspection
+

This command generates one class- and one instance-method both of +which will return a list of the instance methods of the class, and +supporting structures, like the function to compute the information, +and a class variable caching it.

+

The two methods and the class variable are all named +methods.

+
+
+

Context dependent interactions

+

This section documents the various interactions between the +specification commands. While these are are all documented with the +individual commands here they are pulled together to see at a glance.

+
    +
  1. If you are using the command type to specify an external + C type to use for the instance structure you are subject to + the following constraints and rules:

    +
      +
    1. You cannot define your own instance variables.

    2. +
    3. You cannot define your own class variables.

    4. +
    5. You cannot use method_introspection.

    6. +
    7. You have to allocate and release the instance structure on your + own, through constructor and destructor code blocks.

    8. +
    +
  2. +
  3. If you declare class variables you are subject to the + following constraints and rules:

    +
      +
    1. You cannot use type.

    2. +
    3. The system generates an instance variable class for + you, which points from instance to class structure. This makes + you also subject to the rules below, for instance variables.

    4. +
    +
  4. +
  5. If you declare instance variables (possibly automatic, see + above) you are subject to following constraints and rules:

    +
      +
    1. You cannot use type.

    2. +
    3. The system generates and manages an instance variable + cmd for you, which holds the Tcl_Command token + of the instance command.

    4. +
    5. The system generates an instance method destroy for + you.

    6. +
    7. The system manages allocation and release of the instance + structure for you. You have to care only about the instance + variables themselves.

    8. +
    +
  6. +
+
+
+

Example

+

The example shown below is the specification of queue data structure, +with most of the method implementations and support code omitted to +keep the size down.

+

The full implementation can be found in the directory +"examples/queue" of the critcl source distribution/repository.

+
+package require Tcl 8.6
+package require critcl 3.2
+critcl::buildrequirement {
+    package require critcl::class ; # DSL, easy spec of Tcl class/object commands.
+}
+critcl::cheaders util.h
+critcl::class::define ::queuec {
+    include util.h
+    insvariable Tcl_Obj* unget {
+	List object unget elements
+    } {
+	instance->unget = Tcl_NewListObj (0,NULL);
+	Tcl_IncrRefCount (instance->unget);
+    } {
+	Tcl_DecrRefCount (instance->unget);
+    }
+    insvariable Tcl_Obj* queue {
+	List object holding the main queue
+    } {
+	instance->queue = Tcl_NewListObj (0,NULL);
+	Tcl_IncrRefCount (instance->queue);
+    } {
+	Tcl_DecrRefCount (instance->queue);
+    }
+    insvariable Tcl_Obj* append {
+	List object holding new elements
+    } {
+	instance->append = Tcl_NewListObj (0,NULL);
+	Tcl_IncrRefCount (instance->append);
+    } {
+	Tcl_DecrRefCount (instance->append);
+    }
+    insvariable int at {
+	Index of next element to return from the main queue
+    } {
+	instance->at = 0;
+    }
+    support {... queue_peekget, queue_size, etc.}
+    method clear {} {...}
+    method destroy {...}
+    method get  as queue_peekget 1
+    method peek as queue_peekget 0
+    method put {item ...}
+    method size {} {
+	if ((objc != 2)) {
+	    Tcl_WrongNumArgs (interp, 2, objv, NULL);
+	    return TCL_ERROR;
+	}
+	Tcl_SetObjResult (interp, Tcl_NewIntObj (queue_size (instance, NULL, NULL, NULL)));
+	return TCL_OK;
+    }
+    method unget {item} {...}
+}
+package provide queuec 1
+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_cproc.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_cproc.html new file mode 100644 index 00000000..f0045a0a --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_cproc.html @@ -0,0 +1,1116 @@ + +critcl_cproc_types - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_cproc_types(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_cproc_types - CriTcl cproc Type Reference

+
+ + +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is a breakout of the descriptions for the predefined argument- and result-types usable +with the critcl::cproc command, as detailed in the reference manpage for the critcl +package, plus the information on how to extend the predefined set with custom types. The breakout +was made to make this information easier to find (toplevel document vs. having to search the large +main reference).

+

Its intended audience are developers wishing to write Tcl packages with embedded C code.

+
+

Standard argument types

+

Before going into the details first a quick overview:

+
+CriTcl type      | C type         | Tcl type  | Notes
+---------------- | -------------- | --------- | ------------------------------
+Tcl_Interp*      | Tcl_Interp*    | n/a       | Special, only first
+---------------- | -------------- | --------- | ------------------------------
+Tcl_Obj*         | Tcl_Obj*       | Any       | Read-only
+object           |                |           | Alias of Tcl_Obj* above
+list             | critcl_list    | List      | Read-only
+[], [*]          |                |           | Alias of list above
+---------------- | -------------- | --------- | ------------------------------
+[N]              |                |           | Restricted list-types.
+type[], type[N]  |                |           | Length-limited ([..]), expected
+[]type, [N]type  |                |           | element type, or both.
+                 |                |           |
+                 |                |           | Element types can be all known argument
+                 |                |           | types, except for any kind of list.
+                 |                |           | IOW multi-dimensional lists are not
+                 |                |           | supported.
+---------------- | -------------- | --------- | ------------------------------
+char*            | const char*    | Any       | Read-only, string rep
+pstring          | critcl_pstring | Any       | Read-only
+bytes            | critcl_bytes   | ByteArray | Read-only
+---------------- | -------------- | --------- | ------------------------------
+int              | int            | Int       |
+long             | long           | Long      |
+wideint          | Tcl_WideInt    | WideInt   |
+double           | double         | Double    |
+float            | float          | Double    |
+---------------- | -------------- | --------- | ------------------------------
+X > N            |                |           | For X in int ... float above.
+X >= N           |                |           | The C types are as per the base type X.
+X < N            |                |           | N, A, B are expected to be constant integer
+X <= N           |                |           | numbers for types int, long,
+X > A < B        |                |           | and wideint. For types double
+etc.             |                |           | and float the N, A, and B can be floating
+                 |                |           | point numbers. Multiple restrictions are
+                 |                |           | fused as much as possible to yield at most
+                 |                |           | both upper and lower limits.
+---------------- | -------------- | --------- | ------------------------------
+boolean          | int            | Boolean   |
+bool             |                |           | Alias of boolean above
+---------------- | -------------- | --------- | ------------------------------
+channel          | Tcl_Channel    | String    | Assumed to be registered
+unshared-channel | Tcl_Channel    | String    | As above, limited to current interpreter
+take-channel     | Tcl_Channel    | String    | As above, C code takes ownership
+
+

And now the details:

+
+
Tcl_Interp*
+

Attention: This is a special argument type. It can +only be used by the first argument of a function. +Any other argument using it will cause critcl to throw an error.

+

When used, the argument will contain a reference to the current +interpreter that the function body may use. Furthermore the argument +will not be an argument of the Tcl command for the function.

+

This is useful when the function has to do more than simply +returning a value. Examples would be setting up error messages on +failure, or querying the interpreter for variables and other data.

+
Tcl_Obj*
+
+
object
+

The function takes an argument of type Tcl_Obj*. +No argument checking is done. +The Tcl level word is passed to the argument as-is. +Note that this value must be treated as read-only (except for +hidden changes to its intrep, i.e. shimmering).

+
pstring
+

The function takes an argument of type critcl_pstring +containing the original Tcl_Obj* reference of the Tcl argument, +plus the length of the string and a pointer to the character array.

+
+typedef struct critcl_pstring {
+    Tcl_Obj*    o;
+    const char* s;
+    int         len;
+} critcl_pstring;
+
+

Note the const. The string is read-only. Any +modification can have arbitrary effects, from pulling out the rug +under the script because of string value and internal representation +not matching anymore, up to crashes anytime later.

+
list
+
+
[]
+
+
[*]
+

The function takes an argument of type critcl_list containing the original Tcl_Obj* +reference of the Tcl argument, plus the length of the Tcl list and a pointer to the array of the +list elements.

+
+typedef struct critcl_list {
+    Tcl_Obj*        o;
+    Tcl_Obj* const* v;
+    int             c;
+} critcl_list;
+
+

The Tcl argument must be convertible to List, an error is thrown otherwise.

+

Note the const. The list is read-only. Any modification can have arbitrary +effects, from pulling out the rug under the script because of string value and internal +representation not matching anymore, up to crashes anytime later.

+

Further note that the system understands a number of more complex syntactical forms which all +translate into forms of lists under the hood, as described by the following points.

+
[N]
+

A list type with additional checks limiting the length to N, an integer +number greater than zero.

+
[]type
+
+
type[]
+

A list type whose elements all have to be convertible for type. All known +types, including user-defined, are allowed, except for list and derivates. In other +words, multi-dimensional lists are not supported.

+

The function will take a structure argument of the general form

+
+typedef struct critcl_list_... {
+    Tcl_Obj* o;
+    int      c;
+    (Ctype)* v;
+} critcl_list_...;
+
+

where (Ctype) represents the C type for values of type type.

+
[N]type
+
+
type[N]
+

These are list types combining the elements of

+
[N]
+

and

+
[]type
+

.

+

As an example, the specification of

+
int[3] a
+

describes argument a +as a list of exactly 3 elements, all of which have to be of type int.

+

Note that this example can also be written in the more C-like form of

+
int a[3]
+

. The system will translate this internally to the first shown form.

+
bytes
+

This is the new and usable ByteArray type.

+

The function takes an argument of type critcl_bytes +containing the original Tcl_Obj* reference of the Tcl argument, +plus the length of the byte array and a pointer to the byte data.

+
+typedef struct critcl_bytes {
+    Tcl_Obj*             o;
+    const unsigned char* s;
+    int                len;
+} critcl_list;
+
+

The Tcl argument must be convertible to ByteArray, an error is +thrown otherwise.

+

Note the const. The bytes are read-only. Any +modification can have arbitrary effects, from pulling out the rug +under the script because of string value and internal representation +not matching anymore, up to crashes anytime later.

+
char*
+

The function takes an argument of type const char*. +The string representation of the Tcl argument is passed in.

+

Note the const. The string is read-only. Any +modification can have arbitrary effects, from pulling out the rug +under the script because of string value and internal representation +not matching anymore, up to crashes anytime later.

+
double
+

The function takes an argument of type double. +The Tcl argument must be convertible to Double, an error is thrown otherwise.

+
double > N
+
+
double >= N
+
+
double < N
+
+
double <= N
+

These are variants of double above, restricting the argument value to the shown relation. +An error is thrown for Tcl arguments outside of the specified range.

+

The limiter N has to be a constant floating point value.

+

It is possible to use multiple limiters. +For example double > A > B <= C. +The system will fuse them to a single upper/lower limit (or both).

+

The system will reject limits describing an empty range of values, or a range containing only +a single value.

+
float
+

The function takes an argument of type float. +The Tcl argument must be convertible to Double, an error is thrown otherwise.

+
float > N
+
+
float >= N
+
+
float < N
+
+
float <= N
+

These are variants of float above, restricting the argument value to the shown relation. +An error is thrown for Tcl arguments outside of the specified range.

+

The limiter N has to be a constant floating point value.

+

It is possible to use multiple limiters. +For example float > A > B <= C. +The system will fuse them to a single upper/lower limit (or both).

+

The system will reject limits describing an empty range of values, or a range containing only +a single value.

+
boolean
+
+
bool
+

The function takes an argument of type int. +The Tcl argument must be convertible to Boolean, an error is +thrown otherwise.

+
channel
+

The function takes an argument of type Tcl_Channel. +The Tcl argument must be convertible to type Channel, an error +is thrown otherwise. +The channel is further assumed to be already registered +with the interpreter.

+
unshared-channel
+

This type is an extension of channel above. +All of the information above applies.

+

Beyond that the channel must not be shared by multiple +interpreters, an error is thrown otherwise.

+
take-channel
+

This type is an extension of unshared-channel above. +All of the information above applies.

+

Beyond that the code removes the channel from the current +interpreter without closing it, and disables all pre-existing event +handling for it.

+

With this the function takes full ownership of the channel in +question, taking it away from the interpreter invoking it. It is then +responsible for the lifecycle of the channel, up to and including +closing it.

+

Should the system the function is a part of wish to return +control of the channel back to the interpeter it then has to use the +result type return-channel. This will undo the registration +changes made by this argument type. +Note however that the removal of pre-existing event handling +done here cannot be undone.

+

Attention Removal from the interpreter without closing +the channel is effected by incrementing the channel's reference count +without providing an interpreter, before decrementing the same for the +current interpreter. This leaves the overall reference count intact +without causing Tcl to close it when it is removed from the +interpreter structures. At this point the channel is effectively a +globally-owned part of the system not associated with any interpreter.

+

The complementary result type then runs this sequence in +reverse. And if the channel is never returned to Tcl either the +function or the system it is a part of have to unregister the global +reference when they are done with it.

+
int
+

The function takes an argument of type int. +The Tcl argument must be convertible to Int, an error is thrown otherwise.

+
int > N
+
+
int >= N
+
+
int < N
+
+
int <= N
+

These are variants of int above, restricting the argument value to the shown +relation. +An error is thrown for Tcl arguments outside of the specified range.

+

The limiter N has to be a constant integer value.

+

It is possible to use multiple limiters. +For example int > A > B <= C. +The system will fuse them to a single upper/lower limit (or both).

+

The system will reject limits describing an empty range of values, or a range +containing only a single value.

+
long
+

The function takes an argument of type long int. +The Tcl argument must be convertible to Long, an error is thrown otherwise.

+
long > N
+
+
long >= N
+
+
long < N
+
+
long <= N
+

These are variants of long above, restricting the argument value to the shown +relation. +An error is thrown for Tcl arguments outside of the specified range.

+

The limiter N has to be a constant integer value.

+

It is possible to use multiple limiters. +For example long > A > B <= C. +The system will fuse them to a single upper/lower limit (or both).

+

The system will reject limits describing an empty range of values, or a range +containing only a single value.

+
wideint
+

The function takes an argument of type Tcl_WideInt. +The Tcl argument must be convertible to WideInt, an error is thrown otherwise.

+
wideint > N
+
+
wideint >= N
+
+
wideint < N
+
+
wideint <= N
+

These are variants of wideint above, restricting the argument value to the shown +relation. +An error is thrown for Tcl arguments outside of the specified range.

+

The limiter N has to be a constant integer value.

+

It is possible to use multiple limiters. +For example wideint > A > B <= C. +The system will fuse them to a single upper/lower limit (or both).

+

The system will reject limits describing an empty range of values, or a range +containing only a single value.

+
void*
+
+
+
+

Standard result types

+

Before going into the details first a quick overview:

+
+CriTcl type    | C type         | Tcl type  | Notes
+-------------- | -------------- | --------- | ------------------------------
+void           | n/a            | n/a       | Always OK. Body sets result
+ok             | int            | n/a       | Result code. Body sets result
+-------------- | -------------- | --------- | ------------------------------
+int            | int            | Int       |
+boolean        |                |           | Alias of int above
+bool           |                |           | Alias of int above
+long           | long           | Long      |
+wideint        | Tcl_WideInt    | WideInt   |
+double         | double         | Double    |
+float          | float          | Double    |
+-------------- | -------------- | --------- | ------------------------------
+char*          | char*          | String    | Makes a copy
+vstring        |                |           | Alias of char* above
+const char*    | const char*    |           | Behavior of char* above
+-------------- | -------------- | --------- | ------------------------------
+string         |                | String    | Freeable string set directly
+               |                |           | No copy is made
+dstring        |                |           | Alias of string above
+-------------- | -------------- | --------- | ------------------------------
+               |                |           | For all below: Null is ERROR
+               |                |           | Body has to set any message
+Tcl_Obj*       | Tcl_Obj*       | Any       | refcount --
+object         |                |           | Alias of Tcl_Obj* above
+Tcl_Obj*0      |                | Any       | refcount unchanged
+object0        |                |           | Alias of Tcl_Obj*0 above
+-------------- | -------------- | --------- | ------------------------------
+known-channel  | Tcl_Channel    | String    | Assumes to already be registered
+new-channel    | Tcl_Channel    | String    | New channel, will be registered
+return-channel | Tcl_Channel    | String    | Inversion of take-channel
+
+

And now the details:

+
+
Tcl_Obj*
+
+
object
+

If the returned Tcl_Obj* is NULL, the Tcl return code +is TCL_ERROR and the function should set an error mesage +as the interpreter result. Otherwise, the returned Tcl_Obj* is +set as the interpreter result.

+

Note that setting an error message requires the function body +to have access to the interpreter the function is running in. See the +argument type Tcl_Interp* for the details on how to make that +happen.

+

Note further that the returned Tcl_Obj* should have a +reference count greater than 0. This is because the converter +decrements the reference count to release possession after setting the +interpreter result. It assumes that the function incremented the +reference count of the returned Tcl_Obj*. +If a Tcl_Obj* with a reference count of 0 were +returned, the reference count would become 1 when set as the +interpreter result, and immediately thereafter be decremented to +0 again, causing the memory to be freed. The system is then +likely to crash at some point after the return due to reuse of the +freed memory.

+
Tcl_Obj*0
+
+
object0
+

Like Tcl_Obj* except that this conversion assumes that the +returned value has a reference count of 0 and +does not decrement it. Returning a value whose reference +count is greater than 0 is therefore likely to cause a memory +leak.

+

Note that setting an error message requires the function body +to have access to the interpreter the function is running in. See the +argument type Tcl_Interp* for the details on how to make that +happen.

+
new-channel
+

A String Tcl_Obj holding the name of the returned +Tcl_Channel is set as the interpreter result. +The channel is further assumed to be new, and therefore +registered with the interpreter to make it known.

+
known-channel
+

A String Tcl_Obj holding the name of the returned +Tcl_Channel is set as the interpreter result. +The channel is further assumed to be already registered +with the interpreter.

+
return-channel
+

This type is a variant of new-channel above. +It varies slightly from it in the registration sequence to be properly +complementary to the argument type take-channel. +A String Tcl_Obj holding the name of the returned +Tcl_Channel is set as the interpreter result. +The channel is further assumed to be new, and therefore +registered with the interpreter to make it known.

+
char*
+
+
vstring
+

A String Tcl_Obj holding a copy of the returned +char* is set as the interpreter result. If the value is +allocated then the function itself and the extension it is a part of +are responsible for releasing the memory when the data is not in use +any longer.

+
const char*
+

Like char* above, except that the returned string is +const-qualified.

+
string
+
+
dstring
+

The returned char* is directly set as the interpreter result +without making a copy. Therefore it must be dynamically +allocated via Tcl_Alloc. Release happens automatically when the +Interpreter finds that the value is not required any longer.

+
double
+
+
float
+

The returned double or float is converted to a Double +Tcl_Obj and set as the interpreter result.

+
boolean
+
+
bool
+

The returned int value is converted to an Int Tcl_Obj and set as +the interpreter result.

+
int
+

The returned int value is converted to an Int Tcl_Obj and set as +the interpreter result.

+
long
+

The returned long int value is converted to a Long Tcl_Obj and +set as the interpreter result.

+
wideint
+

The returned Tcl_WideInt value is converted to a WideInt Tcl_Obj +and set as the interpreter result.

+
ok
+

The returned int value becomes the Tcl return code. +The interpreter result is left untouched and can be set by the +function if desired. Note that doing this requires the function body +to have access to the interpreter the function is running in. See the +argument type Tcl_Interp* for the details on how to make that +happen.

+
void
+

The function does not return a value. +The interpreter result is left untouched and can be set by the function if +desired.

+
+
+

Advanced: Adding types

+

While the critcl::cproc command understands the most common C +types (as per the previous 2 sections), sometimes this is not enough.

+

To get around this limitation the commands in this section +enable users of critcl to extend the set of argument and +result types understood by critcl::cproc. In other words, they +allow them to define their own, custom, types.

+
+
::critcl::has-resulttype name
+

This command tests if the named result-type is known or not. +It returns a boolean value, true if the type is known and +false otherwise.

+
::critcl::resulttype name body ?ctype?
+

This command defines the result type name, and associates it +with the C code doing the conversion (body) from C to Tcl. +The C return type of the associated function, also the C type of the +result variable, is ctype. This type defaults to name if +it is not specified.

+

If name is already declared an error is thrown. +Attention! The standard result type void is special as +it has no accompanying result variable. This cannot be expressed +by this extension command.

+

The body's responsibility is the conversion of the +functions result into a Tcl result and a Tcl status. The first has to +be set into the interpreter we are in, and the second has to be +returned.

+

The C code of body is guaranteed to be called last in the +wrapper around the actual implementation of the cproc in +question and has access to the following environment:

+
+
interp
+

A Tcl_Interp* typed C variable referencing the + interpreter the result has to be stored into.

+
rv
+

The C variable holding the result to convert, of type + ctype.

+
+

As examples here are the definitions of two standard result types:

+
+    resulttype int {
+	Tcl_SetObjResult(interp, Tcl_NewIntObj(rv));
+	return TCL_OK;
+    }
+    resulttype ok {
+	/* interp result must be set by cproc body */
+	return rv;
+    } int
+
+
+
::critcl::resulttype name = origname
+

This form of the resulttype command declares name as an +alias of result type origname, which has to be defined +already. If this is not the case an error is thrown.

+
::critcl::has-argtype name
+

This command tests if the named argument-type is known or not. +It returns a boolean value, true if the type is known and +false otherwise.

+
::critcl::argtype name body ?ctype? ?ctypefun?
+

This command defines the argument type name, and associates it +with the C code doing the conversion (body) from Tcl to C. +ctype is the C type of the variable to hold the conversion result +and ctypefun is the type of the function argument itself. +Both types default to name if they are the empty string or are not +provided.

+

If name is already declared an error is thrown.

+

body is a C code fragment that converts a Tcl_Obj* into a +C value which is stored in a helper variable in the underlying function.

+

body is called inside its own code block to isolate local +variables, and the following items are in scope:

+
+
interp
+

A variable of type Tcl_Interp* which is the + interpreter the code is running in.

+
@@
+

A placeholder for an expression that evaluates to the + Tcl_Obj* to convert.

+
@A
+

A placeholder for the name of the variable to store the + converted argument into.

+
+

As examples, here are the definitions of two standard argument types:

+
+    argtype int {
+	if (Tcl_GetIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR;
+    }
+    argtype float {
+	double t;
+	if (Tcl_GetDoubleFromObj(interp, @@, &t) != TCL_OK) return TCL_ERROR;
+	@A = (float) t;
+    }
+
+
+
::critcl::argtype name = origname
+

This form of the argtype command declares name as an alias +of argument type origname, which has to be defined already. If +this is not the case an error is thrown.

+
::critcl::argtypesupport name code ?guard?
+

This command defines a C code fragment for the already defined +argument type name which is inserted before all functions +using that type. Its purpose is the definition of any supporting C +types needed by the argument type. +If the type is used by many functions the system ensures that only the +first of the multiple insertions of the code fragment is active, and +the others disabled. +The guard identifier is normally derived from name, but can also +be set explicitly, via guard. This latter allows different +custom types to share a common support structure without having to +perform their own guarding.

+
::critcl::argtyperelease name code
+

This command defines a C code fragment for the already defined +argument type name which is inserted whenever the worker +function of a critcl::cproc returns to the shim. It is the +responsibility of this fragment to unconditionally release any +resources the critcl::argtype conversion code allocated. +An example of this are the variadic types for the support of +the special, variadic args argument to critcl::cproc's. +They allocate a C array for the collected arguments which has to be +released when the worker returns. This command defines the C code +for doing that.

+
+
+

Examples

+

The examples shown here have been drawn from the section "Embedding C" in the document about +Using CriTcl. Please see that document for many more examples.

+

A Simple Procedure

+

Starting simple, let us assume that the Tcl code in question is +something like

+
+    proc math {x y z} {
+        return [expr {(sin($x)*rand())/$y**log($z)}]
+    }
+
+

with the expression pretending to be something very complex and +slow. Converting this to C we get:

+
+    critcl::cproc math {double x double y double z} double {
+        double up   = rand () * sin (x);
+        double down = pow(y, log (z));
+        return up/down;
+    }
+
+

Notable about this translation:

+
    +
  1. All the arguments got type information added to them, here + "double". Like in C the type precedes the argument name. Other + than that it is pretty much a Tcl dictionary, with keys and + values swapped.

  2. +
  3. We now also have to declare the type of the result, here + "double", again.

  4. +
  5. The reference manpage lists all the legal C types supported as + arguments and results.

  6. +
+

While the above example was based on type double for +both arguments and result we have a number of additional types in the +same category, i.e. simple types. These are:

+
+CriTcl type | C type         | Tcl type  | Notes
+----------- | -------------- | --------- | ------------------------------
+bool        |                |           | Alias of boolean below
+boolean     | int            | Boolean   |
+double      | double         | Double    |
+float       | float          | Double    |
+int         | int            | Int       |
+long        | long           | Long      |
+wideint     | Tcl_WideInt    | WideInt   |
+
+

A slightly advanced form of these simple types are a limited +set of constraints on the argument value. Note that bool and +alias do not support this.

+
+    critcl::cproc sqrt {{double >= 0} x} double {
+        return sqrt(x);
+    }
+
+

In the example above CriTcl's argument handling will reject +calling the command with a negative number, without ever invoking the +C code.

+

These constraints are called limited because only +0 and 1 can be used as the borders, although all the +operators <, <=, >, and >= are +possible. It is also not possible to combine restrictions.

+
+

More Builtin Types: Strings

+

Given that "Everything is a String" is a slogan of Tcl the ability of cprocs +to receive strings as arguments, and return them as results is quite important.

+

We actually have a variety of builtin string types, all alike, yet different.

+

For arguments we have:

+
+CriTcl type | C type         | Tcl type  | Notes
+----------- | -------------- | --------- | ------------------------------
+char*       | const char*    | Any       | Read-only, string rep
+pstring     | critcl_pstring | Any       | Read-only
+bytes       | critcl_bytes   | ByteArray | Read-only
+
+

In C

+
+    critcl::cproc takeStrings {
+        char*   cstring
+	pstring pstring
+	bytes   barray
+    } void {
+        printf ("len %d = %s\n", strlen(cstring), cstring);
+	printf ("len %d = %s\n", pstring.len, pstring.s);
+	printf ("len %d = %s\n", barray.len, barray.s);
+        return; // void result, no result
+    }
+
+

Notable about the above:

+
    +
  1. The cstring is a plain const char*. It points directly +into the Tcl_Obj* holding the argument in the script.

  2. +
  3. The pstring is a slight extension to that. The value is actually a structure +containing the string pointer like cstring (field .s), the length of the +string (field .len), and a pointer to the Tcl_Obj* these came from.

  4. +
  5. The last, barray is like pstring, however it has ensured that the +Tcl_Obj* is a Tcl ByteArray, i.e. binary data.

  6. +
+

Treat all of them as Read Only. Do not modify ever.

+

On the other side, string results, we have:

+
+CriTcl type   | C type         | Tcl type  | Notes
+------------- | -------------- | --------- | ------------------------------
+char*         | char*          | String    | Makes a copy
+vstring       |                |           | Alias of char* above
+const char*   | const char*    |           | Behavior of char* above
+------------- | -------------- | --------- | ------------------------------
+string        | char*          | String    | Freeable string set directly
+              |                |           | No copy is made
+dstring       |                |           | Alias of string above
+
+
+    critcl::cproc returnCString {} char* {
+        return "a string";
+    }
+    critcl::cproc returnString {} string {
+        char* str = Tcl_Alloc (200);
+	sprintf (str, "hello world");
+        return str; 
+    }
+
+

Notable about the above:

+
    +
  1. The type char* is best used for static strings, or strings in some kind +fixed buffer.

    +

    CriTcl's translation layer makes a copy of it for the result of the command. While +it is possible to return heap-allocated strings it is the C code who is responsible for +freeing such at some point. If that is not done they will leak.

  2. +
  3. The type string on the other hand is exactly for returning strings allocated +with Tcl_Alloc and associates.

    +

    For these the translation layer makes no copy at all, and sets them directly as the +result of the command. A very important effect of this is that the ownership of +the string pointer moves from the function to Tcl.

    +

    Tcl will release the allocated memory when it does not need it any +longer. The C code has no say in that.

  4. +
+
+

Custom Types, Introduction

+

When writing bindings to external libraries critcl::cproc is +usually the most convenient way of writing the lower layers. This is +however hampered by the fact that critcl on its own only supports a +few standard (arguably the most import) standard types, whereas the +functions we wish to bind most certainly will use much more, specific +to the library's function.

+

The critcl commands argtype, resulttype and their +adjuncts are provided to help here, by allowing a developer to extend +critcl's type system with custom conversions.

+

This and the three following sections will demonstrate this, +from trivial to complex.

+

The most trivial use is to create types which are aliases of +existing types, standard or other. As an alias it simply copies and +uses the conversion code from the referenced types.

+

Our example is pulled from an incomplete project of mine, a +binding to Jeffrey Kegler's libmarpa library managing +Earley parsers. Several custom types simply reflect the typedef's done +by the library, to make the critcl::cprocs as self-documenting +as the underlying library functions themselves.

+
+    critcl::argtype Marpa_Symbol_ID     = int
+    critcl::argtype Marpa_Rule_ID       = int
+    critcl::argtype Marpa_Rule_Int      = int
+    critcl::argtype Marpa_Rank          = int
+    critcl::argtype Marpa_Earleme       = int
+    critcl::argtype Marpa_Earley_Set_ID = int
+    ...
+    method sym-rank: proc {
+        Marpa_Symbol_ID sym
+        Marpa_Rank      rank
+    } Marpa_Rank {
+        return marpa_g_symbol_rank_set (instance->grammar, sym, rank);
+    }
+    ...
+
+
+

Custom Types, Semi-trivial

+

A more involved custom argument type would be to map from Tcl strings +to some internal representation, like an integer code.

+

The first example is taken from the tclyaml package, +a binding to the libyaml library. In a few places we have to +map readable names for block styles, scalar styles, etc. to the +internal enumeration.

+
+    critcl::argtype yaml_sequence_style_t {
+        if (!encode_sequence_style (interp, @@, &@A)) return TCL_ERROR;
+    }
+    ...
+    critcl::ccode {
+        static const char* ty_block_style_names [] = {
+            "any", "block", "flow", NULL
+        };
+        static int
+        encode_sequence_style (Tcl_Interp* interp, Tcl_Obj* style,
+                               yaml_sequence_style_t* estyle)
+        {
+            int value;
+            if (Tcl_GetIndexFromObj (interp, style, ty_block_style_names,
+                                     "sequence style", 0, &value) != TCL_OK) {
+                return 0;
+            }
+            *estyle = value;
+            return 1;
+        }
+    }
+    ...
+    method sequence_start proc {
+        pstring anchor
+        pstring tag
+        int implicit
+        yaml_sequence_style_t style
+    } ok {
+        /* Syntax: <instance> seq_start <anchor> <tag> <implicit> <style> */
+        ...
+    }
+    ...
+
+

It should be noted that this code precedes the advent of the +supporting generator package critcl::emap. using the +generator the definition of the mapping becomes much simpler:

+
+    critcl::emap::def yaml_sequence_style_t {
+        any   0
+        block 1
+        flow  2
+    }
+
+

Note that the generator will not only provide the conversions, but +also define the argument and result types needed for their use by +critcl::cproc. +Another example of such a semi-trivial argument type can be found in +the CRIMP package, which defines a Tcl_ObjType for +image values. This not only provides a basic argument type for +any image, but also derived types which check that the image has a +specific format. Here we see for the first time non-integer arguments, +and the need to define the C types used for variables holding the C +level value, and the type of function parameters (Due to C promotion +rules we may need different types).

+
+    critcl::argtype image {
+        if (crimp_get_image_from_obj (interp, @@, &@A) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    } crimp_image* crimp_image*
+    ...
+        set map [list <<type>> $type]
+        critcl::argtype image_$type [string map $map {
+            if (crimp_get_image_from_obj (interp, @@, &@A) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (@A->itype != crimp_imagetype_find ("crimp::image::<<type>>")) {
+                Tcl_SetObjResult (interp,
+                                  Tcl_NewStringObj ("expected image type <<type>>",
+                                                    -1));
+                return TCL_ERROR;
+            }
+        }] crimp_image* crimp_image*
+    ...
+
+
+

Custom Types, Support structures

+

The adjunct command critcl::argtypesupport is for when the +conversion needs additional definitions, for example a helper +structure.

+

An example of this can be found among the standard types of +critcl itself, the pstring type. This type provides the C +function with not only the string pointer, but also the string length, +and the Tcl_Obj* this data came from. As critcl::cproc's +calling conventions allow us only one argument for the data of the +parameter a structure is needed to convey these three pieces of +information.

+

Thus the argument type is defined as

+
+    critcl::argtype pstring {
+        @A.s = Tcl_GetStringFromObj(@@, &(@A.len));
+        @A.o = @@;
+    } critcl_pstring critcl_pstring
+    critcl::argtypesupport pstring {
+        typedef struct critcl_pstring {
+            Tcl_Obj*    o;
+            const char* s;
+            int         len;
+        } critcl_pstring;
+    }
+
+

In the case of such a structure being large we may wish to +allocate it on the heap instead of having it taking space on the +stack. If we do that we need another adjunct command, +critcl::argtyperelease. This command specifies the code required +to release dynamically allocated resources when the worker function +returns, before the shim returns to the caller in Tcl. +To keep things simple our example is synthetic, a modification of +pstring above, to demonstrate the technique. An actual, but +more complex example is the code to support the variadic args +argument of critcl::cproc.

+
+    critcl::argtype pstring {
+        @A = (critcl_pstring*) ckalloc(sizeof(critcl_pstring));
+        @A->s = Tcl_GetStringFromObj(@@, &(@A->len));
+        @A->o = @@;
+    } critcl_pstring* critcl_pstring*
+    critcl::argtypesupport pstring {
+        typedef struct critcl_pstring {
+            Tcl_Obj*    o;
+            const char* s;
+            int         len;
+        } critcl_pstring;
+    }
+    critcl::argtyperelease pstring {
+        ckfree ((char*)) @A);
+    }
+
+

Note, the above example shows only the most simple case of an +allocated argument, with a conversion that cannot fail (namely, string +retrieval). If the conversion can fail then either the allocation has +to be defered to happen only on successful conversion, or the +conversion code has to release the allocated memory itself in the +failure path, because it will never reach the code defined via +critcl::argtyperelease in that case.

+
+

Custom Types, Results

+

All of the previous sections dealt with argument conversions, +i.e. going from Tcl into C. +Custom result types are for the reverse direction, from C to Tcl. +This is usually easier, as most of the time errors should not be +possible. Supporting structures, or allocating them on the heap are +not really required and therefore not supported.

+

The example of a result type shown below was pulled from +KineTcl. It is a variant of the builtin result type +Tcl_Obj*, aka object. The builtin conversion assumes +that the object returned by the function has a refcount of 1 (or +higher), with the function having held the reference, and releases +that reference after placing the value into the interp result. The +conversion below on the other hand assumes that the value has a +refcount of 0 and thus that decrementing it is forbidden, lest it be +released much to early, and crashing the system.

+
+    critcl::resulttype KTcl_Obj* {
+        if (rv == NULL) { return TCL_ERROR; }
+        Tcl_SetObjResult(interp, rv);
+        /* No refcount adjustment */
+        return TCL_OK;
+    } Tcl_Obj*
+
+

This type of definition is also found in Marpa and recent +hacking hacking on CRIMP introduced it there as well. Which +is why this definition became a builtin type starting with version +3.1.16, under the names Tcl_Obj*0 and object0.

+

Going back to errors and their handling, of course, if a +function we are wrapping signals them in-band, then the conversion of +such results has to deal with that. This happens for example in +KineTcl, where we find

+
+    critcl::resulttype XnStatus {
+        if (rv != XN_STATUS_OK) {
+            Tcl_AppendResult (interp, xnGetStatusString (rv), NULL);
+            return TCL_ERROR;
+        }
+        return TCL_OK;
+    }
+    critcl::resulttype XnDepthPixel {
+        if (rv == ((XnDepthPixel) -1)) {
+            Tcl_AppendResult (interp,
+                              "Inheritance error: Not a depth generator",
+                              NULL);
+            return TCL_ERROR;
+        }
+        Tcl_SetObjResult (interp, Tcl_NewIntObj (rv));
+        return TCL_OK;
+    }
+
+
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_cutil.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_cutil.html new file mode 100644 index 00000000..65214a38 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_cutil.html @@ -0,0 +1,482 @@ + +critcl::cutil - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::cutil(n) 0.3 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::cutil - CriTcl - C-level Utilities

+
+ + +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the critcl::cutil +package. This package encapsulates a number of C-level utilites for +easier writing of memory allocations, assertions, and narrative tracing +and provides convenience commands to make these utilities accessible +to critcl projects. +Its intended audience are mainly developers wishing to write Tcl +packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+

The reason for this is that the main critcl package makes +use of the facilities for narrative tracing when +critcl::config trace is set, to instrument commands and +procedures.

+
+

API

+
+
::critcl::cutil::alloc
+

This command provides a number C-preprocessor macros which make the +writing of memory allocations for structures and arrays of structures +easier.

+

When run the header file "critcl_alloc.h" is directly made +available to the ".critcl" file containing the command, and +becomes available for use in #include directives of companion +C code declared via critcl::csources.

+

The macros definitions and their signatures are:

+
+    type* ALLOC (type)
+    type* ALLOC_PLUS (type, int n)
+    type* NALLOC (type, int n)
+    type* REALLOC (type* var, type, int n)
+    void  FREE (type* var)
+    void STREP    (Tcl_Obj* o, char* s, int len);
+    void STREP_DS (Tcl_Obj* o, Tcl_DString* ds);
+    void STRDUP   (varname, char* str);
+
+

The details of the semantics are explained in section +Allocation.

+

The result of the command is an empty string.

+
::critcl::cutil::assertions ?enable?
+

This command provides a number C-preprocessor macros for the writing +of assertions in C code.

+

When invoked the header file "critcl_assert.h" is directly +made available to the ".critcl" file containing the command, and +becomes available for use in #include directives of companion +C code declared via critcl::csources.

+

The macro definitions and their signatures are

+
+    void ASSERT (expression, char* message);
+    void ASSERT_BOUNDS (int index, int size);
+    void STOPAFTER (int n);
+
+

Note that these definitions are conditional on the existence of +the macro CRITCL_ASSERT. +Without a critcl::cflags -DCRITCL_ASSERT all assertions in the +C code are quiescent and not compiled into the object file. In other +words, assertions can be (de)activated at will during build time, as +needed by the user.

+

For convenience this is controlled by enable. By default +(false) the facility available, but not active. +Using true not only makes it available, but activates it as +well.

+

The details of the semantics are explained in section +Assertions.

+

The result of the command is an empty string.

+
::critcl::cutil::tracer ?enable?
+

This command provides a number C-preprocessor macros for tracing +C-level internals.

+

When invoked the header file "critcl_trace.h" is directly +made available to the ".critcl" file containing the command, and +becomes available for use in #include directives of companion +C code declared via critcl::csources. Furthermore the ".c" +file containing the runtime support is added to the set of C companion +files

+

The macro definitions and their signatures are

+
+    /* (de)activation of named logical streams.
+     * These are declarators, not statements.
+     */
+    TRACE_ON;
+    TRACE_OFF;
+    TRACE_TAG_ON  (tag_identifier);
+    TRACE_TAG_OFF (tag_identifier);
+    /*
+     * Higher level trace statements (convenience commands)
+     */
+    void TRACE_FUNC   (const char* format, ...);
+    void TRACE_FUNC_VOID;
+    any  TRACE_RETURN (const char* format, any x);
+    void TRACE_RETURN_VOID;
+    void TRACE (const char* format, ...);
+    /*
+     * Low-level trace statements the higher level ones above
+     * are composed from. Scope management and output management.
+     */
+    void TRACE_PUSH_SCOPE (const char* scope);
+    void TRACE_PUSH_FUNC;
+    void TRACE_POP;
+    void TRACE_HEADER (int indent);
+    void TRACE_ADD (const char* format, ...);
+    void TRACE_CLOSER;
+    /*
+     * Convert tag to the underlying status variable.
+     */
+    TRACE_TAG_VAR (tag)
+    /*
+     * Conditional use of arbitrary code.
+     */
+    TRACE_RUN (code);
+    TRACE_DO (code);
+    TRACE_TAG_DO (code);
+
+

Note that these definitions are conditional on the existence of +the macro CRITCL_TRACER. +Without a critcl::cflags -DCRITCL_TRACER all trace +functionality in the C code is quiescent and not compiled into the +object file. In other words, tracing can be (de)activated at will +during build time, as needed by the user.

+

For convenience this is controlled by enable. By default +(false) the facility available, but not active. +Using true not only makes it available, but activates it as +well. +Further note that the command critcl::config now accepts a +boolean option trace. Setting it activates enter/exit tracing +in all commands based on critcl::cproc, with proper printing of +arguments and results. This implicitly activates the tracing facility +in general.

+

The details of the semantics are explained in section +Tracing

+

The result of the command is an empty string.

+
+
+

Allocation

+
+
type* ALLOC (type)
+

This macro allocates a single element of the given type and +returns a pointer to that memory.

+
type* ALLOC_PLUS (type, int n)
+

This macro allocates a single element of the given type, plus an +additional n bytes after the structure and returns a pointer to +that memory.

+

This is for variable-sized structures of. An example of such +could be a generic list element structure which stores management +information in the structure itself, and the value/payload immediately +after, in the same memory block.

+
type* NALLOC (type, int n)
+

This macro allocates n elements of the given type and +returns a pointer to that memory.

+
type* REALLOC (type* var, type, int n)
+

This macro expands or shrinks the memory associated with the C +variable var of type type to hold n elements of the +type. It returns a pointer to that memory. +Remember, a reallocation may move the data to a new location in memory +to satisfy the request. Returning a pointer instead of immediately +assigning it to the var allows the user to validate the new +pointer before trying to use it.

+
void FREE (type* var)
+

This macro releases the memory referenced by the pointer variable +var.

+
void STREP (Tcl_Obj* o, char* s, int len)
+

This macro properly sets the string representation of the Tcl object +o to a copy of the string s, expected to be of length +len.

+
void STREP_DS (Tcl_Obj* o, Tcl_DString* ds)
+

This macro properly sets the string representation of the Tcl object +o to a copy of the string held by the DString ds.

+
void STRDUP (varname, char* str)
+

This macro duplicates the string str into the heap and stores +the result into the named char* variable var.

+
+
+

Assertions

+
+
void ASSERT (expression, char* message
+

This macro tests the expression and panics if it does not hold. +The specified message is used as part of the panic. +The message has to be a static string, it cannot be a variable.

+
void ASSERT_BOUNDS (int index, int size)
+

This macro ensures that the index is in the +range 0 to size-1.

+
void STOPAFTER(n)
+

This macro throws a panic after it is called n times. +Note, each separate instance of the macro has its own counter.

+
+
+

Tracing

+

All output is printed to stdout.

+
+
TRACE_ON
+
+
TRACE_OFF
+
+
TRACE_TAG_ON (identifier)
+
+
TRACE_TAG_OFF (identifier)
+

These "commands" are actually declarators, for use outside of +functions. They (de)activate specific logical streams, named either +explicitly by the user, or implicitly, refering to the current file.

+

For example:

+
+    TRACE_TAG_ON (lexer_in);
+
+

All high- and low-level trace commands producing output have +the controlling tag as an implicit argument. The scope management +commands do not take tags.

+
void TRACE_FUNC
+
+
void TRACE_TAG_FUNC (tag)
+
+
void TRACE_FUNC_VOID
+
+
void TRACE_TAG_FUNC_VOID (tag)
+

Use these macros at the beginning of a C function to record entry into +it. The name of the entered function is an implicit argument +(__func__), forcing users to have a C99 compiler..

+

The tracer's runtime maintains a stack of active functions and +expects that function return is signaled by either TRACE_RETURN, +TRACE_RETURN_VOID, or the equivalent forms taking a tag.

+
void TRACE_RETURN_VOID
+
+
void TRACE_TAG_RETURN_VOID (tag)
+

Use these macros instead of

+
return
+

to return from a void +function. Beyond returning from the function this also signals the +same to the tracer's runtime, popping the last entered function from +its stack of active functions.

+
any TRACE_RETURN ( char* format, any x)
+
+
any TRACE_TAG_RETURN (tag, char* format, any x)
+

Use this macro instead of

+
return x
+

to return from a +non-void function. +Beyond returning from the function with value x this also +signals the same to the tracer's runtime, popping the last entered +function from its stack of active functions. +The format is expected to be a proper formatting string for +printf and analogues, able to stringify x.

+
void TRACE ( char* format, ...)
+
+
void TRACE_TAG (tag, char* format, ...)
+

This macro is the trace facilities' equivalent of printf, +printing arbitrary data under the control of the format.

+

The printed text is closed with a newline, and indented as per +the stack of active functions.

+
void TRACE_HEADER (int indent)
+
+
void TRACE_TAG_HEADER (tag, int indent)
+

This is the low-level macro which prints the beginning of a trace +line. This prefix consists of physical location (file name and line +number), if available, indentation as per the stack of active scopes +(if activated), and the name of the active scope.

+
void TRACE_CLOSER
+
+
void TRACE_TAG_CLOSER (tag)
+

This is the low-level macro which prints the end of a trace +line.

+
void TRACE_ADD (const char* format, ...)
+
+
void TRACE_TAG_ADD (tag, const char* format, ...)
+

This is the low-level macro which adds formatted data to the line.

+
void TRACE_PUSH_SCOPE (const char* name)
+
+
void TRACE_PUSH_FUNC
+
+
void TRACE_PUSH_POP
+

These are the low-level macros for scope management. The first two +forms push a new scope on the stack of active scopes, and the last +forms pops the last scope pushed.

+
TRACE_TAG_VAR (tag)
+

Helper macro converting from a tag identifier to the name of the +underlying status variable.

+
TRACE_RUN (code);
+

Conditionally insert the code at compile time when the tracing +facility is activated.

+
TRACE_DO (code);
+
+
TRACE_TAG_DO (tag, code);
+

Insert the code at compile time when the tracing facility is +activated, and execute the same when either the implicit tag for the +file or the user-specified tag is active.

+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_devguide.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_devguide.html new file mode 100644 index 00000000..8f69ac4f --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_devguide.html @@ -0,0 +1,372 @@ + +critcl_devguide - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_devguide(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_devguide - Guide To The CriTcl Internals

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+
+

Audience

+

This document is a guide for developers working on CriTcl, i.e. maintainers fixing +bugs, extending the package's functionality, etc.

+

Please read

+
    +
  1. CriTcl - License,

  2. +
  3. CriTcl - How To Get The Sources, and

  4. +
  5. CriTcl - The Installer's Guide

  6. +
+

first, if that was not done already.

+

Here we assume that the sources are already available in a directory of the readers +choice, and that the reader not only know how to build and install them, but also has all +the necessary requisites to actually do so. The guide to the sources in particular also +explains which source code management system is used, where to find it, how to set it up, +etc.

+
+

Playing with CriTcl

+

Note that the sources of CriTcl, should the reader have gotten them, also +contain several examples show-casing various aspects of the system. These demonstration +packages can all be found in the sub-directory "examples/" of the sources.

+

Lots of smaller examples can be found in the document +Using CriTcl, an introduction to CriTcl by way of a of +examples. These focus more on specific critcl commands than the +overall picture shown by the large examples mentioned in the previous +paragraph.

+
+

Developing for CriTcl

+

Architecture & Concepts

+

The system consists of two main layers, as seen in the figure below, +plus a support layer containing general packages the system uses during +operation.

+

architecture

+
    +
  1. At the top we have an application built on top of the core packages, +providing command line access to the second and third usage modes, +i.e. Generate Package and Generate TEA Package.

    +
    +
    critcl
    +
    +
    critcl::app
    +
    +
    +
  2. +
  3. Below that is the core package providing the essential functionality +of the system, plus various utility packages which make common tasks +more convenient.

    +
    +
    critcl
    +
    +
    critcl::util
    +
    +
    +
  4. +
  5. Lastly a layer of supporting packages, mostly external to critcl.

    +
    +
    md5
    +

    For this pure-Tcl package to be fast users should get one of several +possible accelerator packages:

    +
      +
    1. tcllibc

    2. +
    3. Trf

    4. +
    5. md5c

    6. +
    +
    cmdline
    +
    +
    platform
    +
    +
    stubs::container
    +
    +
    stubs::reader
    +
    +
    stubs::writer
    +
    +
    stubs::gen
    +
    +
    stubs::gen::init
    +
    +
    stubs::gen::header
    +
    +
    stubs::gen::decl
    +
    +
    stubs::gen::macro
    +
    +
    stubs::gen::slot
    +
    +
    stubs::gen::lib
    +
    +
    +
  6. +
+
+

Requirements

+

To develop for critcl the following packages and applications must be available in the +environment. These are all used by the build.tcl helper application.

+
+
dtplite
+

A Tcl application provided by Tcllib, for the validation and conversion of +doctools-formatted text.

+
dia
+

A Tcl application provided by Tklib, for the validation and conversion +of diagram-formatted figures into raster images.

+

Do not confuse this with the Gnome dia application, which is a graphical +editor for figures and diagrams, and completely unrelated.

+
fileutil
+

A Tcl package provided by Tcllib, providing file system utilities.

+
vfs::mk4, vfs
+

Tcl packages written in C providing access to Tcl's VFS facilities, required for the +generation of critcl starkits and starpacks.

+
+
+

Directory structure

+
+
Helpers
+
+
"build.tcl"
+

This helper application provides various operations needed by a developer for critcl, like +regenerating the documentation, the figures, building and installing critcl, etc.

+

Running the command like

+
+	./build.tcl help
+
+

will provide more details about the available operations and their arguments.

+
+
Documentation
+
+
"doc/"
+

This directory contains the documentation sources, for both the text, and the figures. +The texts are written in doctools format, whereas the figures are written for +tklib's dia(gram) package and application.

+
"embedded/"
+

This directory contains the documentation converted to regular manpages (nroff) and HTML. +It is called embedded because these files, while derived, are part of the git repository, +i.e. embedded into it. This enables us to place these files where they are visible when +serving the prject's web interface.

+
+
Testsuite
+
+
"test/all.tcl"
+
+
"test/testutilities.tcl"
+
+
"test/*.test"
+

These files are a standard testsuite based on Tcl's tcltest package, with some +utility code snarfed from Tcllib.

+

This currently tests only some of the stubs::* packages.

+
"test/*.tcl"
+

These files (except for "all.tcl" and "testutilities.tcl") are example files +(Tcl with embedded C) which can be run through critcl for testing.

+

TODO for a maintainers: These should be converted into a proper test suite.

+
+
Package Code, General structure
+
+
+
Package Code, Per Package
+
+
critcl
+
+
"lib/critcl/critcl.tcl"
+

The Tcl code implementing the package.

+
"lib/critcl/Config"
+

The configuration file for the standard targets and their settings.

+
"lib/critcl/critcl_c/"
+

Various C code snippets used by the package. +This directory also contains the copies of the Tcl header files used to compile the +assembled C code, for the major brnaches of Tcl, i.e. 8.4, 8.5, and 8.6.

+
+
critcl::util
+
+
"lib/critcl-util/util.tcl"
+

The Tcl code implementing the package.

+
+
critcl::app
+
+
"lib/app-critcl/critcl.tcl"
+

The Tcl code implementing the package.

+
+
critcl::iassoc
+
+
"lib/critcl-iassoc/iassoc.tcl"
+

The Tcl code implementing the package.

+
"lib/critcl-iassoc/iassoc.h"
+

C code template used by the package.

+
+
critcl::class
+
+
"lib/critcl-class/class.tcl"
+

The Tcl code implementing the package.

+
"lib/critcl-class/class.h"
+

C code template used by the package.

+
+
stubs::*
+
+
"lib/stubs/*"
+

A set of non-public (still) packages which provide read and write access to and represent +Tcl stubs tables. These were created by taking the "genStubs.tcl" helper application +coming with the Tcl core sources apart along its internal logical lines.

+
+
critclf
+
+
"lib/critclf/"
+

Arjen Markus' work on a critcl/Fortran. The code is outdated and has not been adapted to +the changes in critcl version 3 yet.

+
+
md5
+
+
md5c
+
+
platform
+

These are all external packages whose code has been inlined in the repository for easier +development (less dependencies to pull), and quicker deployment from the repository +(generation of starkit and -pack).

+

TODO for maintainers: These should all be checked against their origin for +updates and changes since they were inlined.

+
+
+
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_emap.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_emap.html new file mode 100644 index 00000000..3aefed4a --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_emap.html @@ -0,0 +1,284 @@ + +critcl::emap - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::emap(n) 1.3 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::emap - CriTcl - Wrap Support - Enum en- and decoding

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2?
  • +
  • package require critcl::emap ?1.3?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the +critcl::emap package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package critcl::iassoc.

+

C level libraries often use enumerations or integer values to encode +information, like the state of a system. Tcl bindings to such libraries now +have the task of converting a Tcl representation, i.e. a string into such +state, and back. +Note here that the C-level information has to be something which +already exists. The package does not create these values. This is +in contrast to the package critcl::enum which creates an +enumeration based on the specified symbolic names.

+

This package was written to make the declaration and management +of such enumerations and their associated conversions functions easy, +hiding all attendant complexity from the user.

+

Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::emap::def name definition ?-nocase? ?-mode mode?
+

This command defines C functions for the conversion of the named +state code into a Tcl string, and vice versa. +The underlying mapping tables are automatically initialized on first +access (if not fully constant), and finalized on interpreter +destruction.

+

The definition dictionary provides the mapping from the +Tcl-level symbolic names of the state to their C expressions (often +the name of the macro specifying the actual value). +Note here that the C-level information has to be something which +already exists. The package does not create these values. This is +in contrast to the package critcl::enum which creates an +enumeration based on the specified symbolic names.

+

Further note that multiple strings can be mapped to the same C +expression. When converting to Tcl the first string for the mapping is +returned. An important thing to know: If all C expressions are +recognizable as integer numbers and their covered range is not too +large (at most 50) the package will generate code using direct and +fast mapping tables instead of using a linear search.

+

If the option -nocase is specified then the encoder +will match strings case-insensitively, and the decoder will always +return a lower-case string, regardless of the string's case in the +definition.

+

If the option -mode is specified its contents will +interpreted as a list of access modes to support. The two allowed +modes are c and tcl. Both modes can be used +together. The default mode is tcl.

+

The package generates multiple things (declarations and +definitions) with names derived from name, which has to be a +proper C identifier. Some of the things are generated conditional on +the chosen modes.

+
+
name_encode
+

The tcl-mode function for encoding a Tcl string into the +equivalent state code. +Its signature is

+
+int name_encode (Tcl_Interp* interp, Tcl_Obj* state, int* result);
+
+

The return value of the function is a Tcl error code, +i.e. TCL_OK, TCL_ERROR, etc.

+
name_encode_cstr
+

The c-mode function for encoding a C string into the +equivalent state code. +Its signature is

+
+int name_encode_cstr (const char* state);
+
+

The return value of the function is the encoded state, or -1 if +the argument is not a vlaid state.

+
name_decode
+

The tcl-mode function for decoding a state code into the +equivalent Tcl string. +Its signature is

+
+Tcl_Obj* name_decode (Tcl_Interp* interp, int state);
+
+
+
name_decode_cstr
+

The c-mode function for decoding a state code into the +equivalent C string. +Its signature is

+
+const char* name_decode_cstr (int state);
+
+

The return value of the function is the C string for the state, +or NULL if the state argument does not contain a valid +state value.

+
name.h
+

A header file containing the declarations for the conversion +functions, for use by other parts of the system, if necessary.

+

The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files (csources).

+
name
+

For mode tcl the command registers a new argument-type for +critcl::cproc with critcl, encapsulating the encoder function.

+
name
+

For mode tcl the command registers a new result-type for +critcl::cproc with critcl, encapsulating the decoder function.

+
+
+
+

Example

+

The example shown below is the specification for the possible modes of +entry (normal, no feedback, stars) used by the Tcl binding to the +linenoise library.

+
+package require Tcl 8.6
+package require critcl 3.2
+critcl::buildrequirement {
+    package require critcl::emap
+}
+critcl::emap::def hiddenmode {
+            no  0 n 0 off 0 false 0 0 0
+    all   1 yes 1 y 1 on  1 true  1 1 1
+    stars 2
+} -nocase
+# Declarations: hiddenmode.h
+# Encoder:      int      hiddenmode_encode (Tcl_Interp* interp, Tcl_Obj* state, int* result);
+# Decoder:      Tcl_Obj* hiddenmode_decode (Tcl_Interp* interp, int state);
+# ResultType:   hiddenmode
+# ArgumentType: hiddenmode
+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_enum.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_enum.html new file mode 100644 index 00000000..8c872f72 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_enum.html @@ -0,0 +1,274 @@ + +critcl::enum - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::enum(n) 1.2 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::enum - CriTcl - Wrap Support - String/Integer mapping

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2?
  • +
  • package require critcl::enum ?1.2?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the +critcl::enum package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package critcl::literals.

+

It is an extended form of string pool which not only converts +integer values into Tcl-level strings, but also handles the reverse +direction, converting from strings to the associated integer values.

+

It essentially provides a bi-directional mapping between a C +enumeration type and a set of strings, one per enumeration value. +Note that the C enumeration in question is created by the +definition. It is not possible to use the symbols of an existing +enumeration type.

+

This package was written to make the declaration and management +of such mappings easy. It uses a string pool for one of the directions, +using its ability to return shared literals and conserve memory.

+

Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::enum::def name definition ?mode?
+

This command defines two C functions for the conversion between +C values and Tcl_Obj'ects, with named derived from name.

+

The definition dictionary provides the mapping from the +specified C-level symbolic names to the strings themselves.

+

The mode-list configures the output somewhat. +The two allowed modes are +list and tcl. +All modes can be used together. +The default mode is tcl. +Using mode +list implies tcl as well.

+

For mode tcl the new function has two arguments, a +Tcl_Interp* pointer refering to the interpreter holding the +string pool, and a code of type "name_pool_names" (see below), +the symbolic name of the string to return. The result of the function +is a Tcl_Obj* pointer to the requested string constant.

+

For mode +list all of tcl applies, plus an +additional function is generated which takes three arguments, in +order: a Tcl_Interp* pointer refering to the interpreter +holding the string pool, an int holding the size of the last +argument, and an array of type "name_pool_names" holding the +codes (see below), the symbolic names of the strings to return. The +result of the function is a Tcl_Obj* pointer to a Tcl list +holding the requested string constants.

+

The underlying string pool is automatically initialized on +first access, and finalized on interpreter destruction.

+

The package generates multiple things (declarations and +definitions) with names derived from name, which has to be a +proper C identifier.

+
+
name_pool_names
+

The C enumeration type containing the specified symbolic names.

+
name_ToObj
+

The function converting from integer value to Tcl string. +Its signature is

+
+Tcl_Obj* name_ToObj (Tcl_Interp* interp, name_names literal);
+
+
+
name_ToObjList
+

The mode +list function converting from integer array to Tcl +list of strings. +Its signature is

+
+Tcl_Obj* name_ToObjList (Tcl_Interp* interp, int c, name_names* literal);
+
+
+
name_GetFromObj
+

The function converting from Tcl string to integer value. +Its signature is

+
+int name_GetFromObj (Tcl_Interp* interp, Tcl_Obj* obj, int flags, int* literal);
+
+

The flags are like for Tcl_GetIndexFromObj.

+
name.h
+

A header file containing the declarations for the converter functions, +for use by other parts of the system, if necessary.

+

The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files (csources).

+
name
+

At the level of critcl itself the command registers a new result-type +for critcl::cproc, which takes an integer result from the function +and converts it to the equivalent string in the pool for the script.

+
name
+

At the level of critcl itself the command registers a new argument-type +for critcl::cproc, which takes a Tcl string and converts it to the +equivalent integer for delivery to the function.

+
+
+
+

Example

+

The example shown below is the specification for a set of actions, methods, +and the like, a function may take as argument.

+
+package require Tcl 8.6
+package require critcl 3.2
+critcl::buildrequirement {
+    package require critcl::enum
+}
+critcl::enum::def action {
+    w_create	"create"
+    w_directory	"directory"
+    w_events	"events"
+    w_file	"file"
+    w_handler	"handler"
+    w_remove	"remove"
+}
+# Declarations: action.h
+# Type:         action_names
+# Accessor:     Tcl_Obj* action_ToObj (Tcl_Interp* interp, int literal);
+# Accessor:     int action_GetFromObj (Tcl_Interp* interp, Tcl_Obj* o, int flags, int* literal);
+# ResultType:   action
+# ArgType:      action
+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_install.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_install.html new file mode 100644 index 00000000..2e0a4833 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_install.html @@ -0,0 +1,346 @@ + +critcl_howto_install - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_howto_install(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_howto_install - How To Install CriTcl

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

CriTcl is installed in four major steps:

+
    +
  1. Install The Requisites

  2. +
  3. Follow the instructions on How To Get The CriTcl Sources

  4. +
  5. Install The CriTcl Packages

  6. +
  7. Test The Installation

  8. +
+

It is now possible to follow the instructions on How To Use CriTcl.

+
+

Install The Requisites

+

This major step breaks down into three minor steps:

+
    +
  1. Install A Working C Compiler and development environment.

  2. +
  3. Install A Working Tcl Shell

  4. +
  5. Install Supporting Tcl Packages

  6. +
+

Install A Working C Compiler

+

While CriTcl requires a working C compiler to both install itself, and to process +CriTcl-based packages installing such is very much out of scope for this document.

+

Please follow the instructions for the platform and system CriTcl is to be +installed on.

+

The important pieces of information are this:

+
    +
  1. The path to the directory containing the C compiler binary has to be listed in the + environment variable PATH, for CriTcl to find it.

  2. +
  3. On Windows(tm) the environment variable LIB has to be present and contain the + paths of the directories holding Microsoft's libraries. The standard CriTcl + configuration for this platform searches these paths to fine-tune its settings + based on available libraries and compiler version.

  4. +
+

Links of interest:

+
+
http://www.tldp.org/HOWTO/HOWTO-INDEX/programming.html
+
+
+
+

Install A Working Tcl Shell

+

That a working installation of CriTcl will require a working installation of +Tcl should be obvious.

+

Installing Tcl however is out of scope here, same as for installing a working C +compiler.

+

There are too many options, starting from +building it from scratch, installing what is provided +by the platform's package manager (zypper, yum, apt-get, and more), +to using some vendor's distribution.

+

A single piece of advice however.

+

While CriTcl currently supports running on Tcl 8.4 and higher, and the +creation of packages for the same, the last release for this version was in 2013 (9 years +ago at the time of writing). Similarly, the last release for Tcl 8.5 was in 2016 (6 years +ago). Both are official end of life.

+

Given this I recommend to install and use Tcl 8.6.

+
+

Install Supporting Tcl Packages

+

The implementation of CriTcl uses and depends on

+
    +
  1. cmdline

  2. +
+

Depending on how Tcl was installed this package may be available already without +action, or not. +Invoke the command

+
+    echo 'puts [package require cmdline]' | tclsh
+
+

to check if the package is present or not. If it is present then its version number will +be printed, else the error message can't find package cmdline or similar.

+

If it is not present install the package as per the instructions for the chosen Tcl +installation.

+

Note, the package cmdline may not exist as its own installable +package. In such a case check if the chosen Tcl installation provides a tcllib +package and install that. This should install all the packages in the Tcllib bundle, +including cmdline.

+

As a last fallback, go to Tclib and follow the instructions to install +the bundle from scratch.

+
+
+

Install The CriTcl Packages

+

Note that this step has different instructions dependent on the platform CriTcl is +to be installed on. In other words, only one of the sub sections applies, the other can be +ignored.

+

Install On Unix

+

This section offers instructions for installing CriTcl on various kinds of Unix and +Unix-related systems, i.e. Linux, the various BSDs, etc. It especially +covers Mac OS X as well.

+

Use the instructions in section Install On Windows when installing on a +Windows platform and not using a unix-like environment as provided by tools like +MinGW, CygWin, Git For Windows, WSL, etc.

+
    +
  1. Change the working directory to the top level directory of the CriTcl +checkout obtained by following the instructions of How To Get The CriTcl Sources.

  2. +
  3. Verify that the file "build.tcl" is marked executable. Make it executable if +it is not.

  4. +
  5. Invoke

    +
     ./build.tcl install 
    +

    to perform the installation.

    +

    Attention This command uses default locations for the placement of the +critcl application, the various packages, and header files.

  6. +
  7. Invoke

    +
     ./build.tcl dirs 
    +

    to see the chosens paths before actually +performing the installation.

  8. +
  9. Use the options listed below to change the paths used for installation as desired. This is +the same method as with configure based packages.

    +
    +
    --prefix path
    +

    Base path for non-package files.

    +
    --include-dir path
    +

    Destination path for header files.

    +
    --exec-prefix path
    +

    Base path for applications and packages.

    +
    --bin-dir path
    +

    Destination path for applications.

    +
    --lib-dir path
    +

    Destination path for packages.

    +
    +

    These options are especially necessary in all environments not using the semi-standard +"bin", "lib", "include" locations from configure.

    +

    As an example of such environments, Ubuntu (and possibly Debian) expect Tcl +packages to be installed into the "/usr/share/tcltk" directory, therefore requiring +the use of

    +
    --lib-dir /usr/share/tcltk
    +

    for proper installation.

  10. +
+

Note that this guide neither covers the details of the install +method, nor does it cover any of the other methods available through the build.tcl +tool of CriTcl. +These can be found in the CriTcl build.tcl Tool Reference.

+
+

Install On Windows

+

This section offers instructions for installing CriTcl on a Windows (tm) host. +Note that environments as provided by tools like MinGW, CygWin, +Git For Windows, WSL, etc. are classed as Unix-like, and the instructions in section +Install On Unix apply.

+
    +
  1. In a DOS box, change the working directory to the top level directory of the +CriTcl checkout obtained by following the instructions of +How To Get The CriTcl Sources.

  2. +
  3. In the same DOS box, invoke

    +
     tclsh.exe ./build.tcl install 
    +

    to perform +the installation.

    +

    Attention This command uses default locations for the placement of the +critcl application, the various packages, and header files.

  4. +
  5. Invoke

    +
     tclsh.exe ./build.tcl dirs 
    +

    to see the chosens paths before +actually performing the installation.

  6. +
  7. Use the options listed below to change the paths used for installation as desired. This is +the same method as with configure based packages.

    +
    +
    --prefix path
    +

    Base path for non-package files.

    +
    --include-dir path
    +

    Destination path for header files.

    +
    --exec-prefix path
    +

    Base path for applications and packages.

    +
    --bin-dir path
    +

    Destination path for applications.

    +
    --lib-dir path
    +

    Destination path for packages.

    +
    +
  8. +
+

Attention! The current installer does not put an extension on the +critcl application. This forces users to either explicitly choose the +tclsh to run the application, or manually rename the installed file to +"critcl.tcl". The latter assumes that an association for ".tcl" is available, to +either tclsh, or wish.

+

Note that this guide neither covers the details of the install +method, nor does it cover any of the other methods available through the build.tcl +tool of CriTcl. +These can be found in the CriTcl build.tcl Tool Reference.

+
+
+

Test The Installation

+

Installing CriTcl contains an implicit test of its functionality.

+

One of its operation modes uses the MD5 hash internally to generate unique ids for +sources, as a means of detecting changes. To make generation of such hashes fast a +CriTcl-based package for MD5 is installed as part of the main installation process.

+

In other words, after installing the core packages of CriTcl this partial +installation is used to build the rest.

+

This is possible because building a package from CriTcl-based sources is the +operation mode not using MD5, therefore there is no circular dependency.

+

For our purposes this however is also a self-test of the system, verifying that the +core of CriTcl works, as well as the C compiler.

+

For additional testing simply move on to section The First Package of +the guide on How To Use CriTcl.

+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_sources.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_sources.html new file mode 100644 index 00000000..f35fa793 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_sources.html @@ -0,0 +1,173 @@ + +critcl_howto_sources - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_howto_sources(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_howto_sources - How To Get The CriTcl Sources

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

The sources for CriTcl are retrieved in two easy steps:

+
    +
  1. Install the Git Source Code Manager

  2. +
  3. Retrieve The Sources

  4. +
+

It is now possible to follow the instructions on How To Install CriTcl.

+
+

Install the Git Source Code Manager

+

CriTcl's sources are managed by the popular Git SCM.

+

Binaries of clients for popular platforms can be found at the download page.

+

See also if your operating system's package manager provides clients and associated +tools for installation. If so, follow the instructions for the installation of such +packages on your system.

+
+

Retrieve The Sources

+
    +
  1. Choose a directory for the sources, and make it the working directory.

  2. +
  3. Invoke the command

    +
    +git clone http://andreas-kupries.github.io/critcl
    +
    +
  4. +
  5. The working directory now contains a sub-directory "critcl" holding the +sources of CriTcl.

  6. +
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_use.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_use.html new file mode 100644 index 00000000..69985143 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_howto_use.html @@ -0,0 +1,1791 @@ + +critcl_howto_use - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_howto_use(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_howto_use - How To Use CriTcl

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document assumes the presence of a working CriTcl installation.

+

If that is missing follow the instructions on How To Install CriTcl.

+
+

Basics

+

To create a minimal working package

+
    +
  1. Choose a directory to develop in and make it the working directory. This should +not be a checkout of CriTcl itself.

  2. +
  3. Save the following example to a file. In the following it is assumed that the file +was named "example.tcl".

    +
    +# -*- tcl -*-
    +# Critcl support, absolutely necessary.
    +package require critcl
    +# Bail out early if the compile environment is not suitable.
    +if {![critcl::compiling]} {
    +    error "Unable to build project, no proper compiler found."
    +}
    +# Information for the teapot.txt meta data file put into a generated package.
    +# Free form strings.
    +critcl::license {Andreas Kupries} {Under a BSD license}
    +critcl::summary {The first CriTcl-based package}
    +critcl::description {
    +    This package is the first example of a CriTcl-based package. It contains all the
    +    necessary and conventionally useful pieces.
    +}
    +critcl::subject example {critcl package}
    +critcl::subject {basic critcl}
    +# Minimal Tcl version the package should load into.
    +critcl::tcl 8.6
    +# Use to activate Tcl memory debugging
    +#critcl::debug memory
    +# Use to activate building and linking with symbols (for gdb, etc.)
    +#critcl::debug symbols
    +# ## #### ######### ################ #########################
    +## A hello world, directly printed to stdout. Bypasses Tcl's channel system.
    +critcl::cproc hello {} void {
    +    printf("hello world\n");
    +}
    +# ## #### ######### ################ #########################
    +# Forcing compilation, link, and loading now.
    +critcl::msg -nonewline { Building ...}
    +if {![critcl::load]} {
    +    error "Building and loading the project failed."
    +}
    +# Name and version the package. Just like for every kind of Tcl package.
    +package provide critcl-example 1
    +
    +
  4. +
  5. Invoke the command

    +
     critcl -keep -debug all -pkg example.tcl 
    +

    This compiles the example and installs it into a "lib/" sub directory of the +working directory, generating output similar to

    +
    +    Config:   linux-x86_64-gcc
    +    Build:    linux-x86_64-gcc
    +    Target:   linux-x86_64
    +    Source:   example.tcl  (provide critcl-example 1) Building ...
    +    Library:  example.so
    +     (tclStubsPtr     =>  const TclStubs *tclStubsPtr;)
    +     (tclPlatStubsPtr =>  const TclPlatStubs *tclPlatStubsPtr;)
    +    Package:  lib/example
    +    Files left in /home/aku/.critcl/pkg2567272.1644845439   
    +
    +

    during operation.

    +

    The -keep option suppressed the cleanup of the generated C files, object +files, compiler log, etc. normally done at the end of building.

    +
    +% ls -l /home/aku/.critcl/pkg2567272.1644845439
    +total 36
    +-rw-r--r-- 1 aku aku  1260 Feb 14 18:30 v3118_00000000000000000000000000000004.c
    +-rw-r--r-- 1 aku aku  2096 Feb 14 18:30 v3118_00000000000000000000000000000004_pic.o
    +-rw-r--r-- 1 aku aku  1728 Feb 14 18:30 v3118_00000000000000000000000000000009.c
    +-rw-r--r-- 1 aku aku  2448 Feb 14 18:30 v3118_00000000000000000000000000000009_pic.o
    +-rwxr-xr-x 1 aku aku 14424 Feb 14 18:30 v3118_00000000000000000000000000000009.so
    +-rw-r--r-- 1 aku aku  1725 Feb 14 18:30 v3118.log
    +
    +

    This enables inspection of the generated C code. +Simply drop the option from the command if that is not desired.

    +

    The option -debug, with argument all activated Tcl's memory +debugging and caused the generation of the symbol tables needed by gdb or any +other debugger. The alternate arguments memory and symbols activate just +one of the these.

  6. +
  7. Now invoke an interactive tclsh and enter the commands:

    +
      +
    • lappend auto_path lib

    • +
    • package require critcl-example

    • +
    • info loaded

    • +
    • hello

    • +
    • exit

    • +
    +

    I.e. extend tclsh's package search path to include the location of the new +package, load the package, verify that the associated shared library is present, invoke +the package command, and stop the session.

    +

    When the package command is invoked the terminal will show hello world, +followed by the prompt.

  8. +
+

Commands: critcl::compiling, critcl::cproc, +critcl::description, critcl::license, critcl::load, +critcl::msg, critcl::subject, critcl::summary, critcl::tcl.

+

Make a copy of "example.tcl" before going through the sub-sections. Keep it as +a save point to return to from the editing done in the sub-section.

+

Simple Arguments

+

A function taking neither arguments nor returning results is not very useful.

+
    +
  1. We are now extending the command to take an argument.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {double x} void {
    +	/* double x; */
    +	printf("hello world, we have %f\n", x);
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. When testing the package again, entering the simple hello will fail.

    +

    The changed command is now expecting an argument, and we gave it none.

    +

    Retry by entering

    +
    hello 5
    +

    instead. + Now the command behaves as expected and prints the provided value.

    +

    Further try and enter

    +
    hello world
    +

    This will fail again. + The command expected a real number and we gave it something decidedly not so.

    +

    These checks (argument count, argument type) are implemented in the translation +layer CriTcl generates for the C function. The function body is never invoked.

  6. +
+
+

Simple Results

+

A function taking neither arguments nor returning results is not very useful.

+
    +
  1. We are now extending the command to return a result.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc twice {double x} double {
    +	return 2*x;
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. Note that the name of the command changed. Goodbye hello, hello twice.

  6. +
  7. Invoke

    +
     twice 4 
    +

    and the tclsh will print the result 8 +in the terminal.

  8. +
+

An important limitation of the commands implemented so far is that they cannot +fail. The types used so far (void, double) and related scalar types can +return only a value of the specified type, and nothing else. They have no ability to +signal an error to the Tcl script.

+

We will come back to this after knowing a bit more about the more complex argument +and result types.

+

Of interest to the eager reader: CriTcl cproc Type Reference

+
+

Range-limited Simple Arguments

+
    +
  1. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {{double > 5 < 22} x} void {
    +	/* double x, range 6-21; */
    +	printf("hello world, we have %f\n", x);
    +    }
    +
    +

    and rebuild the package.

  2. +
  3. When dealing with simple arguments whose range of legal values is limited to a single +continuous interval extend the base type with the necessary relations (>, >=, +<, and <=) and limiting values.

    +

    Note that the limiting values have to be proper constant numbers acceptable by the +base type. Symbolic values are not accepted.

    +

    Here the argument x of the changed function will reject all values outside of the +interval 6 to 21.

  4. +
+
+

String Arguments

+

Tcl prides itself on the fact that Everything Is A String. +So how are string values passed into C functions ?

+
    +
  1. We are now extending the command with a string argument.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {pstring x} void {
    +	/* critcl_pstring x (.s, .len, .o); */
    +	printf("hello world, from %s (%d bytes)\n", x.s, x.len);
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. Testing hello with any kind of argument the information is printed.

  6. +
  7. Of note here is that the command argument x is a structure.

  8. +
  9. The example uses only two of the three fields, the pointer to the string data +(.s), and the length of the string (.len). In bytes, not in +characters, because Tcl's internal representation of strings uses a modified UTF-8 +encoding. A character consists of between 1 and TCL_UTF_MAX bytes.

  10. +
  11. Attention The pointers (.s) refer into data structures internal +to and managed by the Tcl interpreter. +Changing them is highly likely to cause subtle and difficult to track down bugs. +Any and all complex arguments must be treated as Read-Only. Never modify them.

  12. +
  13. Use the simpler type char* if and only if the length of the string is not +relevant to the command, i.e. not computed, or not used by any of the functions called +from the body of the command. +Its value is essentially just the .s field of pstring's structure. +This then looks like

    +
    +    critcl::cproc hello {char* x} void {
    +	/* char* x; */
    +	printf("hello world, from %s\n", x);
    +    }
    +
    +
  14. +
+
+

String Results

+

Tcl prides itself on the fact that Everything Is A String. +So how are string values returned from C functions ?

+
    +
  1. We are now giving the command a string result.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc twice {double x} char* {
    +	char buf [lb]40[rb];
    +	sprintf(buf, "%f", 2*x);
    +	return buf;
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. Note that the name of the command changed. Goodbye hello, hello twice.

  6. +
  7. Invoke

    +
     twice 4 
    +

    and the tclsh will print the result 8 +in the terminal.

  8. +
  9. Attention. To the translation layer the string pointer is owned by the C +code. A copy is made to become the result seen by Tcl.

    +

    While the C code is certainly allowed to allocate the string on the heap if it so +wishes, this comes with the responsibility to free the string as well. Abrogation of that +responsibility will cause memory leaks.

    +

    The type char* is recommended to be used with static string buffers, string +constants and the like.

  10. +
  11. Conversely, to return heap-allocated strings it is recommended to use the type +string instead.

    +

    Replace the definition of twice with

    +
    +critcl::cproc twice {double x} string {
    +    char* buf = Tcl_Alloc (40);
    +    sprintf(buf, "%f", 2*x);
    +    return buf;
    +}
    +
    +

    Now the translation layer takes ownership of the string from the C code and +transfers that ownership to the Tcl interpreter. This means that the string will be +released when the Tcl interpreter is done with it. The C code has no say in the lifecycle +of the string any longer, and having the C code releasing the string will cause +issues. Dangling pointers and associated memory corruption and crashes.

  12. +
+
+

List Arguments

+

Even as a string-oriented language Tcl is capable of handling more complex structures. The first of +it, with Tcl since the beginning are lists. Sets of values indexed by a numeric value.

+

In C parlance, arrays.

+
    +
  1. We are now extending the command with a list argument.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {list x} void {
    +	/* critcl_list x (.o, .v, .c); */
    +	printf("hello world, %d elements in (%s)\n", x.c, Tcl_GetString (x.o));
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. Testing hello with any kind of list argument it will print basic information about it.

  6. +
  7. Of note here is that the command argument x is a structure.

  8. +
  9. The example uses only two of the three fields, the pointer to the original Tcl_Obj* +holding the list (.o), and the length of the list (.c) in elements.

    +

    The field .v, not used above, is the C array holding the Tcl_Obj* pointers to +the list elements.

  10. +
  11. Attention The pointers .o and .v refer into data structures +internal to and managed by the Tcl interpreter. +Changing them is highly likely to cause subtle and difficult to track down bugs. +Any and all complex arguments must be treated as Read-Only. Never modify them.

  12. +
  13. As a last note, this argument type does not place any constraints on the size of the list, or +on the type of the elements.

  14. +
+
+

Constrained List Arguments

+

As mentioned at the end of section List Arguments the basic list type places no +constraints on the size of the list, nor on the type of the elements.

+

Both kind of constraints can be done however, alone or together.

+
    +
  1. We are now extending the command with a length-limited list.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {[5] x} void {
    +	/* critcl_list x (.o, .v, .c); */
    +	printf("hello world, %d elements in (%s)\n", x.c, Tcl_GetString (x.o));
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. Testing the new command will show that only lists holding exactly 5 elements will be +accepted.

  6. +
  7. To accept lists of any length use [] or [*]. Both forms are actually +aliases of the base type, i.e. list.

  8. +
  9. To constrain just the type of elements, for example to type int, use

    +
    int[]
    +

    or

    +
    []int
    +
  10. +
  11. To combine both type and length constraints use the forms

    +
    int[5]
    +

    or

    +
    [5]int
    +
  12. +
  13. The last, most C-like forms of these contraints place the list indicator syntax on the +argument instead of the type. I.e

    +
    int a[]
    +

    or

    +
    int a[5]
    +
  14. +
+
+

Raw Tcl_Obj* Arguments

+

When the set of predefined argument types is not enough the oldest way of handling the +situation is falling back to the structures used by Tcl to manage values, i.e. +Tcl_Obj*.

+
    +
  1. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {object x} void {
    +	/* Tcl_Obj* x */
    +	int len;
    +	char* str = Tcl_GetStringFromObj (x, &len);
    +	printf("hello world, from %s (%d bytes)\n", str, len);
    +    }
    +
    +

    and rebuild the package.

  2. +
  3. Having direct access to the raw Tcl_Obj* value all functions of the public +Tcl API for working with Tcl values become usable. The downside of that is that all the +considerations for handling them apply as well.

    +

    In other words, the C code becomes responsible for handling the reference counts +correctly, for duplicating shared Tcl_Obj* structures before modifying them, etc.

    +

    One thing the C code is allowed to do without restriction is to shimmer the +internal representation of the value as needed, through the associated Tcl API +functions. For example Tcl_GetWideIntFromObj and the like. +It actually has to be allowed to do so, as the type checking done as part of such +conversions is now the responsibility of the C code as well.

    +

    For the predefined types this is all hidden in the translation layer generated by +CriTcl.

    +

    If more than one command has to perform the same kind of checking and/or conversion +it is recommended to move the core of the code into proper C functions for proper sharing +among the commands.

  4. +
  5. This is best done by defining a custom argument type using CriTcl commands. +This extends the translation layer CriTcl is able to generate. +The necessary conversions, type checks, etc. are then again hidden from the bulk of the +application C code.

    +

    We will come back to this.

  6. +
+
+

Raw Tcl_Obj* Results

+

When the set of predefined result types is not enough the oldest way of handling the +situation is falling back to the structures used by Tcl to manage values, i.e. +Tcl_Obj*.

+

Two builtin types are provided for this, to handle different reference counting +requirements.

+
    +
  1. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc twice {double x} object0 {
    +	return Tcl_NewDoubleObj(2*x);
    +    }
    +
    +

    and rebuild the package.

  2. +
  3. With object0 the translation layer assumes that the returned Tcl_Obj* +value has a reference count of 0. I.e. a value which is unowned and unshared.

    +

    This value is passed directly to Tcl for its use, without any changes. Tcl +increments the reference count and thus takes ownership. The value is still unshared.

    +

    It would be extremely detrimental if the translation layer had decremented the +reference count before passing the value. This action would release the memory and then +leave Tcl with a dangling pointer and the associated memory corruption bug to come.

  4. +
  5. The situation changes when the C code returns a Tcl_Obj* value with a +reference count greater than 0. I.e. at least owned (by the C code), and possibly +even shared. +There are some object constructors and/or mutators in the public Tcl API which do that, +although I do not recall their names. The example below simulates this situation by +explicitly incrementing the reference count before returning the value.

  6. +
  7. In this case use the type object (without the trailing 0).

  8. +
  9. Edit the file "example.tcl" and replace the definition of twice with

    +
    +    critcl::cproc twice {double x} object {
    +	Tcl_Obj* result = Tcl_NewDoubleObj(2*x);
    +	Tcl_IncrRefCount (result);
    +	return result;
    +    }
    +
    +

    and rebuild the package.

  10. +
  11. After handing the value to Tcl, with the associated incremented reference count, +the translation layer decrements the reference count, invalidating the C code's ownership +and leaving the final reference count the same.

    +

    Note, the order matters. If the value has only one reference then decrementing it +before Tcl increments it would again release the value, and again leave Tcl with a +dangling pointer.

    +

    Also, not decrementing the reference count at all causes the inverse problem to the +memory corruption issues of before, memory leaks.

  12. +
  13. Note that both types transfer ownership of the value. Their difference is +just in the reference count of the value coming out of the function, and the (non-)actions +having to be (not) taken to effect said transfer without causing memory issues.

  14. +
+
+

Errors & Messages

+
    +
  1. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc sqrt {
    +	Tcl_Interp* interp
    +	double      x
    +    } object0 {
    +	if (x < 0) {
    +	    Tcl_SetObjResult (interp, Tcl_ObjPrintf ("Expected double >=0, but got \"%d\"", x));
    +	    Tcl_SetErrorCode (interp, "EXAMPLE", "BAD", "DOMAIN", NULL);
    +	    return NULL;
    +	}
    +	return Tcl_NewDoubleObj(sqrt(x));
    +    }
    +
    +

    and rebuild the package.

  2. +
  3. In standard C-based packages commands signal errors by returning TCL_ERROR, +placing the error message as the interpreter result, and maybe providing an error code via +Tcl_SetErrorCode.

  4. +
  5. When using critcl::cproc this is limited and hidden.

  6. +
  7. The simple and string types for results do not allow failure. The value is returned +to the translation layer, converted into the interpreter result and then reported as +success (TCL_OK).

  8. +
  9. The object types on the other hand do allow for failure. +Return a NULL value to signal failure to the translation layer, which then reports +this to the interpreter via the standard TCL_ERROR.

  10. +
  11. Attention Setting the desired error message and code into the interpreter is +still the responsibility of the function body.

  12. +
+
+

Tcl_Interp* Access

+
    +
  1. Reread the example in the previous section.

  2. +
  3. Note the type Tcl_Interp* used for the first argument.

  4. +
  5. This type is special.

  6. +
  7. An argument of this type has to be the first argument of a function.

  8. +
  9. Using it tells CriTcl that the function needs access to the Tcl interpreter +calling it. It then arranges for that to happen in the generated C code.

    +

    Using functions from Tcl's public C API taking an interpreter argument in the +function body is a situation where this is needed.

  10. +
  11. This special argument is not visible at the script level.

  12. +
  13. This special argument is not an argument of the Tcl command for the function.

  14. +
  15. In our example the sqrt command is called with a single argument.

  16. +
  17. The name of the argument can be freely chosen. It is the type which is important +and triggers the special behaviour. +My prefered names are ip and interp.

  18. +
+
+

Binary Data Arguments

+
    +
  1. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc hello {bytes x} void {
    +        /* critcl_bytes x (.s, .len, .o); */
    +        printf("hello world, with %d bytes \n data: ", x.len);
    +        for (i = 0; i < x.len; i++) {
    +            printf(" %02x", x.s[i]);
    +            if (i % 16 == 15) printf ("\ndata: ");
    +        }
    +        if (i % 16 != 0) printf ("\n");
    +    }
    +
    +

    and rebuild the package.

  2. +
  3. To deal with strings holding binary data use the type bytes. It ensures that +the function sees the proper binary data, and not how Tcl is encoding it internally, as +the string types would.

  4. +
+
+

Constant Binary Data Results

+
    +
  1. Use the command critcl::cdata to create a command taking no arguments and +returning a constant ByteArray value.

    +
    +    # P5 3 3 255 \n ...
    +    critcl::cdata cross3x3pgm {
    +	80 52 32 51 32 51 32 50 53 53 10
    +	0   255 0
    +	255 255 255
    +	0   255 0
    +    }
    +
    +
  2. +
+
+

Tcl Runtime Version

+
    +
  1. See and reread the basic package for the introduction of the +commands referenced below.

  2. +
  3. Use the command critcl::tcl to tell CriTcl the minimal version of Tcl +the package is to be used with.

    +

    This determines which Tcl headers all files are compiled against, and what version +of the public Tcl API is available to the C code.

    +

    Currently 8.4, 8.5 and 8.6 are supported.

    +

    If not specified 8.4 is assumed.

  4. +
+
+

Additional Tcl Code

+
    +
  1. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::cproc greetings::hello {} void {
    +	printf("hello world\n");
    +    }
    +    critcl::cproc greetings::hi {} void {
    +	printf("hi you\n");
    +    }
    +
    +

    and rebuild the package.

  2. +
  3. The command hello is now available as greetings::hello, and a second +command greetings::hi was added.

  4. +
  5. Tcl has automatically created the namespace greetings.

  6. +
  7. Create a file "example-policy.tcl" and enter

    +
    +    namespace eval greetings {
    +	namespace export hello hi
    +	namespace ensemble create
    +    }
    +
    +

    into it.

  8. +
  9. Edit "example.tcl". Add the code

    +
    +    critcl::tsources example-policy.tcl
    +
    +

    and rebuild the package.

  10. +
  11. The added Tcl code makes greetings available as an ensemble +command.

    +

    The commands in the namespace have been registered as methods of the ensemble.

    +

    They can now be invoked as

    +
    +    greetings hello
    +    greetings hi
    +
    +
  12. +
  13. The Tcl builtin command string is an ensemble as well, as is clock.

  14. +
+

New commands: critcl::tsources

+
+

Debugging Support

+
    +
  1. See and reread the basic package for the introduction of the +commands referenced below.

  2. +
  3. Use the command critcl::debug to activate various features supporting debugging.

    +
    +    critcl::debug memory  ;# Activate Tcl memory debugging (-DTCL_MEM_DEBUG)
    +    critcl::debug symbols ;# Activate building and linking with debugger symbols (-g)
    +    critcl::debug all     ;# Shorthand for both `memory` and `symbols`.
    +
    +
  4. +
+
+

Install The Package

+
    +
  1. Starting from the Basics.

  2. +
  3. Use an interactive tclsh seesion to determine the value of +info library.

    +

    For the purpose of this HowTo assume that this path is +"/home/aku/opt/ActiveTcl/lib/tcl8.6"

  4. +
  5. Invoke the critcl application in a terminal, using

    +
    +    critcl -libdir /home/aku/opt/ActiveTcl/lib/tcl8.6 -pkg example.tcl
    +
    +
  6. +
  7. The package is now build and installed into the chosen directory.

    +
    +   % find /home/aku/opt/ActiveTcl/lib/tcl8.6/example/
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/pkgIndex.tcl
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/critcl-rt.tcl
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/license.terms
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/linux-x86_64
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/linux-x86_64/example.so
    +    /home/aku/opt/ActiveTcl/lib/tcl8.6/example/teapot.txt
    +
    +
  8. +
+
+
+

Using External Libraries

+

To create a minimal package wrapping an external library

+
    +
  1. Choose a directory to develop in and make it the working directory. +This should not be a checkout of CriTcl itself.

  2. +
  3. Save the following example to a file. In the following it is assumed that the file +was named "example.tcl".

    +
    +# -*- tcl -*-
    +# Critcl support, absolutely necessary.
    +package require critcl
    +# Bail out early if the compile environment is not suitable.
    +if {![critcl::compiling]} {
    +    error "Unable to build project, no proper compiler found."
    +}
    +# Information for the teapot.txt meta data file put into a generated package.
    +# Free form strings.
    +critcl::license {Andreas Kupries} {Under a BSD license}
    +critcl::summary {The second CriTcl-based package}
    +critcl::description {
    +    This package is the second example of a CriTcl-based package. It contains all the
    +    necessary and conventionally useful pieces for wrapping an external library.
    +}
    +critcl::subject {external library usage} example {critcl package}
    +critcl::subject {wrapping external library}
    +# Minimal Tcl version the package should load into.
    +critcl::tcl 8.6
    +# Locations for headers and shared library of the library to wrap.
    +# Required only for non-standard locations, i.e. where CC is not searching by default.
    +critcl::cheaders   -I/usr/include
    +critcl::clibraries -L/usr/lib/x86_64-linux-gnu
    +critcl::clibraries -lzstd
    +# Import library API, i.e. headers.
    +critcl::include zstd.h
    +# ## #### ######### ################ #########################
    +## (De)compression using Zstd
    +## Data to (de)compress is passed in and returned as Tcl byte arrays.
    +critcl::cproc compress {
    +    Tcl_Interp* ip
    +    bytes       data
    +    int         {level ZSTD_CLEVEL_DEFAULT}
    +} object0 {
    +    /* critcl_bytes data; (.s, .len, .o) */
    +    Tcl_Obj* error_message;
    +    int max = ZSTD_maxCLevel();
    +    if ((level < 1) || (level > max)) {
    +	error_message = Tcl_ObjPrintf ("level must be integer between 1 and %d", max);
    +	goto err;
    +    }
    +    size_t dest_sz  = ZSTD_compressBound (data.len);
    +    void*  dest_buf = Tcl_Alloc(dest_sz);
    +    if (!dest_buf) {
    +	error_message = Tcl_NewStringObj ("can't allocate memory to compress data", -1);
    +	goto err;
    +    }
    +    size_t compressed_size = ZSTD_compress (dest_buf, dest_sz,
    +					    data.s,   data.len,
    +					    level);
    +    if (ZSTD_isError (compressed_size)) {
    +	Tcl_Free(dest_buf);
    +	error_message = Tcl_ObjPrintf ("zstd encoding error: %s",
    +				       ZSTD_getErrorName (compressed_size));
    +	goto err;
    +    }
    +    Tcl_Obj* compressed = Tcl_NewByteArrayObj (dest_buf, compressed_size);
    +    Tcl_Free (dest_buf);
    +    return compressed;
    +  err:
    +    Tcl_SetObjResult (ip, error_message);
    +    return 0;
    +}
    +critcl::cproc decompress {
    +    Tcl_Interp*  ip
    +    bytes        data
    +} object0 {
    +    Tcl_Obj* error_message;
    +    size_t dest_sz = ZSTD_getDecompressedSize (data.s, data.len);
    +    if (dest_sz == 0) {
    +        error_message = Tcl_NewStringObj("invalid data", -1);
    +	goto err;
    +    }
    +    void* dest_buf = Tcl_Alloc (dest_sz);
    +    if (!dest_buf) {
    +	error_message = Tcl_NewStringObj("failed to allocate decompression buffer", -1);
    +	goto err;
    +    }
    +    size_t decompressed_size = ZSTD_decompress (dest_buf, dest_sz,
    +						data.s,   data.len);
    +    if (decompressed_size != dest_sz) {
    +	Tcl_Free (dest_buf);
    +        error_message = Tcl_ObjPrintf("zstd decoding error: %s",
    +				      ZSTD_getErrorName (decompressed_size));
    +	goto err;
    +    }
    +    Tcl_Obj* decompressed = Tcl_NewByteArrayObj (dest_buf, dest_sz);
    +    Tcl_Free (dest_buf);
    +    return decompressed;
    +  err:
    +    Tcl_SetObjResult (ip, error_message);
    +    return 0;
    +}
    +# ## #### ######### ################ #########################
    +# Forcing compilation, link, and loading now.
    +critcl::msg -nonewline { Building ...}
    +if {![critcl::load]} {
    +    error "Building and loading the project failed."
    +}
    +# Name and version the package. Just like for every kind of Tcl package.
    +package provide critcl-example 1
    +
    +
  4. +
  5. Build the package. See the Basics, if necessary.

  6. +
  7. Load the package and invoke the commands.

    +

    Attention. The commands take and return binary data. +This may look very bad in the terminal.

  8. +
  9. To test the commands enter

    +
    +    set a [compress {hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhello wwwwwwwworld}]
    +    decompress $a
    +
    +

    in the interactive tclsh

  10. +
+

New commands: critcl::cheaders, critcl::clibraries, critcl::include.

+

Default Values For Arguments

+
    +
  1. Reread the example of the main section. Note specifically the line

    +
    +    int {level ZSTD_CLEVEL_DEFAULT}
    +
    +
  2. +
  3. This line demonstrates that critcl::cproc arguments allowed to have default +values, in the same vein as proc arguments, and using the same syntax.

  4. +
  5. Attention Default values have to be legal C rvalues and match the C type of +the argument.

    +

    They are literally pasted into the generated C code.

    +

    They bypass any argument validation done in the generated translation layer. This +means that it is possible to use a value an invoker of the command cannot use from Tcl.

  6. +
  7. This kind of in-band signaling of a default versus a regular argument is however +not necessary.

    +

    Look at

    +
    +    critcl::cproc default_or_not {int {x 0}} void {
    +	if !has_x {
    +	    printf("called with default\n");
    +	    return
    +	}
    +	printf("called with %d\n", x);
    +    }
    +
    +

    Any argument x with a default causes CriTcl to create a hidden +argument has_x, of type int (boolean). +This argument is set to 1 when x was filled from defaults, and 0 +else.

  8. +
+
+

Custom Argument Validation

+
    +
  1. Starting from the base wrapper. + Edit the file "example.tcl". Replace the entire compress function with

    +
    +    critcl::argtype zstd_compression_level {
    +        /* argtype: `int` */
    +        if (Tcl_GetIntFromObj (interp, @@, &@A) != TCL_OK) return TCL_ERROR;
    +        /* additional validation */    
    +        int max = ZSTD_maxCLevel();
    +        if ((@A < 1) || (@A > max)) {
    +            Tcl_SetObjResult (interp,
    +                Tcl_ObjPrintf ("zstd compression level must be integer between 1 and %d", max));
    +            return TCL_ERROR;
    +        }
    +        /* @@: current objv[] element
    +        ** @A: name of argument variable for transfer to C function
    +        ** interp: predefined variable, access to current interp - error messages, etc.
    +        */
    +    } int int ;# C types of transfer variable and function argument.
    +    critcl::cproc compress {
    +        Tcl_Interp*            ip
    +        bytes                  data
    +        zstd_compression_level {level ZSTD_CLEVEL_DEFAULT}
    +    } object0 {
    +        /* critcl_bytes data; (.s, .len, .o) */
    +        /* int level; validated to be in range 1...ZSTD_maxCLevel() */
    +        Tcl_Obj* error_message;
    +        size_t dest_sz  = ZSTD_compressBound (data.len);
    +        void*  dest_buf = Tcl_Alloc(dest_sz);
    +        if (!dest_buf) {
    +            error_message = Tcl_NewStringObj ("can't allocate memory to compress data", -1);
    +            goto err;
    +        }
    +        size_t compressed_size = ZSTD_compress (dest_buf, dest_sz,
    +                                                data.s,   data.len,
    +                                                level);
    +        if (ZSTD_isError (compressed_size)) {
    +            Tcl_Free(dest_buf);
    +            error_message = Tcl_ObjPrintf ("zstd encoding error: %s",
    +                                           ZSTD_getErrorName (compressed_size));
    +            goto err;
    +        }
    +        Tcl_Obj* compressed = Tcl_NewByteArrayObj (dest_buf, compressed_size);
    +        Tcl_Free (dest_buf);
    +        return compressed;
    +    err:
    +        Tcl_SetObjResult (ip, error_message);
    +        return 0;
    +    }
    +
    +

    and rebuild the package.

    +

    In the original example the level argument of the function was validated in +the function itself. +This may detract from the funtionality of interest itself, especially if there are lots of +arguments requiring validation. +If the same kind of argument is used in multiple places this causes code duplication in +the functions as well.

    +

    Use a custom argument type as defined by the modification to move this kind of +validation out of the function, and enhance readability.

    +

    Code duplication however is only partially adressed. +While there is no duplication in the visible definitions the C code of the new argument +type is replicated for each use of the type.

  2. +
  3. Now replace the argtype definition with

    +
    +    critcl::code {
    +        int GetCompressionLevel (Tcl_Interp* interp, Tcl_Obj* obj, int* level)
    +        {
    +            if (Tcl_GetIntFromObj (interp, obj, level) != TCL_OK) return TCL_ERROR;
    +            int max = ZSTD_maxCLevel();
    +            if ((*level < 1) || (*level > max)) {
    +                Tcl_SetObjResult (interp,
    +                    Tcl_ObjPrintf ("zstd compression level must be integer between 1 and %d", max));
    +                return TCL_ERROR;
    +            }
    +            return TCL_OK;
    +        }
    +    }
    +    critcl::argtype zstd_compression_level {
    +        if (GetCompressionLevel (@@, &@A) != TCL_OK) return TCL_ERROR;
    +    } int int
    +
    +

    and rebuild the package.

    +

    Now only the calls to the new validation function are replicated. +The function itself exists only once.

  4. +
+
+

Separating Local C Sources

+
    +
  1. Starting from the end of the previous section. + Edit the file "example.tcl".

  2. +
  3. Save the contents of the critcl::ccode block into a file "example.c" and +then replace the entire block with

    +
    +    critcl::csources example.c
    +    critcl::ccode {
    +	extern int GetCompressionLevel (Tcl_Interp* interp, Tcl_Obj* obj, int* level);
    +    }
    +
    +

    When mixing C and Tcl code the different kind of indentation rules for these +languages may come into strong conflict. Further, very large blocks of C code may reduce +overall readability.

  4. +
  5. The examples fixes this by moving the code block into a local C file and then +registering this file with CriTcl. +When building the package CriTcl arranges to build all such registered C files as +well.

  6. +
  7. Attention. The C code is now in a separate compilation unit. +The example declares the exported function so that the cprocs are again able to see +and use it.

  8. +
  9. Now go a step further. Save the declaration into a file "example.h", and then +use

    +
    +    critcl::include example.h
    +
    +

    to import it. Note that this is just a shorthand for

    +
     critcl::ccode {
    +	#include "example.h"
    +    }
    +
    +
  10. +
  11. As an alternative solution, start from the beginning of the section and move the +entire original critcl::ccode block into a file "example-check.tcl".

    +

    Then replace it with

    +
    +    critcl::source example-check.tcl
    +
    +

    to import it into the main code again.

    +

    Attention Tcl's builtin command source is not suitable for +importing the separate file due to how CriTcl uses the information from +info script to key various internal datastructures.

  12. +
+
+

Very Simple Results

+
    +
  1. Starting from the end of the validation section. +Edit the file "example.tcl". +Add the code below, just before the compress command.

    +
    +    critcl::cconst version   char* ZSTD_VERSION_STRING
    +    critcl::cconst min-level int   1
    +    critcl::cconst max-level int   ZSTD_maxCLevel()
    +
    +

    and rebuild the package.

  2. +
  3. These declarations create three additional commands, each returning the specified +value. A fixed string, an integer, and a function call returning an integer.

  4. +
  5. Attention The values have to be legal C rvalues and match the C type of the +result. They are literally pasted into the generated C code.

  6. +
  7. When using critcl::cconst CriTcl is aware that the result of the +function does not depend on any parameters and is computed in a single C expression.

    +

    This enables it do to away with the internal helper function it would need and +generate if critcl::cproc had been used instead. +For example

    +
    +    critcl::cproc version {} char* {
    +	return ZSTD_VERSION_STRING;
    +    }
    +
    +
  8. +
+
+

Structure Arguments

+
    +
  1. For all that this is a part of how to +Use External Libraries, for the demonstratation +only the basics are needed.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    critcl::ccode {
    +	typedef struct vec2 {
    +	    double x;
    +	    double y;
    +	} vec2;
    +	typedef vec2* vec2ptr;
    +	int
    +	GetVecFromObj (Tcl_Interp* interp, Tcl_Obj* obj, vec2ptr* vec)
    +	{
    +	    int len;
    +	    if (Tcl_ListObjLength (interp, obj, &len) != TCL_OK) return TCL_ERROR;
    +	    if (len != 2) {
    +		Tcl_SetObjResult (interp, Tcl_ObjPrintf ("Expected 2 elements, got %d", len));
    +		return TCL_ERROR;
    +	    }
    +	    Tcl_Obj* lv[2];
    +	    if (Tcl_ListObjGetElements (interp, obj, &lv) != TCL_OK) return TCL_ERROR;
    +	    double x, y;
    +	    if (Tcl_GetDoubleFromObj (interp, lv[0], &x) != TCL_OK) return TCL_ERROR;
    +	    if (Tcl_GetDoubleFromObj (interp, lv[1], &y) != TCL_OK) return TCL_ERROR;
    +	    *vec = Tcl_Alloc (sizeof (vec2));
    +	    (*vec)->x = x;
    +	    (*vec)->y = y;
    +	    return TCL_OK;
    +	}
    +    }
    +    critcl::argtype vec2 {
    +	if (GetVecFromObj (interp, @@, &@A) != TCL_OK) return TCL_ERROR;
    +    } vec2ptr vec2ptr
    +    critcl::argtyperelease vec2 {
    +	/* @A : C variable holding the data to release */
    +	Tcl_Free ((char*) @A);
    +    }
    +    critcl::cproc norm {vec2 vector} double {
    +	double norm = hypot (vector->x, vector->y);
    +	return norm;
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. The structure to pass as argument is a 2-dimensional vector. It is actually passed +in as a pointer to a vec2 structure. +This pointer is created by the GetVecFromObj function. It allocates and fills the +structure from the Tcl value, which has to be a list of 2 doubles. The bulk of the code in +GetVecFromObj is for verifying this and extracting the doubles.

  6. +
  7. The argtyperelease code releases the pointer when the C function returns. In +other words, the pointer to the structure is owned by the translation layer and exists +only while the function is active.

  8. +
  9. While working this code has two disadvantages. +First there is memory churn. Each call of norm causes the creation and release of a +temporary vec2 structure for the argument. +Second is the need to always extract the data from the Tcl_Obj* value.

    +

    Both can be done better.

    +

    We will come back to this after explaining how to return structures to Tcl.

  10. +
+
+

Structure Results

+
    +
  1. Starting from the end of the previous section.

  2. +
  3. Edit the file "example.tcl" and add the following code, just after the +definition of the norm command.

    +
    +    critcl::resulttype vec2 {
    +	/* rv: result value of function, interp: current Tcl interpreter */
    +	if (rv == NULL) return TCL_ERROR;
    +	Tcl_Obj* lv[2];
    +	lv[0] = Tcl_NewDoubleObj (rv->x);
    +	lv[1] = Tcl_NewDoubleObj (rv->y);
    +	Tcl_SetObjResult (interp, Tcl_NewListObj (2, lv));
    +	Tcl_Free (rv);
    +	return TCL_OK;
    +    } vec2ptr ;# C result type
    +    critcl::cproc add {vec2 a vec2 b} vec2 {
    +	vec2ptr z = Tcl_Alloc (sizeof (vec2));
    +	z->x = a->x + b->x;
    +	z->y = a->y + b->y;
    +	return z;
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. The new command add takes two vectors and return the element-wise sum of both +as a new vector.

  6. +
  7. The function allocates and initializes a structure and hands it over to the +translation layer. Which in turn constructs a Tcl list of 2 doubles from it, sets that as +the command's result and at last discards the allocated structure again.

  8. +
  9. While working this code has two disadvantages. +First there is memory churn. Each call of add causes the creation and release of +three temporary vec2 structures. One per argument, and one for the result. +Second is the need to always construct a complex Tcl_Obj* value from the structure.

    +

    Both can be done better. This is explained in the next section.

  10. +
+
+

Structure Types

+
    +
  1. Starting from the end of the previous section.

  2. +
  3. Edit the file "example.tcl".

  4. +
  5. Remove the entire functionality (type definitions, related C code, and cprocs). +Replace it with

    +
    +    critcl::ccode {
    +	typedef struct vec2 {
    +	    double x;
    +	    double y;
    +	} vec2;
    +	typedef vec2* vec2ptr;
    +	/* -- Core vector structure management -- */
    +	static vec2ptr Vec2New (double x, double y) {
    +	    vec2ptr vec = Tcl_Alloc (sizeof (vec2));
    +	    vec->x = x;
    +	    vec->y = y;
    +	    return vec;
    +	}
    +	static vec2ptr Vec2Copy (vec2ptr src) {
    +	    vec2ptr vec = Tcl_Alloc (sizeof (vec2));
    +	    *vec = *src
    +	    return vec;
    +	}
    +	static void Vec2Release (vec2ptr vec) {
    +	    Tcl_Free ((char*) vec);
    +	}
    +	/* -- Tcl value type for vec2 -- Tcl_ObjType -- */
    +	static void Vec2Free     (Tcl_Obj* obj);
    +	static void Vec2StringOf (Tcl_Obj* obj);
    +	static void Vec2Dup      (Tcl_Obj* obj, Tcl_Obj* dst);
    +	static int  Vec2FromAny  (Tcl_Interp* interp, Tcl_Obj* obj);
    +	Tcl_ObjType vec2_objtype = {
    +	    "vec2",
    +	    Vec2Free,
    +	    Vec2Dup,
    +	    Vec2StringOf,
    +	    Vec2FromAny
    +	};
    +	static void Vec2Free (Tcl_Obj* obj) {
    +	    Vec2Release ((vec2ptr) obj->internalRep.otherValuePtr);
    +	}
    +	static void Vec2Dup (Tcl_Obj* obj, Tcl_Obj* dst) {
    +	    vec2ptr vec = (vec2ptr) obj->internalRep.otherValuePtr;
    +	    dst->internalRep.otherValuePtr = Vec2Copy (vec);
    +	    dst->typePtr                   = &vec2_objtype;
    +	}
    +	static void Vec2StringOf (Tcl_Obj* obj) {
    +	    vec2ptr vec = (vec2ptr) obj->internalRep.otherValuePtr;
    +	    /* Serialize vector data to string (list of two doubles) */
    +	    Tcl_DString      ds;
    +	    Tcl_DStringInit (&ds);
    +	    char buf [TCL_DOUBLE_SPACE];
    +	    Tcl_PrintDouble (0, vec->x, buf); Tcl_DStringAppendElement (&ds, buf);
    +	    Tcl_PrintDouble (0, vec->y, buf); Tcl_DStringAppendElement (&ds, buf);
    +	    int length = Tcl_DStringLength (ds);
    +	    /* Set string representation */
    +	    obj->length = length;
    +	    obj->bytes  = Tcl_Alloc(length+1);
    +	    memcpy (obj->bytes, Tcl_DStringValue (ds), length);
    +	    obj->bytes[length] = '\0';
    +	    /*
    +	    ** : package require critcl::cutil ;# get C utilities
    +	    ** : critcl::cutil::alloc          ;# Activate allocation utilities
    +	    ** : (Internally cheaders, include)
    +	    ** : Then all of the above can be written as STREP_DS (obj, ds);
    +	    ** : STREP_DS = STRing REP from DString
    +	    */
    +	    Tcl_DStringFree (&ds);
    +	}
    +	static int Vec2FromAny (Tcl_Interp* interp, Tcl_Obj* obj) {
    +	    /* Change intrep of obj to vec2 structure.
    +	    ** A Tcl list of 2 doubles is used as an intermediary intrep.
    +	    */
    +	    int len;
    +	    if (Tcl_ListObjLength (interp, obj, &len) != TCL_OK) return TCL_ERROR;
    +	    if (len != 2) {
    +		Tcl_SetObjResult (interp, Tcl_ObjPrintf ("Expected 2 elements, got %d", len));
    +		return TCL_ERROR;
    +	    }
    +	    Tcl_Obj* lv[2];
    +	    if (Tcl_ListObjGetElements (interp, obj, &lv) != TCL_OK) return TCL_ERROR;
    +	    double x, y;
    +	    if (Tcl_GetDoubleFromObj (interp, lv[0], &x) != TCL_OK) return TCL_ERROR;
    +	    if (Tcl_GetDoubleFromObj (interp, lv[1], &y) != TCL_OK) return TCL_ERROR;
    +	    obj->internalRep.otherValuePtr = (void*) Vec2New (x, y);
    +	    obj->typePtr                   = &vec2_objtype;
    +	    return TCL_OK;
    +	}
    +	/* -- (un)packing structures from/into Tcl values -- */
    +	int GetVecFromObj (Tcl_Interp* interp, Tcl_Obj* obj, vec2ptr* vec)
    +	{
    +	    if (obj->typePtr != &vec2_objtype) {
    +		if (Vec2FromAny (interp, obj) != TCL_OK) return TCL_ERROR;
    +	    }
    +	    *vec = (vec2ptr) obj->internalRep.otherValuePtr;
    +	    return TCL_OK;
    +	}
    +	Tcl_Obj* NewVecObj (vec2ptr vec) {
    +	    Tcl_Obj* obj = Tcl_NewObj ();
    +	    Tcl_InvalidateStringRep (obj);
    +	    obj->internalRep.otherValuePtr = Vec2Copy (vec);
    +	    obj->typePtr                   = &vec2_objtype;
    +	    return obj;
    +	}
    +    }
    +    critcl::argtype vec2 {
    +	if (GetVecFromObj (interp, @@, &@A) != TCL_OK) return TCL_ERROR;
    +    } vec2ptr vec2ptr
    +    critcl::resulttype vec2 {
    +	/* rv: result value of function, interp: current Tcl interpreter */
    +	Tcl_SetObjResult (interp, NewVecObj (&rv));
    +	return TCL_OK;
    +    } vec2
    +    critcl::cproc norm {vec2 vector} double {
    +	double norm = hypot (vector->x, vector->y);
    +	return norm;
    +    }
    +    critcl::cproc add {vec2 a vec2 b} vec2 {
    +	vec2 z;
    +	z.x = a->x + b->x;
    +	z.y = a->y + b->y;
    +	return z;
    +    }
    +
    +

    and rebuild the package.

  6. +
  7. This implements a new Tcl_ObjType to handle vec2 structures. With it +vec2 structures are become usable as internal representation (intrep of +Tcl_Obj* values.

    +

    The two functions NewVecObj and GetVecFromObj pack and unpack the +structures from and into Tcl_Obj* values. +The latter performs the complex deserialization into a structure if and only if needed, +i.e. when the TclObj* value has no intrep, or the intrep for a different type. +This process of changing the intrep of a Tcl value is called shimmering.

    +

    Intreps cache the interpretation of Tcl_Obj* values as a specific kind of +type. Here vec2. This reduces conversion effort and memory churn, as intreps are +kept by the Tcl interpreter as long as possible and needed.

  8. +
  9. The arguments of norm and add are now converted once on entry, if not +yet in the proper type, or not at all, if so.

  10. +
  11. Attention. This example has the issue of passing result structures by value +through the stack, and then packing a copy into a Tcl_Obj* value. +While this is no trouble for structures as small as vec2 larger structures may pose +a problem.

    +

    We will address this in the next section.

  12. +
+

Packages: critcl::cutil

+
+

Large Structures

+
    +
  1. Starting from the end of the previous section.

  2. +
  3. Edit the file "example.tcl".

  4. +
  5. Describing each individual change is too complex. The following is easier.

  6. +
  7. Save the file, then replace the entire functionality with the following.

  8. +
  9. After that use a diff of your choice to compare the files and see the +critical changes.

    +
    +    critcl::ccode {
    +	typedef struct vec2 {
    +	    unsigned int rc;
    +	    double x;
    +	    double y;
    +	} vec2;
    +	typedef vec2* vec2ptr;
    +	/* -- Core vector structure management -- */
    +	static vec2ptr Vec2New (double x, double y) {
    +	    vec2ptr vec = Tcl_Alloc (sizeof (vec2));
    +	    vec->rc = 0;
    +	    vec->x = x;
    +	    vec->y = y;
    +	    return vec;
    +	}
    +	static vec2ptr Vec2Copy (vec2ptr src) {
    +	    scr->rc ++;
    +	    return src;
    +	}
    +	static void Vec2Release (vec2ptr vec) {
    +	    if (vec->rc > 1) {
    +		vec->rc --;
    +		return;
    +	    }
    +	    
    +	    Tcl_Free ((char*) vec);
    +	}
    +	/* -- Vector obj type -- */
    +	static void Vec2Free     (Tcl_Obj* obj);
    +	static void Vec2StringOf (Tcl_Obj* obj);
    +	static void Vec2Dup      (Tcl_Obj* obj, Tcl_Obj* dst);
    +	static int  Vec2FromAny  (Tcl_Interp* interp, Tcl_Obj* obj);
    +	Tcl_ObjType vec2_objtype = {
    +	    "vec2",
    +	    Vec2Free,
    +	    Vec2Dup,
    +	    Vec2StringOf,
    +	    Vec2FromAny
    +	};
    +	static void Vec2Free (Tcl_Obj* obj) {
    +	    Vec2Release ((vec2ptr) obj->internalRep.otherValuePtr);
    +	}
    +	static void Vec2Dup (Tcl_Obj* obj, Tcl_Obj* dst) {
    +	    vec2ptr vec = (vec2ptr) obj->internalRep.otherValuePtr;
    +	    dst->internalRep.otherValuePtr = Vec2Copy (vec);
    +	    dst->typePtr                   = &vec2_objtype;
    +	}
    +	static void Vec2StringOf (Tcl_Obj* obj) {
    +	    vec2ptr vec = (vec2ptr) obj->internalRep.otherValuePtr;
    +	    /* Serialize vector data to string (list of two doubles) */
    +	    Tcl_DString      ds;
    +	    Tcl_DStringInit (&ds);
    +	    char buf [TCL_DOUBLE_SPACE];
    +	    Tcl_PrintDouble (0, vec->x, buf); Tcl_DStringAppendElement (&ds, buf);
    +	    Tcl_PrintDouble (0, vec->y, buf); Tcl_DStringAppendElement (&ds, buf);
    +	    int length = Tcl_DStringLength (ds);
    +	    /* Set string representation */
    +	    obj->length = length;
    +	    obj->bytes  = Tcl_Alloc(length+1);
    +	    memcpy (obj->bytes, Tcl_DStringValue (ds), length);
    +	    obj->bytes[length] = '\0';
    +	    /*
    +	    ** : package require critcl::cutil ;# get C utilities
    +	    ** : critcl::cutil::alloc          ;# Activate allocation utilities
    +	    ** : (Internally cheaders, include)
    +	    ** : Then all of the above can be written as STREP_DS (obj, ds);
    +	    ** : STREP_DS = STRing REP from DString
    +	    */
    +	    Tcl_DStringFree (&ds);
    +	}
    +	static int Vec2FromAny (Tcl_Interp* interp, Tcl_Obj* obj) {
    +	    /* Change internal rep of obj to vector structure.
    +	    ** A Tcl list of 2 doubles is used as intermediary int rep.
    +	    */
    +	    int len;
    +	    if (Tcl_ListObjLength (interp, obj, &len) != TCL_OK) return TCL_ERROR;
    +	    if (len != 2) {
    +		Tcl_SetObjResult (interp, Tcl_ObjPrintf ("Expected 2 elements, got %d", len));
    +		return TCL_ERROR;
    +	    }
    +	    Tcl_Obj* lv[2];
    +	    if (Tcl_ListObjGetElements (interp, obj, &lv) != TCL_OK) return TCL_ERROR;
    +	    double x, y;
    +	    if (Tcl_GetDoubleFromObj (interp, lv[0], &x) != TCL_OK) return TCL_ERROR;
    +	    if (Tcl_GetDoubleFromObj (interp, lv[1], &y) != TCL_OK) return TCL_ERROR;
    +	    obj->internalRep.otherValuePtr = (void*) Vec2New (x, y);
    +	    obj->typePtr                   = &vec2_objtype;
    +	    return TCL_OK;
    +	}
    +	/* (un)packing structures from/into Tcl values -- */
    +	int GetVecFromObj (Tcl_Interp* interp, Tcl_Obj* obj, vec2ptr* vec)
    +	{
    +	    if (obj->typePtr != &vec2_objtype) {
    +		if (VecFromAny (interp, obj) != TCL_OK) return TCL_ERROR;
    +	    }
    +	    *vec = (vec2ptr) obj->internalRep.otherValuePtr;
    +	    return TCL_OK;
    +	}
    +	Tcl_Obj* NewVecObj (vec2ptr vec) {
    +	    Tcl_Obj* obj = Tcl_NewObj ();
    +	    Tcl_InvalidateStringRep (obj);
    +	    obj->internalRep.otherValuePtr = Vec2Copy (vec);
    +	    obj->typePtr                   = &vec2_objtype;
    +	    return obj;
    +	}
    +    }
    +    critcl::argtype vec2 {
    +	if (GetVecFromObj (interp, @@, &@A) != TCL_OK) return TCL_ERROR;
    +    } vec2ptr vec2ptr
    +    critcl::resulttype vec2 {
    +	/* rv: result value of function, interp: current Tcl interpreter */
    +	Tcl_SetObjResult (interp, NewVecObj (rv));
    +	return TCL_OK;
    +    } vec2ptr
    +    critcl::cproc norm {vec2 vector} double {
    +	double norm = hypot (vector->x, vector->y);
    +	return norm;
    +    }
    +    critcl::cproc add {vec2 a vec2 b} vec2 {
    +	return Vec2New (a->x + b->x, a->y + b->y);
    +    }
    +
    +
  10. +
  11. The vec2 structure is now reference counted.

  12. +
  13. The core management functions, i.e. Vec2New, Vec2Copy, and +Vec2Release are changed to maintain that reference count. +Starting at 0 on creation, copies increment, and releases decrement. +A structure is actually only freed when its reference count falls to 0 or below.

  14. +
  15. vec2 results are changed to pointers, easily passed back through the stack. +The modified translation layer just wraps it into a Tcl_Obj* value.

  16. +
  17. Attention. Duplicating such a Tcl_Obj* does not duplicate the +referenced vec2 structure anymore, just adds a reference.

  18. +
  19. Regarding diff commands, I know of two graphical diffs for Tcl/Tk, +TkDiff, and Eskil.

  20. +
+

Packages: critcl::cutil

+
+

External Structures

+
    +
  1. Handle structures provided by external libraries using either +Structure Types or Large Structures as template.

  2. +
  3. Attention. The choice is with the developer.

    +

    This is true even if the external structure is not reference counted by itself.

    +

    To reference count a structure S without such simply wrap S into a +local structure which provides the reference count and has a field for S (pointer +or value).

  4. +
  5. Attention Opaque external types, i.e. pointers to structures with hidden +fields, can also be handled by the given templates.

  6. +
+
+

External Enumerations

+

This section demonstrates how to convert from any kind of enumeration provided by an +external library to Tcl strings, and the converse.

+
    +
  1. For all that this is a part of how to +Use External Libraries, for the demonstratation +only the basics are needed.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    package require critcl::emap
    +    # no header included due to use of literal ints instead of symbolic names
    +    critcl::emap::def yaml_sequence_style_t {
    +	any   0
    +	block 1
    +	flow  2
    +    }
    +    # encode: style to int
    +    critcl::cproc encode {yaml_sequence_style_t style} int {
    +	return style;
    +    }
    +    # decode: int to style
    +    critcl::cproc decode {int style} yaml_sequence_style_t {
    +	return style;
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. The map converts between the Tcl level strings listed on the left side to the C +values on the right side, and the reverse.

  6. +
  7. It automatically generates critcl::argtype and critcl::resulttype +definitions.

  8. +
  9. Attention Like the default values for cproc arguments, and the results +for cconst definitions the values on the right side have to be proper C +rvalues. They have to match C type int.

    +

    In other words, it is perfectly ok to use the symbolic names provided by the header +file of the external library.

    +

    Attention This however comes at a loss in efficiency. As CriTcl then +has no insight into the covered range of ints, gaps, etc. it has to perform a linear +search when mapping from C to Tcl. When it knows the exact integer values it can use a +table lookup instead.

    +

    Attention It also falls back to a search if a lookup table would contain more +than 50 entries.

  10. +
+

Packages: critcl::emap

+
+

External Bitsets/Bitmaps/Flags

+

This section demonstrates how to convert from any kind of bit-mapped flags provided by an +external library to lists of Tcl strings, and the converse.

+
    +
  1. For all that this is a part of how to +Use External Libraries, for the demonstratation +only the basics are needed.

  2. +
  3. Starting from the Basics. + Edit the file "example.tcl". + Remove the definition of hello. Replace it with

    +
    +    # http://man7.org/linux/man-pages/man7/inotify.7.html
    +    
    +    package require critcl::bitmap
    +    # critcl::cheaders - n/a, header is in system directories
    +    critcl::include sys/inotify.h
    +    
    +    critcl::bitmap::def tcl_inotify_events {
    +	accessed       IN_ACCESS
    +	all            IN_ALL_EVENTS
    +	attribute      IN_ATTRIB
    +	closed         IN_CLOSE
    +	closed-nowrite IN_CLOSE_NOWRITE
    +	closed-write   IN_CLOSE_WRITE
    +	created        IN_CREATE
    +	deleted        IN_DELETE
    +	deleted-self   IN_DELETE_SELF
    +	dir-only       IN_ONLYDIR
    +	dont-follow    IN_DONT_FOLLOW
    +	modified       IN_MODIFY
    +	move           IN_MOVE
    +	moved-from     IN_MOVED_FROM
    +	moved-self     IN_MOVE_SELF
    +	moved-to       IN_MOVED_TO
    +	oneshot        IN_ONESHOT
    +	open           IN_OPEN
    +	overflow       IN_Q_OVERFLOW
    +	unmount        IN_UNMOUNT
    +    } {
    +	all closed move oneshot
    +    }
    +    
    +    # encode: flag set to int
    +    critcl::cproc encode {tcl_inotify_events e} int {
    +	return e;
    +    }
    +    # decode: int to flag set
    +    critcl::cproc decode {int e} tcl_inotify_events {
    +	return e;
    +    }
    +
    +

    and rebuild the package.

  4. +
  5. The map converts between lists of the Tcl level strings listed on the left side to +the bit-union of the C values on the right side, and the reverse.

    +

    It is noted that the four strings all, closed, move, and +oneshot cannot be converted from C flags to list of strings, only from list to +bits.

  6. +
  7. It automatically generates critcl::argtype and critcl::resulttype +definitions.

  8. +
  9. Attention Like the default values for cproc arguments, and the results +for cconst definitions the values on the right side have to be proper C +rvalues. They have to match C type int.

    +

    In other words, it is perfectly ok to use the symbolic names provided by the header +file of the external library. As shown.

  10. +
+

Packages: critcl::bitmap

+
+

Non-standard header/library locations

+
    +
  1. See and reread the basic wrapper package for +the introduction of the commands referenced below.

  2. +
  3. Attention Relative paths will be resolved relative to the location of the +".tcl" file containing the CriTcl commands.

  4. +
  5. Use the command critcl::cheaders to tell CriTcl about non-standard +locations for header files.

    +

    Multiple arguments are allowed, and multiple calls as well. The information +accumulates.

    +

    Arguments of the form "-Idirectory" register the directory directly.

    +

    For arguments of the form "path" the directory holding the path is +registered. In other words, it is assumed to be the full path of a header file, and +not a directory.

    +
    +    critcl::cheaders -I/usr/local/include
    +    critcl::cheaders local/types.h
    +    critcl::cheaders other-support/*.h
    +
    +
  6. +
  7. Use the command critcl::include to actually use a specific header file.

  8. +
  9. Use the command critcl::clibraries to tell CriTcl about non-standard +locations for shared libaries, and about shared libaries to link to

    +

    Multiple arguments are allowed, and multiple calls as well. The information +accumulates.

    +

    Arguments of the form "-Ldirectory" register a directory.

    +

    Arguments of the form "-lname" register a shared libary to link to by +name. The library will be looked for in both standard and registered directories.

    +

    Arguments of the form "-path" register a shared libary to link to by full +path.

    +
    +    critcl::clibraries -L/usr/lib/x86_64-linux-gnu
    +    critcl::clibraries -lzstd
    +    critcl::clibraries /usr/lib/x86_64-linux-gnu/libzstd.so
    +
    +
  10. +
  11. On Mac OS X use the command critcl::framework to name the frameworks to use +in the package.

    +

    Attention Using the command on other platforms is ok, and will be ignored.

  12. +
  13. Not answered in the above is how to find the necessary paths if they are not fixed +across machines or platforms.

    +

    We will come back to this.

  14. +
+
+

Non-standard compile/link configuration

+
    +
  1. See and reread the basic wrapper package for +the introduction of the commands referenced below.

  2. +
  3. Use the command critcl::cflags to provide additional, non-standard flags to +the compiler.

    +
    +    critcl::cflags -DBYTE_ORDER=bigendian
    +
    +
  4. +
  5. Use the command critcl::ldflags to provide additional, non-standard flags to +the linker.

    +
    +    critcl::ldflags -
    +
    +
  6. +
  7. Not answered in the above is how to determine such flags if they are not fixed +across machines or platforms.

    +

    This is addressed by the next section.

  8. +
+
+

Querying the compilation environment

+
    +
  1. Use the command critcl::check to immediately check if a piece of C code can +compiled successfully as a means of querying the compiler configuration itself.

    +
    +    if {[critcl::check {
    +        #include <FOO.h>
    +    }]} {
    +        Do stuff with FOO.h present.
    +    } else {
    +        Do stuff without FOO.h
    +    }
    +
    +

    All header and library paths which were registered with CriTcl before using +critcl::check take part in the attempted compilation.

    +

    Use the package critcl::util and various convenience commands it +provides.

  2. +
  3. Use the full Power of Tcl (tm) itself.

  4. +
+
+

Shared C Code

+
    +
  1. See and reread the basic wrapper package for +the introduction of the commands referenced below.

  2. +
  3. Use the command critcl::ccode to write C code residing outside of cproc +bodies.

  4. +
  5. Or, alternatively, place the C code into one or more ".c" files and use the +command critcl::csources to register them with CriTcl for compilation.

  6. +
  7. This topic is also treated in section Separating Local C Sources.

  8. +
+
+
+

Various

+

Author, License, Description, Keywords

+
    +
  1. See and reread the basic package for the introduction of the +commands referenced below.

  2. +
  3. Use the command critcl::license to set the package license.

    +

    Use the same command to set the package author.

    +

    Both arguments are free form text.

  4. +
  5. Use the command critcl::summary to set a short package description.

  6. +
  7. Use the command critcl::description to set a longer package description.

    +

    The arguments of both commands are free form text.

  8. +
  9. Use the command critcl::subject to set one or more keywords.

    +

    Attention Contrary to the other commands the arguments accumulate.

  10. +
  11. All the commands are optional.

  12. +
  13. Their information is not placed into the generated C code.

  14. +
  15. In package mode the information is placed into the file "teapot.txt" +of the generated package.

  16. +
  17. This file serves as integration point for Teapot, the package system of +ActiveTcl.

  18. +
+
+

Get Critcl Application Help

+
    +
  1. Invoke the command

    +
    +    critcl -help
    +
    +

    in a terminal to get help about the critcl application.

  2. +
+
+

Supported Targets & Configurations

+
    +
  1. Invoke the application as

    +
    +    critcl -show
    +
    +

    in a terminal to get the detailed configuration of the target for the current platform.

  2. +
  3. Invoke the application as

    +
    +    critcl -show -target NAME
    +
    +

    in a terminal to get the detailed configuration of the named target.

  4. +
  5. Invoke the application as

    +
    +    critcl -targets
    +
    +

    in a terminal to get a list of the available targets.

  6. +
+
+

Building A Package

+
    +
  1. Start at section Basics.

  2. +
+
+

Building A Package For Debugging

+
    +
  1. Start at section Basics.

  2. +
+
+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_iassoc.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_iassoc.html new file mode 100644 index 00000000..241f83cd --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_iassoc.html @@ -0,0 +1,251 @@ + +critcl::iassoc - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::iassoc(n) 1.2 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::iassoc - CriTcl - Code Gen - Tcl Interp Associations

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2?
  • +
  • package require critcl::iassoc ?1.2?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the critcl::iassoc +package. This package provides convenience commands for advanced +functionality built on top of the critcl core.

+

With it a user wishing to associate some data with a Tcl +interpreter via Tcl's Tcl_(Get|Set)AssocData() APIs can now +concentrate on the data itself, while all the necessary boilerplate +around it is managed by this package.

+

Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::iassoc::def name arguments struct constructor destructor
+

This command defines a C function with the given name which +provides access to a structure associated with a Tcl interpreter.

+

The C code code fragment struct defines the elements of +said structure, whereas the fragments constructor and +destructor are C code blocks executed to initialize and release +any dynamically allocated parts of this structure, when needed. Note +that the structure itself is managed by the system.

+

The new function takes a Tcl_Interp* pointer refering +to the interpreter whose structure we wish to obtain as the first +argument, plus the specified arguments and returns a pointer to +the associated structure, of type "name_data" (see below).

+

The arguments are a dictionary-like list of C types and +identifiers specifying additional arguments for the accessor function, +and, indirectly, the constructor C code block. This is useful +for the supplication of initialization values, or the return of more +complex error information in case of a construction failure.

+

The C types associated with the structure are derived from +name, with "name_data__" the type of the structure itself, +and "name_data" representing a pointer to the structure. +The C code blocks can rely on the following C environments:

+
+
constructor
+
+
data
+

Pointer to the structure (type: name_data) to +initialize.

+
interp
+

Pointer to the Tcl interpreter (type: Tcl_Interp*) +the new structure will be associated with.

+
error
+

A C code label the constructor can jump to should it have +to signal a construction failure. It is the responsibility of the +constructor to release any fields already initialized before jumping +to this label.

+
...
+

The names of the constructor arguments specified with +arguments.

+
+
destructor
+
+
data
+

Pointer to the structure being released.

+
interp
+

Pointer to the Tcl interpreter the structure +belonged to.

+
+
+
+
+

Example

+

The example shown below is the specification of a simple interpreter-associated +counter. The full example, with meta data and other incidentals, can be found +in the directory "examples/queue" of the critcl source +distribution/repository.

+
+package require Tcl 8.6
+package require critcl 3.2
+critcl::buildrequirement {
+    package require critcl::iassoc
+}
+critcl::iassoc::def icounter {} {
+    int counter; /* The counter variable */
+} {
+    data->counter = 0;
+} {
+    /* Nothing to release */
+}
+critcl::ccode {
+    ... function (...)
+    {
+         /* Access to the data ... */
+         icounter_data D = icounter (interp /* ... any declared arguments, here, none */);
+	 ... D->counter ...
+    }
+}
+# or, of course, 'cproc's, 'ccommand's etc.
+package provide icounter 1
+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_license.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_license.html new file mode 100644 index 00000000..e7ba8559 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_license.html @@ -0,0 +1,178 @@ + +critcl_license - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_license(n) 1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_license - The CriTcl License

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

All packages are under the BSD license.

+
+

License

+

This software is copyrighted by Andreas Kupries 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-7014 (b) (3) +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.

+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_literals.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_literals.html new file mode 100644 index 00000000..db7aacca --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_literals.html @@ -0,0 +1,274 @@ + +critcl::literals - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::literals(n) 1.4 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::literals - CriTcl - Code Gen - Constant string pools

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2?
  • +
  • package require critcl::literals ?1.4?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the +critcl::literals package. This package provides convenience +commands for advanced functionality built on top of both critcl core +and package critcl::iassoc.

+

Many packages will have a fixed set of string constants +occuring in one or places. Most of them will be coded to create a new +string Tcl_Obj* from a C char* every time the constant +is needed, as this is easy to to, despite the inherent waste of +memory.

+

This package was written to make declaration and management of +string pools which do not waste memory as easy as the wasteful +solution, hiding all attendant complexity from the user.

+

Its intended audience are mainly developers wishing to write +Tcl packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::literals::def name definition ?mode?
+

This command defines a C function with the given name which +provides access to a pool of constant strings with a Tcl interpreter.

+

The definition dictionary provides the mapping from the +C-level symbolic names to the string themselves.

+

The mode-list configures the output somewhat. +The three allowed modes are c, +list and tcl. +All modes can be used together. +The default mode is tcl. +Using mode +list implies tcl as well.

+

For mode tcl the new function has two arguments, a +Tcl_Interp* pointer refering to the interpreter holding the +string pool, and a code of type "name_names" (see below), the +symbolic name of the literal to return. The result of the function is +a Tcl_Obj* pointer to the requested string constant.

+

For mode c the new function has one argument, a code of +type "name_names" (see below), the symbolic name of the literal +to return. The result of the function is a const char* +pointer to the requested string constant.

+

For mode +list all of tcl applies, plus an +additional function is generated which takes three arguments, in +order, a Tcl_Interp* pointer refering to the interpreter +holding the string pool, an int holding the size of the last +argument, and an array of type "name_names" holding the codes +(see below), the symbolic names of the literals to return. The result +of the function is a Tcl_Obj* pointer to a Tcl list holding the +requested string constants.

+

The underlying string pool is automatically initialized on +first access, and finalized on interpreter destruction.

+

The package generates multiple things (declarations and +definitions) with names derived from name, which has to be a +proper C identifier.

+
+
name
+

The mode tcl function providing access to the string pool. +Its signature is

+
+Tcl_Obj* name (Tcl_Interp* interp, name_names literal);
+
+
+
name_list
+

The mode +list function providing multi-access to the string pool. +Its signature is

+
+Tcl_Obj* name_list (Tcl_Interp* interp, int c, name_names* literal);
+
+
+
name_cstr
+

The mode c function providing access to the string pool. +Its signature is

+
+const char* name_cstr (name_names literal);
+
+
+
name_names
+

A C enumeration type containing the symbolic names of the strings +provided by the pool.

+
name.h
+

A header file containing the declarations for the accessor functions +and the enumeration type, for use by other parts of the system, if +necessary.

+

The generated file is stored in a place where it will not +interfere with the overall system outside of the package, yet also be +available for easy inclusion by package files (csources).

+
name
+

New in version 1.1: +For mode tcl the command registers a new result-type for +critcl::cproc with critcl, which takes an integer result from +the function and converts it to the equivalent string in the pool for +the script.

+
+
+
+

Example

+

The example shown below is the specification of the string pool pulled +from the draft work on a Tcl binding to Linux's inotify APIs.

+
+package require Tcl 8.6
+package require critcl 3.2
+critcl::buildrequirement {
+    package require critcl::literals
+}
+critcl::literals::def tcl_inotify_strings {
+    w_create	"create"
+    w_directory	"directory"
+    w_events	"events"
+    w_file	"file"
+    w_handler	"handler"
+    w_remove	"remove"
+} {c tcl}
+# Declarations: tcl_inotify_strings.h
+# Type:         tcl_inotify_strings_names
+# Accessor:     Tcl_Obj*    tcl_inotify_strings      (Tcl_Interp*               interp,
+#                                                     tcl_inotify_strings_names literal);
+# Accessor:     const char* tcl_inotify_strings_cstr (tcl_inotify_strings_names literal);
+# ResultType:   tcl_inotify_strings
+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_package.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_package.html new file mode 100644 index 00000000..9c72d539 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_package.html @@ -0,0 +1,1801 @@ + +critcl_package - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_package(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_package - CriTcl Package Reference

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2.1?
  • +
  • package require platform ?1.0.2?
  • +
  • package require md5 ?2?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

The critcl package is the core of the system. For an overview of the +complete system, see Introduction To CriTcl. For the usage of the +standalone critcl program, see CriTcl Application. +This core package maybe be used to embed C code into Tcl scripts. It also +provides access to the internals that other parts of the core use and which +are of interest to those wishing to understand the internal workings of the +core and of the API it provides to the CriTcl Application. These +advanced sections are marked as such so that those simply wishing to use the +package can skip them.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+

A short note ahead of the documentation: Instead of repeatedly talking +about +"a Tcl script with embbedded C code", or +"a Tcl script containing CriTcl commands", +we call such a script a CriTcl script. A file containing a +CriTcl script usually has the extension .tcl or +.critcl.

+

Embedded C Code

+

The following commands append C code fragments to the current module. Fragments +appear in the module in the order they are appended, so the earlier fragments +(variables, functions, macros, etc.) are visible to later fragments.

+
+
::critcl::ccode fragment
+

Appends the C code in fragment to the current module and returns the +empty string. +See Runtime Behaviour.

+
::critcl::ccommand tclname cname
+

As documented below, except that cname is the name of a C function +that already exists.

+
::critcl::ccommand tclname arguments body ?option value...?
+

Appends the code to create a Tcl command named tclname and a +corresponding C function whose body is body and which behaves as +documented for Tcl's own +Tcl_CreateObjCommand.

+

aguments is a list of zero to four names for the standard arguments +clientdata, interp, objc, and objv. The +standard default names are used in place of any missing names. +This is a more low-level way than critcl::cproc to define a command, as +processing of the items in objv is left to the author, affording +complete control over the handling of the arguments to the command. +See section Runtime Behaviour.

+

Returns the empty string.

+

Each option may be one of:

+
+
-clientdata c-expression
+

Provides the client data for the new command. NULL by default.

+
-delproc c-expression
+

Provides a function pointer of type Tcl_CmdDeleteProc as the deletion function for the new command. NULL by default.

+
-cname boolean
+

If false (the default), a name for the corresponding C function is +automatically derived from the fully-qualified tclname. Otherwise, name +of the C function is the last component of tclname.

+
+
::critcl::cdata tclname data
+

Appends the code to create a new Tcl command named tclname which returns +data as a ByteArray result.

+

Returns the empty string.

+
::critcl::cconst tclname resulttype value
+

Appends the code to create a new Tcl command named tclname which returns +the constant value having the Tcl type resulttype. value can +be a C macro or a function call (including the parentheses) to any +visible C function that does not take arguments. +Unlike critcl::cdata, resulttype can be any type known to +critcl::cproc. +Its semantics are equivalent to:

+
+    cproc $tclname {} $resulttype "return $value ;"
+
+

This is more efficient than critcl::cproc since there is no +C function generated.

+

Returns the empty string.

+
::critcl::cdefines list of glob patterns ?namespace?
+

Arranges for C enum and #define values that match one of the +patterns in glob patterns to be created in the namespace +namespace, each variable having the same as the corresponding C item. +The default namespace is the global namespace. A pattern that matches nothing +is ignored.

+

The Tcl variables are created when the module is compiled, using the +preprocessor in order to properly find all matching C definitions.

+

Produces no C code. The desired C definitions must already exist.

+
::critcl::cproc name arguments resulttype body ?option value...?
+

Appends a function having body as its body, another shim function to +perform the needed conversions, and the code to create a corresponding Tcl +command named tclname. Unlike critcl::ccommand the arguments and +result are typed, and CriTcl generates the code to convert between Tcl_Obj +values and C data types. +See also Runtime Behaviour.

+

Returns the empty string.

+
+
string option
+

Each may be one of:

+
+
-cname boolean
+

If false (the default), a name for the corresponding C function is +automatically derived from the fully-qualified tclname. Otherwise, name +of the C function is the last component of tclname.

+
-pass-cdata boolean
+

If false (the default), the shim function performing the conversion to +and from Tcl level does not pass the ClientData as the first argument to +the function.

+
-arg-offset int
+

A non-negative integer, 0 by default, indicating the number of hidden +arguments preceding the actual procedure arguments. Used by higher-order code +generators where there are prefix arguments which are not directly seen by the +function but which influence argument counting and extraction.

+
+
string resulttype
+

May be a predefined or a custom type. +See CriTcl cproc Type Reference for the full list of predefined types and how to +extend them. +Unless otherwise noted, the Tcl return code is always TCL_OK.

+
list arguments
+

Is a multi-dictionary where each key is an +argument type and its value is the argument name. +For example:

+
 int x int y 
+

Each argument name must be a valid C identifier.

+

If the name is a list containing two items, the first item is the name +and the second item is the default value. A limited form of variadic arguments +can be accomplished using such default values. +For example:

+
 int {x 1} 
+

Here x is an optional argument of type int with a default +value of 1.

+

Argument conversion is completely bypassed when the argument is not +provided, so a custom converter doing validation does not get the chance to +validate the default value. In this case, the value should be checked in the +body of the function.

+

Each argument type may be a predefined or custom type. +See CriTcl cproc Type Reference for the full list of predefined types and how to +extend them.

+
+
::critcl::cproc name arguments resulttype
+

As documented below, but used when the C function named name already +exists.

+
::critcl::cinit text externals
+

Appends the C code in text and externals, but only after all the +other fragments appended by the previously-listed commands regardless of their +placement in the CriTcl script relative to this command. Thus, all +their content is visible. See also Runtime Behaviour.

+

The C code in text is placed into the body of the initialization +function of the shared library backing the CriTcl script, and is +executed when this library is loaded into the interpreter. It has access to +the variable Tcl_Interp* interp referencing the Tcl interpreter currently +being initialized.

+

externals is placed outside and just before the initialization +function, making it a good place for any external symbols required by +initialization function, but which should not be accessible by any other parts +of the C code.

+

Calls to this command are cumulative.

+

Returns the empty string.

+
::critcl::include path
+

This command is a convenient shorthand for

+
+critcl::code {
+  #include <${path}>
+}
+
+
+
+
+

Stubs Table Management

+

CriTcl versions 3 and later provide critcl::api to create and manipulate +stubs tables, Tcl's dynamic linking mechanism handling the resolution of +symbols between C extensions. +See http://wiki.tcl-lang.org/285 +for an introduction, and section Stubs Tables +for the details of CriTcl's particular variant.

+

Importing stubs tables, i.e. APIs, from another extension:

+
+
::critcl::api import name version
+

Adds the following include directives into the CriTcl script +and each of its companion ".c" files:

+
    +
  1. #include <name/nameDecls.h>

  2. +
  3. #include <name/nameStubLib.h>

  4. +
+

Returns an error if "name" isn't in the search path for the +compiler. See critcl::cheaders and the critcl application's -I +and -includedir options.

+

Important: If name is a fully-qualified name in a +non-global namespace, e.g. +"c::stack", the namespace separators "::" are converted into underscores +("_") in path names, C code, etc.

+

name/nameDecls.h contains the stubs table type declarations, +mapping macros, etc., and may include package-specific headers. See +critcl::api header, below. An #include directive is added at +the beginning of the generated code for CriTcl script and at the +beginning of each of its companion ".c" files.

+

name/nameStubLib.h contains the stubs table variable +definition and the function to initialize it. An #include directive +for it is added to the initialization code for the CriTcl script , +along with a call to the initializer function.

+

If "name/name.decls" accompanies +name/nameDecls.h, it should contain the external representation of +the stubs table used to generate the headers. The file is read and the internal +representation of the stubs table returned for use by the importing package. +Otherwise, the empy string is returned.

+

One possible use would be the automatic generation of C code +calling on the functions listed in the imported API.

+

When generating a TEA package the names of the imported APIs +are used to declare configure options with which the user can +declare a non-standard directory for the headers of the API. Any API +name is translated into a single configure option +--with-name-include.

+
+

Declaration and export of a stubs table, i.e. API, for +the CriTcl script:

+
+
::critcl::api function resulttype name arguments
+

Adds to the public API of the CriTcl script the signature +for the function named name and having the signature specified by +arguments and resulttype. Code is generated for a ".decls" +file, the corresponding public headers, and a stubs table usable by +critcl::api import.

+

arguments is a multidict where each key is an argument type and its +value is the argument name, and resulttype is a C type.

+
::critcl::api header ?glob pattern...?
+

Each file matching a glob pattern is copied into the directory +containing the generated headers, and an #include directive for it is +added to "Decls.h" for the CriTcl script. +Returns an error if a glob pattern matches nothing.

+

A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+
::critcl::api extheader ?file...?
+

Like ::critcl::api header, but each file should exist in the +external development environment. An #include directive is added to +"fooDecls.h", but file is not copied to the package header +directory. file is not a glob pattern as CriTcl has no context, +i.e directory, in which to expand such patterns.

+
+

As with the headers for an imported API, an #include directive is +added to the generated code for the CriTcl script and to +each companion ".c" file.

+

In "compile & run" mode the generated header files and any companion +headers are placed in the Result Cache subdirectory for the +CriTcl script. This directory is added to the include search path of +any other package importing this API and and building in mode "compile & run".

+

In "generate package" mode -includedir specifies the +subdirectory in the package to place the generated headers in. This +directory is added to the search paths for header files, ensuring that a +package importing an API finds it if the package exporting that API used the +same setting for -includedir.

+

In "generate TEA" mode the static scanner recognizes +critcl::api header as a source of companion files. +It also uses data from calls to critcl::api import to +add support for --with-foo-include options into the +generated "configure(.in)" so that a user may specify custom +locations for the headers of any imported API.

+
+

Package Meta Data

+

CriTcl versions 3 and later can create TEApot meta-data to be placed into +"teapot.txt" in a format suitable for use by the +TEApot tools.

+

In version 2, some meta data support was already present through +::critcl::license, but this was only used to generate "license.txt".

+
+
::critcl::license author ?text...?
+

Ignored in "compile & run" mode.

+

In "generate package" mode provides information about the author of the +package and the license for the package.

+

text arguments are concatenated to form the text of the license, which is +written to "license.terms" in the same directory as "pkgIndex.tcl". +If no text is provided the license is read from "license.terms" +in the same directory as the CriTcl script.

+

This information takes precedence over any information specified through +the generic API ::critcl::meta. It is additionally placed +into the meta data file "teapot.txt" under the keys as::author and +license.

+
::critcl::summary text
+

Ignored in "compile & run" mode.

+

In "generate package" mode places a short, preferably one-line description of +the package into the meta data file "teapot.txt" under the key +summary. This information takes precedence over information specified +through the generic API ::critcl::meta.

+
::critcl::description text
+

Ignored in "compile & run" mode.

+

In "generate package" mode places a longer description of the package into the +meta data file "teapot.txt", under the key description. The data +specified by this command takes precedence over any information specified +through the generic API ::critcl::meta.

+
::critcl::subject ?key...?
+

Ignored in "compile & run" mode.

+

In "generate package" mode places each key into the meta data file +"teapot.txt", under the key subject. This information takes +precedence over any information specified through the generic API +::critcl::meta.

+

Calls to this command are cumulative.

+
::critcl::meta key ?word...?
+

Provides arbitrary meta data outside of the following reserved keys: +as::author, +as::build::date, +description, +license, +name, +platform, +require +subject, +summary, and +version, +Its behaviour is like ::critcl::subject in that it treats all +keys as list of words, with each call providing one or more words for +the key, and multiple calls extending the data for an existing key, if +not reserved.

+

While it is possible to declare information for one of the +reserved keys with this command such data is ignored when the final +meta data is assembled and written.

+

Use the commands +::critcl::license, +::critcl::summary, +::critcl::description +::critcl::subject, +package require, and +package provide +to declare data for the reserved keys.

+

The information for the reserved keys +as::build::date and +platform +is automatically generated by critcl itself.

+
::critcl::meta? key
+

Returns the value in the metadata associated with key.

+

Used primarily to retrieve the name of the package +from within utility packages having to adapt C code templates to their +environment. For example, critcl::class uses does this.

+
::critcl::buildrequirement script
+

Provides control over the capturing of dependencies declared via +package require. script is evaluated and any dependencies +declared within are ignored, i.e. not recorded in the meta data.

+
+
+

Control & Interface

+

These commands control the details of compilation and linking a +CriTcl script. The information is used only to compile/link the +object for the CriTcl script. For example, information for +"FOO.tcl" is kept separate from information for "BAR.tcl".

+
+
::critcl::cheaders ?arg...?
+

Provides additional header locations.

+

Each argument is a glob pattern. If an argument begins with - +it is an argument to the compiler. Otherwise the parent directory of each +matching path is a directory to be searched for header files. Returns an +error if a pattern matches no files. +A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+

#include lines are not automatically generated for matching +header files. Use critcl::include or critcl::ccode as necessary to +add them.

+

Calls to this command are cumulative.

+
::critcl::csources ?glob pattern...?
+

Matching paths become inputs to the compilation of the current object +along with the sources for the current CriTcl script. Returns an +error if no paths match a pattern. +A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+

Calls to this command are cumulative.

+
::critcl::clibraries ?glob pattern...?
+

provides the link step with additional libraries and library locations. +A glob pattern that begins with - is added as an argument to +the linker. Otherwise matching files are linked into the shared library. +Returns an error if no paths match a pattern. +A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+

Calls to this command are cumulative.

+
::critcl::source glob pattern
+

Evaluates as scripts the files matching each glob pattern. Returns an +error if there are no matching files. +A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+
::critcl::tsources glob pattern...
+

Provides the information about additional Tcl script files to source when the +shared library is loaded.

+

Matching paths are made available to the generated shared library when +it is loaded for the current CriTcl script. Returns an error if a +pattern matches no files. +A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+

Calls to this command are cumulative.

+

After the shared library has been loaded, the declared files are sourced +in the same order that they were provided as arguments.

+
::critcl::owns glob pattern...
+

Ignored in "compile and run" and "generate package" modes. +In "generate TEA" mode each file matching a glob pattern is a file to +be included in the TEA extension but that could not be ascertained as such from +previous commands like critcl::csources and critcl::tsources, +either because of they were specified dynamically or because they were directly +sourced.

+
::critcl::cflags ?arg...?
+

Each arg is an argument to the compiler.

+

Calls to this command are cumulative.

+
::critcl::ldflags ?arg...?
+

Each arg is an argument to the linker.

+

Calls to this command are cumulative.

+
::critcl::framework ?arg...?
+

Each arg is the name of a framework to link on MacOS X. This command is +ignored if OS X is not the target so that frameworks can be specified +unconditionally.

+

Calls to this command are cumulative.

+
::critcl::tcl version
+

Specifies the minimum version of the Tcl runtime +to compile and link the package for. The default is 8.4.

+
::critcl::tk
+

Arranges to include the Tk headers and link to the Tk stubs.

+
::critcl::preload lib...
+

Arranges for the external shared library lib to be loaded +before the shared library for the CriTcl script is loaded.

+

Calls to this command are cumulative.

+

Each library FOO is searched for in the directories listed below, in the order +listed. The search stops at the first existing path. +Additional notes:

+
    +
  • platform is the placeholder for the target platform of the package.

  • +
  • The extension ".so" is the placeholder for whatever actual extension is used by the target platform for its shared libraries.

  • +
  • The search is relative to the current working directory.

  • +
+

And now the paths, depending on the exact form of the library name:

+
+
FOO
+
    +
  1. FOO.so

  2. +
  3. FOO/FOO.so

  4. +
  5. FOO/platform/FOO.so

  6. +
+
PATH/FOO
+

The exact set searched depends on the existence of +directory "PATH/FOO". If it exists, critcl searches

+
    +
  1. FOO.so

  2. +
  3. PATH/FOO/FOO.so

  4. +
  5. PATH/FOO/platform/FOO.so

  6. +
+

Otherwise it searches

+
    +
  1. FOO.so

  2. +
  3. PATH/FOO.so

  4. +
  5. PATH/platform/FOO.so

  6. +
+

instead.

+
/PATH/FOO
+

Even when specifying FOO with an absolute path the first path searched +is relative to the current working directory.

+
    +
  1. FOO.so

  2. +
  3. /PATH/FOO.so

  4. +
  5. /PATH/platform/FOO.so

  6. +
+
+

For developers who want to understand or modify the internals of the +critcl package, Preloading functionality explains how +preloading is implemented.

+
::critcl::debug area...
+

Specifies what debugging features to activate. Internally each area is translated into +area-specific flags for the compiler which are then handed over to +critcl::cflags.

+
+
memory
+

Specifies Tcl memory debugging.

+
symbols
+

Specifies compilation and linking with debugging symbols for use by a debugger +or other tool.

+
all
+

Specifies all available debugging.

+
+
+
+

Introspection

+

The following commands control compilation and linking.

+
+
::critcl::check ?label? text
+

Returns a true if the C code in text compiles sucessfully, and +false otherwise. Used to check for availability of features in the +build environment. +If provided, label is used to uniquely mark the results in the generated +log.

+
::critcl::checklink ?label? text
+

Like critcl::check but also links the compiled objects, returning +true if the link is successful and false otherwise. +If specified, label is used to uniquely mark the results in the generated +log.

+
::critcl::msg ?-nonewline? msg
+

Scripts using critcl::check and critcl::checklink can use this +command to report results. Does nothing in compile & run mode. Tools +like the CriTcl Aplication may redefine this command to implement +their own message reporting. For example, critcl::app and any +packages built on it print messages to stdout.

+
::critcl::print ?-nonewline? ?chan? msg
+

Used by the CriTcl internals to report activity. By default, effectively the +same thing as ::puts. Tools directly using either the CriTcl package or +the CriTcl application package may redefine this procedure to implement their +own output functionality.

+

For example, the newest revisions of +Kettle +use this to highlight build warnings.

+
::critcl::compiled
+

Returns true if the current CriTcl script is already compiled +and false otherwise.

+

Enables a CriTcl script used as its own Tcl companion file (see +critcl::tsources) to distinguish between being sourced for compilation in +compile & run mode and being sourced from either the result of +generate package mode or during the load phase of +compile & run mode. +The result is false in the first case and true in the later two +cases.

+
::critcl::compiling
+

Returns true if a working C compiler is available and false +otherwise.

+
::critcl::done
+

Returns true when CriTcl script has been built and +false otherwise. Only useful from within a CriTcl script. +Enables the Tcl parts of a CriTcl script to distinguish between +prebuilt package mode and compile & run mode.

+

See also Modes Of Operation/Use.

+
::critcl::failed
+

Returns true if the CriTcl script could not be built, and +false otherwise. Forces the building of the package if it hasn't +already been done, but not its loading. Thus, a CriTcl script can +check itself for availability of the compiled components. Only useful from +within a CriTcl script.

+
::critcl::load
+

Like critcl::failed except that it also forces the loading of the +generated shared library, and that it returns true on success and +false on failure. Thus, a CriTcl script can check itself for +availability of the compiled components. Only useful from within a +CriTcl script.

+
+
+

Build Management

+

The following command manages global settings, i.e. configuration options which +are independent of any CriTcl script.

+

This command should not be needed to write a CriTcl script. It is +a management command which is only useful to the CriTcl Application +or similar tools.

+
+
::critcl::config option ?val?
+

Sets and returns the following global configuration options:

+
+
force bool
+

When false (the default), the C files are not built if there is a +cached shared library.

+
lines bool
+

When true (the default), #line directives are embedded into the +generated C code.

+

This facility requires the use of a tclsh that provides +info frame. Otherwise, no #line directives are emitted. The +command is supported by Tcl 8.5 and higher. It is also supported by +Tcl 8.4 provided that it was compiled with the define +-DTCL_TIP280. An example of such is ActiveState's ActiveTcl.

+

Developers of higher-level packages generating their own C +code, either directly or indirectly through critcl, should +also read section Advanced: Location management to see how +critcl helps them in generating their directives. +Examples of such packages come with critcl itself. See +critcl::iassoc and critcl::class.

+
trace bool
+

When false (the default), no code tracing the entry and exit of +CriTcl-backed commands in the CriTcl script is inserted. Insertion of +such code implicitly activates the tracing facility in general. See +critcl::cutil.

+
I path
+

A single global include path to use for all files. Not set by default.

+
combine enum
+
+
dynamic (the default)
+

Object files have the suffix _pic.

+
static
+

Object files have the suffix _stub.

+
standalone
+

Object files have no suffix, and the generated C files are compiled +without using Tcl/Tk stubs. The result are object files usable for +static linking into a big shell.

+
+
language string
+
+
keepsrc bool
+

When false (the default), the generated ".c" +files are deleted after the ".o" files have been built.

+
outdir directory
+

The directory where to place a generated shared library. By default, it is +placed into the Result Cache.

+
+
+
+

Result Cache Management

+

The following commands control the Result Cache. +These commands are not needed to simply write a CriTcl script.

+
+
::critcl::cache ?path?
+

Sets and returns the path to the directory for the package's result cache.

+

The default location is +"~/.critcl/[platform::generic]" and usually does not +require any changes.

+
::critcl::clean_cache ?pattern...?
+

Cleans the result cache, i.e. removes any and all files +and directories in it. If one or more patterns are specified then only +the files and directories matching them are removed.

+
+
+

Build Configuration

+

The following commands manage the build configuration, i.e. the per-platform +information about compilers, linkers, and their commandline options. +These commands are not needed to simply write a CriTcl script.

+
+
::critcl::readconfig path
+

Reads the build configuration file at path and configures the package +using the information for the target platform.

+
::critcl::showconfig ?chan?
+

Converts the active build configuration into a human-readable string and +returns it, or if chan is provided prints the result to that channel.

+
::critcl::showallconfig ?chan?
+

Converts the set of all known build configurations from the currently active +build configuration file last set with critcl::readconfig into a string +and returns it, or if chan is provided, prints it to that channel.

+
::critcl::chooseconfig target ?nomatcherr?
+

Matches target against all known targets, returning a list containing +all the matching ones. This search is first done on an exact basis, and then +via glob matching. If no known target matches the argument the default is to +return an empty list. However, if the boolean nomatcherr is specified and +set an error is thrown using critcl::error instead.

+
::critcl::setconfig target
+

Configures the package to use the settings of target.

+
+
+

Tool API

+

The following commands provide tools like +CriTcl Application or similar with +deeper access to the package's internals. +These commands are not needed to simply write a CriTcl script.

+
+
::critcl::actualtarget
+

Returns the platform identifier for the target platform, i.e. the platform to +build for. Unlike ::critcl::targetplatform this is the true target, with +any cross-compilation information resolved.

+
::critcl::buildforpackage ?flag?
+

Signals whether the next file is to be built for inclusion into a package. If +not specified the flag defaults to true, i.e. building for a +package. This disables a number of things in the backend, namely the linking of +that file into a shared library and the loading of that library. It is expected +that the build results are later wrapped into a larger collection.

+
::critcl::cnothingtodo file
+

Checks whether there is anything to build for file.

+
::critcl::cresults ?file?
+

Returns information about building file, or info script If +file is not provided. +The result in question is a dictionary containing the following items:

+
+
clibraries
+

A list of external shared libraries and/or directories needed to link +file.

+
ldflags
+

A list of linker flags needed to link file.

+
license
+

The text of the license for the package file is located in.

+
mintcl
+

The minimum version of Tcl required by the package file +is in to run successfully. A proper Tcl version number.

+
objects
+

A list of object files to link into file.

+
preload
+

A list of libraries to be preloaded in order to sucessfully load and use +file.

+
tk
+

true if file requires Tk and false otherwise.

+
tsources
+

A list of companion ".tcl" files to source in order to load and use the +CriTcl script file.

+
log
+

The full build log generated by the compiler/linker, including command +line data from critcl, and other things.

+
exl
+

The raw build log generated by the compiler/linker. Contains the output +generated by the invoked applications.

+
+
::critcl::crosscheck
+

Determines whether the package is configured for cross-compilation and prints a +message to the standard error channel if so.

+
::critcl::error msg
+

Used to report internal errors. The default implementation simply returns the +error. Tools like the CriTcl Application are allowed to redefine +this procedure to perform their own way of error reporting. There is +one constraint they are not allowed to change: The procedure must +not return to the caller.

+
::critcl::knowntargets
+

Returns a list of the identifiers of all targets +found during the last invocation of critcl::readconfig.

+
::critcl::sharedlibext
+

Returns the file extension for shared libraries on the target platform.

+
::critcl::targetconfig
+

Returns the identifier of the target to build for, as specified by either the +user or the system.

+
::critcl::buildplatform
+

Returns the identifier of the build platform, i.e. where the package is running +on.

+
::critcl::targetplatform
+

Returns the identifier of the target platform, +i.e. the platform to compile for. In contrast to +::critcl::actualtarget this may be the name of a +cross-compilation target.

+
::critcl::cobjects ?glob pattern...?
+

Like ::critcl::clibraries, but instead of matching libraries, each +glob pattern matches object files to be linked into the +shared object (at compile time, not runtime). If a glob pattern matches +nothing an error is returned. +Not listed in Control & Interface because it is of no use to +package writers. Only tools like the CriTcl Application need it.

+

A pattern for a relative path is resolved relative to the directory +containing the CriTcl script.

+

Calls to this command are cumulative.

+
::critcl::scan path
+

The main entry point to CriTcl's static code scanner. Used by tools to +implement processing modes like the assembly of a directory hierarchy +containing a TEA-lookalike buildystem, etc.

+

Scans path and returns a dictionary containing the following items:

+
+
version
+

Package version.

+
org
+

Author(ing organization).

+
files
+

List of the companion files, relative to the directory of the input +file.

+
+
::critcl::name2c name
+

Given the Tcl-level identifier name, returns a list containing the +following details of its conversion to C:

+
    +
  • Tcl namespace prefix

  • +
  • C namespace prefix

  • +
  • Tcl base name

  • +
  • C base name

  • +
+

For use by utilities that provide Tcl commands without going through +standard commands like critcl::ccommand or critcl::cproc. +critcl::class does this.

+
+
+

Advanced: Embedded C Code

+

For advanced use, the following commands used by critcl::cproc itself are +exposed.

+
+
::critcl::argnames arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list of the corresponding user-visible names.

+
::critcl::argcnames arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list of the corresponding C variable names for the +user-visible names. The names returned here match the names used in the +declarations and code returned by ::critcl::argvardecls and +::critcl::argconversion.

+
::critcl::argcsignature arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list of the corresponding C parameter declarations.

+
::critcl::argvardecls arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list of the corresponding C variable declarations. +The names used in these declarations match the names returned by +::critcl::argcnames.

+
::critcl::argconversion arguments ?n?
+

Given an argument declaration as documented for critcl::cproc, returns a list of C code fragments converting the user visible +arguments found in the declaration from Tcl_Obj* to C types. The names used in +these statements match the names returned by ::critcl::argcnames.

+

The generated code assumes that the procedure arguments start +at index n of the objv array. The default is 1.

+
::critcl::argoptional arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list of boolean values indicating which arguments +are optional (true), and which are not (false).

+
::critcl::argdefaults arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list containing the default values for all optional +arguments.

+
::critcl::argsupport arguments
+

Given an argument declaration as documented for critcl::cproc, returns a list of C code fragments needed to define the +necessary supporting types.

+
+
+

Custom Build Configuration

+

This package provides one command for the management of +package-specific, i.e. developer-specified custom build configuration +options.

+
+
::critcl::userconfig define name description type ?default?
+

This command defines custom build configuration option, with +description, type and optional default value.

+

The type can be either bool, or a list of values.

+
    +
  1. For bool the default value, if specified, must be a +boolean. If it is not specified it defaults to true.

  2. +
  3. For a list of values the default value, if specified, must be a +value found in this list. If it is not specified it defaults to the +first value of the list.

  4. +
+

The description serves as in-code documentation of the +meaning of the option and is otherwise ignored. When generating a TEA +wrapper the description is used for the configure option +derived from the option declared by the command.

+

A boolean option FOO are translated into a pair of +configure options, --enable-FOO and +--disable-FOO, whereas an option whose type is a +list of values is translated into a single configure option +--with-FOO.

+
::critcl::userconfig query name
+

This command queries the database of custom build configuration option +for the current ".critcl" file and returns the chosen value. +This may be the default if no value was set via +::critcl::userconfig set.

+

It is at this point that definitions and set values are brought +together, with the latter validated against the definition.

+
::critcl::userconfig set name value
+

This command is for use by a tool, like the critcl application, +to specify values for custom build configuration options.

+

At the time this command is used only the association between +option name and value is recorded, and nothing else is done. This +behaviour is necessary as the system may not know if an option of the +specified name exists when the command is invoked, nor its type.

+

Any and all validation is defered to when the value of an +option is asked for via ::critcl::userconfig query.

+

This means that it is possible to set values for any option we +like, and the value will take effect only if such an option is both +defined and used later on.

+
+
+

Advanced: Location management

+

First a small introduction for whose asking themselves +'what is location management' ?

+

By default critcl embeds #line directives into the +generated C code so that any errors, warnings and notes found by the C +compiler during compilation will refer to the ".critcl" file the +faulty code comes from, instead of the generated ".c" file.

+

This facility requires the use of a tclsh that provides +info frame. Otherwise, no #line directives are emitted. The +command is supported by Tcl 8.5 and higher. It is also supported by +Tcl 8.4 provided that it was compiled with the define +-DTCL_TIP280. An example of such is ActiveState's ActiveTcl.

+

Most users will not care about this feature beyond simply +wanting it to work and getting proper code references when reading +compiler output.

+

Developers of higher-level packages generating their own C code +however should care about this, to ensure that their generated code +contains proper references as well. Especially as this is key to +separating bugs concerning code generated by the package itself and +bug in the user's code going into the package, if any.

+

Examples of such packages come with critcl itself, see the +implementation of packages critcl::iassoc and +critcl::class.

+

To help such developers eight commands are provided to manage +such location information. These are listed below.

+

A main concept is that they all operate on a single +stored location, setting, returning and clearing it. +Note that this location information is completely independent of the +generation of #line directives within critcl itself.

+
+
::critcl::at::caller
+

This command stores the location of the caller of the current +procedure as a tuple of file name and linenumber. Any previously +stored location is overwritten. +The result of the command is the empty string.

+
::critcl::at::caller offset
+

As above, the stored line number is modified by the specified +offset. In essence an implicit call of critcl::at::incr.

+
::critcl::at::caller offset level
+

As above, but the level the location information is taken from is +modified as well. Level 0 is the caller, -1 its +caller, etc.

+
::critcl::at::here
+

This command stores the current location in the current procedure as a +tuple of file name and linenumber. Any previously stored location is +overwritten. +The result of the command is the empty string.

+

In terms of ::critcl::at::caller this is equivalent to

+
+	critcl::at::caller 0 1
+
+
+
::critcl::at::get*
+

This command takes the stored location and returns a formatted +#line directive ready for embedding into some C code. The +stored location is left untouched. +Note that the directive contains its own closing newline.

+

For proper nesting and use it is recommended that such +directives are always added to the beginning of a code fragment. This +way, should deeper layers add their own directives these will come +before ours and thus be inactive. End result is that the outermost +layer generating a directive will 'win', i.e. have its directive +used. As it should be.

+
::critcl::at::get
+

This command is like the above, except that it also clears the stored +location.

+
::critcl::at::= file line
+

This command allows the caller to set the stored location to anything +they want, outside of critcl's control. +The result of the command is the empty string.

+
::critcl::at::incr n...
+
+
::critcl::at::incrt str...
+

These commands allow the user to modify the line number of the stored +location, changing it incrementally. The increment is specified as +either a series of integer numbers (incr), or a series of +strings to consider (incrt). In case of the latter the delta is +the number of lines endings found in the strings.

+
::critcl::at::caller!
+
+
::critcl::at::caller! offset
+
+
::critcl::at::caller! offset level
+
+
::critcl::at::here!
+

These are convenience commands combining caller and here +with get. I.e. they store the location and immediately return it +formatted as proper #line directive. Also note that after their +use the stored location is cleared.

+
+
+

Advanced: Diversions

+

Diversions are for higher-level packages generating their own C code, +to make their use of critcl's commands generating +Embedded C Code easier.

+

These commands normally generate all of their C code for the +current ".critcl" file, which may not be what is wanted by a +higher-level package.

+

With a diversion the generator output can be redirected into +memory and from there on then handled and processed as the caller +desires before it is committed to an actual ".c" file.

+

An example of such a package comes with critcl itself, see the +implementation of package critcl::class.

+

To help such developers three commands are provided to manage +diversions and the collection of C code in memory. These are:

+
+
::critcl::collect_begin
+

This command starts the diversion of C code collection into memory.

+

The result of the command is the empty string.

+

Multiple calls are allowed, with each call opening a new +nesting level of diversion.

+
::critcl::collect_end
+

This command end the diversion of C code collection into memory and +returns the collected C code.

+

If multiple levels of diversion are open the call only closes +and returns the data from the last level.

+

The command will throw an error if no diversion is active, +indicating a mismatch in the pairing of collect_begin and +collect_end.

+
::critcl::collect script
+

This is a convenience command which runs the script under +diversion and returns the collected C code, ensuring the correct +pairing of collect_begin and collect_end.

+
+
+

Advanced: File Generation

+

While file generation is related to the diversions explained in the +previous section they are not the same. +Even so, like diversions this feature is for higher-level packages +generating their own C code.

+

Three examples of utility packages using this facility comes +with critcl itself. +See the implementations of packages critcl::literals, +critcl::bitmap, and critcl::enum.

+

When splitting a package implementation into pieces it is often +sensible to have a number of pure C companion files containing +low-level code, yet these files may require information about the code +in the main ".critcl" file. Such declarations are normally not +exportable and using the stub table support does not make sense, as +this is completely internal to the package.

+

With the file generation command below the main ".critcl" +file can generate any number of header files for the C companions to +pick up.

+
+
::critcl::make path contents
+

This command creates the file path in a location where the C +companion files of the package are able to pick it up by simple +inclusion of path during their compilation, without interfering +with the outer system at all.

+

The generated file will contain the specified contents.

+
+
+
+

Concepts

+

Modes Of Operation/Use

+

CriTcl can be used in three different modes of operation, called

+
    +
  1. Compile & Run, and

  2. +
  3. Generate Package

  4. +
  5. Generate TEA Package

  6. +
+

Compile & Run was the original mode and is the default for +critcl_pkg. Collects the C fragments from the +CriTcl script, builds them as needed, and caches the results to +improve load times later.

+

The second mode, Generate Package, was introduced to enable +the creation of (prebuilt) deliverable packages which do not depend on +the existence of a build system, i.e. C compiler, on the target +machine. +This was originally done through the experimental Critbind tool, +and is now handled by the CriTcl Application, also named +critcl.

+

Newly introduced with CriTcl version 3 is +Generate TEA Package. This mode constructs a directory +hierarchy from the package which can later be built like a regular TEA +package, i.e. using

+
+	.../configure --prefix ...
+	make all isntall
+
+

Regarding the caching of results please read the section about +the Result Cache fore more details.

+
+

Runtime Behaviour

+

The default behaviour of critcl, the package is to defer the +compilation, linking, and loading of any C code as much as possible, +given that this is an expensive operation, mainly in the time +required. +In other words, the C code embedded into a ".critcl" file is +built only when the first C command or procedure it provides is +invoked. +This part of the system uses standard functionality built into the Tcl +core, i.e. the auto_index variable to map from commands to +scripts providing them and the unknown command using this +information when the command is needed.

+

A limitation of this behaviour is that it is not +possible to just use info commands check for the existence of +a critcl defined command. It is also necessary to search in the +auto_index array, in case it has not been build yet.

+

This behaviour can be changed by using the control command +critcl::load. When invoked, the building, including loading of +the result, is forced. After this command has been invoked for a +".critcl" file further definition of C code in this file is not +allowed any longer.

+
+

File Mapping

+

Each ".critcl" file is backed by a single private ".c" file +containing that code, plus the boilerplate necessary for its +compilation and linking as a single shared library.

+

The Embedded C Code +fragments appear in that file in the exact same order they were +defined in the ".critcl" file, with one exception. The C code +provided via critcl::cinit is put after all other fragments. +In other words all fragments have access to the symbols defined by +earlier fragments, and the critcl::cinit fragment has access to +all, regardless of its placement in the ".critcl" file.

+

Note: A limitation of the current system is the near +impossibility of C level access between different critcl-based +packages. The issue is not the necessity of writing and sharing the +proper extern statements, but that the management (export and +import) of package-specific stubs-tables is not supported. This means +that dependent parts have to be forcibly loaded before their user, +with all that entails. See section Runtime Behaviour for +the relevant critcl limitation, and remember that many older platforms +do not support the necessary resolution of symbols, the reason why +stubs were invented for Tcl in the first place.

+
+

Result Cache

+

The compilation of C code is time-consuming critcl not only +defers it as much as possible, as described in section +Runtime Behaviour, but also caches the results.

+

This means that on the first use of a ".critcl" file +"FOO.tcl" the resulting object file and shared library are saved +into the cache, and on future uses of the same file reused, +i.e. loaded directly without requiring compilation, provided that the +contents of "FOO.tcl" did not change.

+

The change detection is based MD5 hashes. A single hash is +computed for each ".critcl" file, based on hashes for all C code +fragments and configuration options, i.e. everything which affects the +resulting binary.

+

As long as the input file doesn't change as per the hash a +previously built shared library found in the cache is reused, +bypassing the compilation and link stages.

+

The command to manage the cache are found in section +Result Cache Management. +Note however that they are useful only to tools based on the package, +like the CriTcl Application. Package writers have no need +of them.

+

As a last note, the default directory for the cache is chosen +based on the chosen build target. This means that the cache can be put +on a shared (network) filesystem without having to fear interference +between machines of different architectures.

+
+

Preloading functionality

+

The audience of this section are developers wishing to understand +and possibly modify the internals of critcl package and application. +Package writers can skip this section.

+

It explains how the preloading of external libraries is realized.

+

Whenever a package declares libraries for preloading critcl will build +a supporting shared library providing a Tcl package named "preload". +This package is not distributed separately, but as part of the package +requiring the preload functionality. +This support package exports a single Tcl command

+
+
::preload library
+

which is invoked once per libraries to preload, with the absolute path +of that library. The command then loads the library.

+

On windows the command will further use the Tcl command +::critcl::runtime::precopy to copy the library to the +disk, should its path be in a virtual filesystem which doesn't +directly support the loading of a shared library from it.

+
+

The command ::critcl::runtime::precopy is provided by the file +"critcl-rt.tcl" in the generated package, as is the command +::critcl::runtime::loadlib which generates the +ifneeded script expected by Tcl's package management. This +generated ifneeded script contains the invocations of ::preload.

+

The C code for the supporting library is found in the file +"critcl_c/preload.c", which is part of the critcl +package.

+

The Tcl code for the supporting runtime "critcl-rt.tcl" is found +in the file "runtime.tcl", which is part of the +critcl::app package.

+
+

Configuration Internals

+

The audience of this section are developers wishing to understand +and possibly modify the internals of critcl package and application. +Package writers can skip this section.

+

It explains the syntax of configuration files and the configuration +keys used by critcl to configure its build backend, i.e. how +this part of the system accesses compiler, linker, etc.

+

It is recommended to open the file containing the standard +configurations ("path/to/critcl/Config") in the editor of your +choice when reading this section of the documentation, using it as an +extended set of examples going beyond the simple defaults shown here.

+

First, the keys and the meaning of their values, plus examples drawn +from the standard configurations distributed with the package. +Note that when writing a custom configuration it is not necessary to +specify all the keys listed below, but only those whose default values +are wrong or insufficient for the platform in question.

+
+
version
+

The command to print the compiler version number. +Defaults to

+
 gcc -v 
+
+
compile
+

The command to compile a single C source file to an object file. +Defaults to

+
 gcc -c -fPIC 
+
+
debug_memory
+

The list of flags for the compiler to enable memory debugging in +Tcl. +Defaults to

+
 -DTCL_MEM_DEBUG 
+
+
debug_symbols
+

The list of flags for the compiler to add symbols to the object files +and the resulting library. +Defaults to

+
 -g 
+
+
include
+

The compiler flag to add an include directory. +Defaults to

+
 -I 
+
+
tclstubs
+

The compiler flag to set USE_TCL_STUBS. +Defaults to

+
 -DUSE_TCL_STUBS 
+
+
tkstubs
+

The compiler flag to set USE_TK_STUBS. +Defaults to

+
 -DUSE_TK_STUBS 
+
+
threadflags
+

The list of compiler flags to enable a threaded build. +Defaults to

+
+    -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1
+    -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_READDIR_R=1
+    -DTCL_THREADS=1
+
+

.

+
noassert
+

The compiler flag to turn off assertions in Tcl code. +Defaults to

+
 -DNDEBUG 
+
+
optimize
+

The compiler flag to specify optimization level. +Defaults to

+
 -O2 
+
+
output
+

The compiler flags to set the output file of a compilation. +Defaults to

+
 -o [list $outfile] 
+

NOTE the use of Tcl commands and variables here. At the +time critcl uses the value of this key the value of the +referenced variable is substituted into it. The named variable is the +only variable whose value is defined for this substitution.

+
object
+

The file extension for object files on the platform. +Defaults to

+
 .o 
+
+
preproc_define
+

The command to preprocess a C source file without compiling it, but +leaving #define's in the output. Defaults to

+
 gcc -E -dM 
+
+
preproc_enum
+

See preproc_define, except that #define's are not left in the +output. Defaults to

+
 gcc -E 
+
+
link
+

The command to link one or more object files and create a shared +library. Defaults to

+
 gcc -shared 
+
+
link_preload
+

The list of linker flags to use when dependent libraries are +pre-loaded. Defaults to

+
 --unresolved-symbols=ignore-in-shared-libs 
+
+
strip
+

The flag to tell the linker to strip symbols from the shared library. +Defaults to

+
 -Wl,-s 
+
+
ldoutput
+

Like output, but for the linker. +Defaults to the value of output.

+
link_debug
+

The list of linker flags needed to build a shared library with +symbols. Defaults to the empty string. +One platform requiring this are all variants of Windows, which uses

+
 -debug:full -debugtype:cv 
+
+
link_release
+

The list of linker flags needed to build a shared library without +symbols, i.e. a regular build. Defaults to the empty string. +One platform requiring this are all variants of Windows, which uses

+
 -release -opt:ref -opt:icf,3 -ws:aggressive 
+
+
sharedlibext
+

The file extension for shared library files on the platform. +Defaults to

+
 [info sharedlibextension] 
+
+
platform
+

The identifier of the platform used in generated packages. +Defaults to

+
 [platform::generic] 
+
+
target
+

The presence of this key marks the configuration as a +cross-compilation target and the value is the actual platform +identifier of the target. No default.

+
+

The syntax expected from configuration files is governed by the rules below. +Again, it is recommended to open the file containing the standard +configurations ("path/to/critcl/Config") in the editor of your +choice when reading this section of the documentation, using it as an +extended set of examples for the syntax>

+
    +
  1. Each logical line of the configuration file consists of one or +more physical lines. In case of the latter the physical lines have to +follow each other and all but the first must be marked by a trailing +backslash. This is the same marker for continuation lines as +used by Tcl itself.

  2. +
  3. A (logical) line starting with the character "#" (modulo +whitespace) is a comment which runs until the end of the line, and is +otherwise ignored.

  4. +
  5. A (logical) line starting with the word "if" (modulo +whitespace) is interpreted as Tcl's if command and executed as +such. I.e. this command has to follow Tcl's syntax for the command, +which may stretch across multiple logical lines. The command will be +run in a save interpreter.

  6. +
  7. A (logical) line starting with the word "set" (modulo +whitespace) is interpreted as Tcl's set command and executed as +such. I.e. this command has to follow Tcl's syntax for the command, +which may stretch across multiple logical lines. The command will be +run in a save interpreter.

  8. +
  9. A line of the form "platform variable value" +defines a platform specific configuration variable and value. +The variable has to be the name of one of the configuration keys +listed earlier in this section, and the platform string +identifies the platform the setting is for. All settings with the same +identification string form the configuration block for this +platform.

  10. +
  11. A line of the special form +"platform when expression" +marks the platform and all the settings in its +configuration block as conditional on the expression.

    +

    If the build platform is not a prefix of platform, +nor vice versa the whole block is ignored. +Otherwise the expression is evaluated via expr, in the +same safe interpreter used to run any set and if commands +found in the configuration file (see above).

    +

    If the expression evaluates to true this configuration block +is considered to be the build platform fo the host and chosen as the +default configuration. +An large example of of this feature is the handling of OS X found in +the standard configuration file, where it selects the architectures to +build based on the version of the operating system, the available SDK, +etc. I.e. it chooses whether the output is universal or not, and +whether it is old-style (ix86 + ppc) versus new-style (ix86 32+64) of +universality.

  12. +
  13. A line of the special form +"platform copy sourceplatform" +copies the configuration variables and values currently defined in the +configuration block for sourceplatform to that of +platform, overwriting existing values, and creating missing +ones. Variables of platform not defined by by sourceplatform +are not touched.

    +

    The copied values can be overridden later in the configuration +file. Multiple copy lines may exist for a platform and be +intermixed with normal configuration definitions. Only the last definition of a +variable is used.

  14. +
  15. At last, a line of the form "variable value" +defines a default configuration variable and value.

  16. +
+
+

Stubs Tables

+

This section is for developers of extensions not based on critcl, yet +also wishing to interface with stubs as they are understood and used +by critcl, either by exporting their own stubs table to a +critcl-based extension, or importing a stubs table of a critcl-based +extension into their own.

+

To this end we describe the stubs table information of a +package foo.

+
    +
  1. Note that the differences in the capitalization of "foo", +"Foo", "FOO", etc. below demonstrate how to capitalize the actual +package name in each context.

  2. +
  3. All relevant files must be available in a sub-directory +"foo" which can be found on the include search paths.

  4. +
  5. The above directory may contain a file "foo.decls". If + present it is assumed to contain the external representation + of the stubs table the headers mentioned in the following + items are based on.

    +

    critcl is able to use such a file to give the importing package + programmatic access to the imported API, for automatic code + generation and the like.

  6. +
  7. The above directory must contain a header file +"fooDecls.h". This file declares the exported API. +It is used by both exporting and importing packages. It is usually +generated and must contain (in the order specified):

    +
      +
    1. the declarations of the exported, i.e. public, functions of + foo,

    2. +
    3. the declaration of structure "FooStubs" for the stub table,

    4. +
    5. the C preprocessor macros which route the invocations of the + public functions through the stubs table.

      +

      These macros must be defined if, and only if, the C preprocessor + macro USE_FOO_STUBS is defined. Package foo does not + define this macro, as it is allowed to use the exported + functions directly. All importing packages however must define + this macro, to ensure that they do not use any of the + exported functions directly, but only through the stubs table.

    6. +
    7. If the exported functions need additional types for their proper + declaration then these types should be put into a separate + header file (of arbitrary name) and "fooDecls.h" should + contain an #include directive to this header at the top.

    8. +
    +

    A very reduced, yet also complete example, from a package for +low-level random number generator functions can be found at the end of +this section.

  8. +
  9. The above directory must contain a header file +"fooStubLib.h". This file defines everything needed to use +the API of foo. Consequently it is used only by importing +packages. It is usually generated and must contain (in the order +specified):

    +
      +
    1. An #include directive for "tcl.h", with USE_TCL_STUBS + surely defined.

    2. +
    3. An #include directive for "fooDecls.h", with USE_FOO_STUBS + surely defined.

    4. +
    5. A definition of the stubs table variable, i.e.

      +
      const FooStubs* fooStubsPtr;
      +
    6. +
    7. A definition of the stubs initializer function, like

      +
      char *
      +Foo_InitStubs(Tcl_Interp *interp, CONST char *version, int exact)
      +{
      +    /*
      +     * Boiler plate C code initalizing the stubs table variable,
      +     * i.e. "fooStubsPtr".
      +     */
      +    CONST char *actualVersion;
      +    actualVersion = Tcl_PkgRequireEx(interp, "foo", version,
      +				     exact, (ClientData *) &fooStubsPtr);
      +    if (!actualVersion) {
      +	return NULL;
      +    }
      +    if (!fooStubsPtr) {
      +	Tcl_SetResult(interp,
      +		      "This implementation of Foo does not support stubs",
      +		      TCL_STATIC);
      +	return NULL;
      +    }
      +    return (char*) actualVersion;
      +}
      +
    8. +
    +

    This header file must be included by an importing package +exactly once, so that it contains only one definition of both +stubs table and stubs initializer function.

    +

    The importing package's initialization function must further +contain a statement like

    +
    if (!Foo_InitStubs (ip, "1", 0)) {
    +    return TCL_ERROR;
    +}
    +

    which invokes foo's stubs initializer function to set the +local stub table up.

    +

    For a complete example of such a header file see below, at the +end of this section.

  10. +
  11. The last item above, about "fooStubLib.h" differs + from the regular stub stable system used by Tcl. The regular + system assumes that a static library "libfoostub.a" was + installed by package foo, and links it.

    +

    IMVHO critcl's approach is simpler, using only header + files found in a single location, vs. header files and static + library found in multiple, different locations.

    +

    A second simplification is that we avoid having to extend + critcl's compiler backend with settings for the creation of + static libraries.

  12. +
+

Below is a complete set of example header files, reduced, yet still +complete, from a package for low-level random number generator +functions:

+
+
"rngDecls.h":
+
+
+#ifndef rng_DECLS_H
+#define rng_DECLS_H
+#include <tcl.h>
+/*
+ * Exported function declarations:
+ */
+/* 0 */
+EXTERN void rng_bernoulli(double p, int*v);
+typedef struct RngStubs {
+    int magic;
+    const struct RngStubHooks *hooks;
+    void (*rng_bernoulli) (double p, int*v); /* 0 */
+} RngStubs;
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern const RngStubs *rngStubsPtr;
+#ifdef __cplusplus
+}
+#endif
+#if defined(USE_RNG_STUBS)
+/*
+ * Inline function declarations:
+ */
+#define rng_bernoulli  (rngStubsPtr->rng_bernoulli) /* 0 */
+#endif /* defined(USE_RNG_STUBS) */
+#endif /* rng_DECLS_H */
+
+
+
"rngStubLib.h":
+
+
+/*
+ * rngStubLib.c --
+ *
+ * Stub object that will be statically linked into extensions that wish
+ * to access rng.
+ */
+#ifndef USE_TCL_STUBS
+#define USE_TCL_STUBS
+#endif
+#undef  USE_TCL_STUB_PROCS
+#include <tcl.h>
+#ifndef USE_RNG_STUBS
+#define USE_RNG_STUBS
+#endif
+#undef  USE_RNG_STUB_PROCS
+#include "rngDecls.h"
+/*
+ * Ensure that Rng_InitStubs is built as an exported symbol.  The other stub
+ * functions should be built as non-exported symbols.
+ */
+#undef  TCL_STORAGE_CLASS
+#define TCL_STORAGE_CLASS DLLEXPORT
+const RngStubs* rngStubsPtr;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rng_InitStubs --
+ *
+ * Checks that the correct version of Rng is loaded and that it
+ * supports stubs. It then initialises the stub table pointers.
+ *
+ * Results:
+ *  The actual version of Rng that satisfies the request, or
+ *  NULL to indicate that an error occurred.
+ *
+ * Side effects:
+ *  Sets the stub table pointers.
+ *
+ *----------------------------------------------------------------------
+ */
+#ifdef Rng_InitStubs
+#undef Rng_InitStubs
+#endif
+char *
+Rng_InitStubs(Tcl_Interp *interp, CONST char *version, int exact)
+{
+    CONST char *actualVersion;
+    actualVersion = Tcl_PkgRequireEx(interp, "rng", version,
+				     exact, (ClientData *) &rngStubsPtr);
+    if (!actualVersion) {
+	return NULL;
+    }
+    if (!rngStubsPtr) {
+	Tcl_SetResult(interp,
+		      "This implementation of Rng does not support stubs",
+		      TCL_STATIC);
+	return NULL;
+    }
+    return (char*) actualVersion;
+}
+
+
+
+
+
+

Examples

+

See section "Embedding C" in Using CriTcl.

+
+

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_tcl9.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_tcl9.html new file mode 100644 index 00000000..a59ad776 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_tcl9.html @@ -0,0 +1,265 @@ + +critcl_tcl9 - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl_tcl9(n) 3.2.1 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl_tcl9 - How To Adapt Critcl Packages for Tcl 9

+
+ +

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This guide contains notes and actions to take by writers of CriTcl-based +packages to make their code workable for both Tcl 8.6 and 9.

+
    +
  1. Generally, if there is no interest in moving to Tcl 9, i.e. Tcl 8.[456] + are the only supported runtimes, then just keep using CriTcl 3.2.

    +

    The remainder of this document can be ignored.

  2. +
  3. Use CriTcl version 3.2.1 if, and only if + Tcl 9 support is wanted.

    +

    With some work this will then also provide backward compatibility with Tcl 8.6.

  4. +
  5. Header "tcl.h"

    +

    Replace any inclusion of Tcl's public "tcl.h" header file in the package's + C code with the inclusion of CriTcl's new header file "tclpre9compat.h".

    +

    This includes "tcl.h" and further provides a set of compatibility definitions + which make supporting both Tcl 8.6 and Tcl 9 in a single code base easier.

    +

    The following notes assume that this compatibility layer is in place.

  6. +
  7. critcl::tcl

    +

    Before CriTcl 3.2.1 a single default (8.4) was used for + the minimum Tcl version, to be overriden by an explicit critcl::tcl in the + package code.

    +

    Now the default is dynamic, based on the runtime version, i.e. + package provide Tcl, CriTcl is run with/on.

    +

    When running on Tcl 9 the new default is version 9, and 8.6 else. + Note how this other default was bumped up from 8.4.

    +

    As a consequence it is possible to

    +
      +
    1. Support just Tcl 8.4+, 8.5+, by having an explicit critcl::tcl 8.x in + the package code.

      +

      Remember however, it is better to simply stick with + CriTcl 3.2 for this.

    2. +
    3. Support just Tcl 9 by having an explicit critcl::tcl 9 in the package code.

    4. +
    5. Support both Tcl 8.6 and Tcl 9 (but not 8.4/8.5) by leaving critcl::tcl out of the code + and using the proper tclsh version to run CriTcl with.

    6. +
    +
  8. +
  9. Code checking

    +

    CriTcl 3.2.1 comes with a very basic set of code checks pointing + out places where compatibility might or will be an issue.

    +

    The implementation checks all inlined C code declared by critcl::ccode, + critcl::ccommand, critcl::cproc (and related/derived commands), as well + as the C companion files declared with critcl::csources.

    +

    It is very basic because it simply greps the code line by line for a number + of patterns and reports on their presence. The C code is not fully parsed. + The check can and will report pattern found in C code comments, for example.

    +

    The main patterns deal with functions affected by the change to Tcl_Size, + the removal of old-style interpreter state handling, and command creation.

    +

    A warning message is printed for all detections.

    +

    This is disabled for the Tcl_Size-related pattern if the line also matches + the pattern *OK tcl9*.

    +

    In this way all places in the code already handled can be marked and excluded + from the warnings.

    +
      +
    1. Interpreter State handling

      +

      Tcl 9 removed the type Tcl_SavedResult and its associated functions + Tcl_SaveResult, Tcl_RestoreResult, and Tcl_DiscardResult.

      +

      When a package uses this type and the related functions a rewrite is necessary.

      +

      With Tcl 9 use of type Tcl_InterpState and its functions + Tcl_SaveInterpState, Tcl_RestoreInterpState, and + Tcl_DiscardInterpState is now required.

      +

      As these were introduced with Tcl 8.5 the rewrite gives us compatibility with + Tcl 8.6 for free.

    2. +
    3. Tcl_Size

      +

      One of the main changes introduced with Tcl 9 is the breaking of the 2G barrier + for the number of bytes in a string, elements in a list, etc. + In a lot of interfaces int was replaced with Tcl_Size, which is + effectively ptrdiff_t behind the scenes.

      +

      The "tclpre9compat.h" header mentioned above provides a suitable definition + of Tcl_Size for 8.6, i.e. maps it to int. + This enables the package code to use Tcl_Size everywhere and still have it + work for both Tcl 8.6 and 9.

      +

      It is of course necessary to rewrite the package code to use Tcl_Size.

      +

      The checker reports all lines in the C code using a function whose signature + was changed to use Tcl_Size over int.

      +

      Note that it is necessary to manually check the package code for places where + a %d text formatting specification should be replaced with + TCL_SIZE_FMT.

      +

      I.e. all places where Tcl_Size values are formatted with printf-style + functions a formatting string

      +
      "... %d ..."
      +

      has to be replaced with

      +
      "... " TCL_SIZE_FMT " ..."
      +

      The macro TCL_SIZE_FMT is defined by Critcl's compatibility layer, as an + extension of the TCL_SIZE_MODIFIER macro which only contains the + formatting modifier to insert into a plain %d to handle Tcl_Size + values.

      +

      Note how the original formatting string is split into multiple strings. + The C compiler will fuse these back together into a single string.

    4. +
    5. Command creation.

      +

      This is technically a part of the Tcl_Size changes.

      +

      All places using Tcl_CreateObjCommand have to be rewritten to use + Tcl_CreateObjCommand2 instead, and the registered command functions + to use Tcl_Size for their objc argument.

      +

      The "tclpre9compat.h" header maps this back to the old function + when compilation is done against Tcl 8.6.

      +

      CriTcl does this itself for the commands created via critcl::ccommand, + critcl::cproc, and derived places (critcl::class).

    6. +
    7. TIP 494. This TIP adds three semantic constants wrapping -1 to Tcl 9 to + make the meaning of code clearer. As part of this it also casts the constant to the + proper type. They are:

      +
        +
      • TCL_IO_FAILURE

      • +
      • TCL_AUTO_LENGTH

      • +
      • TCL_INDEX_NONE

      • +
      +

      Critcl's compatibility layer provides the same constants to Tcl 8.6.

      +

      Critcl's new checker highlights places where TCL_AUTO_LENGTH is suitable.

      +

      Doing this for the other two constants looks to require deeper and proper parsing + of C code, which the checker does not do.

    8. +
    +
  10. +
+
+ +

Authors

+

Jean Claude Wippler, Steve Landers, Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report them at https://github.com/andreas-kupries/critcl/issues. +Ideas for enhancements you may have for either package, application, +and/or the documentation are also very welcome and should be reported +at https://github.com/andreas-kupries/critcl/issues as well.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/files/critcl_util.html b/src/vfs/critcl.vfs/embedded/www/files/critcl_util.html new file mode 100644 index 00000000..589c3336 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/files/critcl_util.html @@ -0,0 +1,202 @@ + +critcl::util - C Runtime In Tcl (CriTcl) + + + + + +
[ + Table Of Contents +| Keyword Index + ]
+
+

critcl::util(n) 1.2 doc "C Runtime In Tcl (CriTcl)"

+

Name

+

critcl::util - CriTcl - Utilities

+
+ +

Synopsis

+
+
    +
  • package require Tcl 8.6
  • +
  • package require critcl ?3.2?
  • +
  • package require critcl::util ?1.2?
  • +
+ +
+
+

Description

+

Be welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C +code from within Tcl scripts.

+

This document is the reference manpage for the critcl::util +package. This package provides convenience commands for advanced +functionality built on top of the core. +Its intended audience are mainly developers wishing to write Tcl +packages with embedded C code.

+

This package resides in the Core Package Layer of CriTcl.

+

arch_core

+
+

API

+
+
::critcl::util::checkfun name ?label?
+

This command checks the build-time environment for the existence of +the C function name. +It returns true on success, and false otherwise.

+
::critcl::util::def path define ?value?
+

This command extends the specified configuration file path with a +#define directive for the named define. If the value +is not specified it will default to 1.

+

The result of the command is an empty string.

+

Note that the configuration file is maintained in the critcl::cache +directory.

+
::critcl::util::undef path define
+

This command extends the specified configuration file path with an +#undef directive for the named define.

+

The result of the command is an empty string.

+

Note that the configuration file is maintained in the critcl::cache +directory.

+
::critcl::util::locate label paths ?cmd?
+

This command checks the build-time environment for the existence of a file +in a set of possible paths.

+

If the option cmd prefix is specified it will be called with +the full path of a found file as its only argument to perform further checks. +A return value of false will reject the path and continue the search.

+

The return value of the command is the found path, as listed in +paths. As a side effect the command will also print the found path, +prefixed with the label, using critcl::msg.

+

Failure to find the path is reported via critcl::error, and a +possible empty string as the result, if critcl::error does not +terminate execution. +A relative path is resolved relative to the directory +containing the CriTcl script.

+
+
+

Authors

+

Andreas Kupries

+
+

Bugs, Ideas, Feedback

+

This document, and the package it describes, will undoubtedly contain +bugs and other problems. +Please report such at https://github.com/andreas-kupries/critcl. +Please also report any ideas for enhancements you may have for either +package and/or documentation.

+
+ +

Category

+

Glueing/Embedded C code

+
+ +
diff --git a/src/vfs/critcl.vfs/embedded/www/image/arch_application.png b/src/vfs/critcl.vfs/embedded/www/image/arch_application.png new file mode 100644 index 00000000..2f732c83 Binary files /dev/null and b/src/vfs/critcl.vfs/embedded/www/image/arch_application.png differ diff --git a/src/vfs/critcl.vfs/embedded/www/image/arch_core.png b/src/vfs/critcl.vfs/embedded/www/image/arch_core.png new file mode 100644 index 00000000..4ae56a7d Binary files /dev/null and b/src/vfs/critcl.vfs/embedded/www/image/arch_core.png differ diff --git a/src/vfs/critcl.vfs/embedded/www/image/arch_support.png b/src/vfs/critcl.vfs/embedded/www/image/arch_support.png new file mode 100644 index 00000000..bee761f2 Binary files /dev/null and b/src/vfs/critcl.vfs/embedded/www/image/arch_support.png differ diff --git a/src/vfs/critcl.vfs/embedded/www/image/architecture.png b/src/vfs/critcl.vfs/embedded/www/image/architecture.png new file mode 100644 index 00000000..dacfeb47 Binary files /dev/null and b/src/vfs/critcl.vfs/embedded/www/image/architecture.png differ diff --git a/src/vfs/critcl.vfs/embedded/www/index.html b/src/vfs/critcl.vfs/embedded/www/index.html new file mode 100644 index 00000000..2408ac2b --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/index.html @@ -0,0 +1,178 @@ + + + + + + Keyword Index + + +
[ + Table Of Contents + ]
+

Keyword Index -- doc

+
+ B · C · D · E · F · G · I · L · O · S · T +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Keywords: B +
bitmask + critcl::bitmap · critcl::emap +
bitset + critcl::bitmap · critcl::emap +
+Keywords: C +
C class + critcl::class +
C code + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
C instance + critcl::class +
C object + critcl::class +
calling C code from Tcl + critcl · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
code generator + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
compile & run + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
compiler + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
conversion + critcl::enum +
+Keywords: D +
dynamic code generation + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
dynamic compilation + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
+Keywords: E +
Embedded C Code + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
+Keywords: F +
flags + critcl::bitmap · critcl::emap +
+Keywords: G +
generate package + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
+Keywords: I +
int to string mapping + critcl::enum +
+Keywords: L +
linker + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
literal pool + critcl::enum · critcl::literals +
+Keywords: O +
on demand compilation + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
on-the-fly compilation + critcl · critcl::bitmap · critcl::callback · critcl::class · critcl::cutil · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals · critcl::util · critcl_application · critcl_application_package · critcl_build_tool · critcl_changes · critcl_cproc_types · critcl_devguide · critcl_howto_install · critcl_howto_sources · critcl_howto_use · critcl_license · critcl_package · critcl_tcl9 +
+Keywords: S +
singleton + critcl::bitmap · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals +
string pool + critcl::enum · critcl::literals +
string to int mapping + critcl::enum +
+Keywords: T +
Tcl Interp Association + critcl::bitmap · critcl::emap · critcl::enum · critcl::iassoc · critcl::literals +
+ \ No newline at end of file diff --git a/src/vfs/critcl.vfs/embedded/www/toc.html b/src/vfs/critcl.vfs/embedded/www/toc.html new file mode 100644 index 00000000..12fbaf52 --- /dev/null +++ b/src/vfs/critcl.vfs/embedded/www/toc.html @@ -0,0 +1,104 @@ + + Table Of Contents + + + + +
[ + Keyword Index + ]
+

Table Of Contents

+

doc

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
critclIntroduction To CriTcl
critcl::bitmapCriTcl - Wrap Support - Bitset en- and decoding
critcl::callbackCriTcl - C-level Callback Utilities
critcl::classCriTcl - Code Gen - C Classes
critcl::cutilCriTcl - C-level Utilities
critcl::emapCriTcl - Wrap Support - Enum en- and decoding
critcl::enumCriTcl - Wrap Support - String/Integer mapping
critcl::iassocCriTcl - Code Gen - Tcl Interp Associations
critcl::literalsCriTcl - Code Gen - Constant string pools
critcl::utilCriTcl - Utilities
critcl_applicationCriTcl Application Reference
critcl_application_packageCriTcl Application Package Reference
critcl_build_toolCriTcl build.tcl Tool Reference
critcl_changesCriTcl Releases & Changes
critcl_cproc_typesCriTcl cproc Type Reference
critcl_devguideGuide To The CriTcl Internals
critcl_howto_installHow To Install CriTcl
critcl_howto_sourcesHow To Get The CriTcl Sources
critcl_howto_useHow To Use CriTcl
critcl_licenseThe CriTcl License
critcl_packageCriTcl Package Reference
critcl_tcl9How To Adapt Critcl Packages for Tcl 9
+

diff --git a/src/vfs/critcl.vfs/examples/argtype/build.tcl b/src/vfs/critcl.vfs/examples/argtype/build.tcl new file mode 100644 index 00000000..4f20b9da --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtype/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {clist} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug build of package.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/argtype/cr.tcl b/src/vfs/critcl.vfs/examples/argtype/cr.tcl new file mode 100644 index 00000000..1a836479 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtype/cr.tcl @@ -0,0 +1,47 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "here: [pwd]" +puts "sourced: [file normalize ../../lib/critcl/critcl.tcl]" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/argtype/example.tcl b/src/vfs/critcl.vfs/examples/argtype/example.tcl new file mode 100644 index 00000000..564142c4 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtype/example.tcl @@ -0,0 +1,4 @@ +package require Tcl 8.6 + +ex critcl::ArgumentConversion {int > 0} +ex critcl::ArgumentConversion {double <= 0} diff --git a/src/vfs/critcl.vfs/examples/argtypes-ingress/build.tcl b/src/vfs/critcl.vfs/examples/argtypes-ingress/build.tcl new file mode 100644 index 00000000..05c87e96 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtypes-ingress/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {variadic} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/argtypes-ingress/cr.tcl b/src/vfs/critcl.vfs/examples/argtypes-ingress/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtypes-ingress/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/argtypes-ingress/example.tcl b/src/vfs/critcl.vfs/examples/argtypes-ingress/example.tcl new file mode 100644 index 00000000..10f28300 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtypes-ingress/example.tcl @@ -0,0 +1,39 @@ +#!/usr/bin/env tclsh + +package require Tcl 8.6 +package require ingress + +# Main point is checking that all the conversions of all +# (non-deprecated) builtin argument types generate code which compiles +# without errors or even warnings. +# +# The command names match the type names. + +ex boolean true +ex int 0 +ex long 0 +ex wideint 0 + +ex double 0 +ex float 0 + +ex char* string ;# const!? +ex pstring pstring +ex bytes bytearray + +ex bytearray bytearray ;# deprecated + +ex Tcl_Obj* an-object +ex list {a list} + +ex channel stdout + +foreach t {int long wideint double float} { + foreach {r v} { + {> 0} 1 {>= 0} 0 {> 1} 2 {>= 1} 1 + {< 0} -1 {<= 0} 0 {< 1} 0 {<= 1} 1 + } { + set type "$t $r" + ex $type $v + } +} diff --git a/src/vfs/critcl.vfs/examples/argtypes-ingress/ingress.tcl b/src/vfs/critcl.vfs/examples/argtypes-ingress/ingress.tcl new file mode 100644 index 00000000..a3f86f83 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/argtypes-ingress/ingress.tcl @@ -0,0 +1,60 @@ +# ingress.tcl -- +# +# A template demonstrating the handling of all (non-deprecated) +# argument types to cproc. +# +# Copyright (c) 2020,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +critcl::config keepsrc 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD +critcl::summary {Ingress of arguments for cproc} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare various + argument types to cproc. +} + +critcl::subject demonstration {cproc argument types} +#critcl::config lines 0 + +# # ## ### ##### ######## ############# ##################### +## C code. + +# general types +foreach type { + boolean int long wideint + double float + char* pstring bytes bytearray + Tcl_Obj* list + channel +} { + critcl::cproc $type [list $type x] void {} + # variadic - triggered by `args` argument name + #critcl::cproc variadic-$type [list $type args] void {} +} + +# constrained types +foreach t {int long wideint double float} { + foreach {r v} { + {> 0} 1 {>= 0} 0 {> 1} 2 {>= 1} 1 + {< 0} -1 {<= 0} 0 {< 1} 0 {<= 1} 1 + } { + set type "$t $r" + critcl::cproc $type [list $type x] void {} + } +} + +# ### ### ### ######### ######### ######### +## Ready +package provide ingress 1 diff --git a/src/vfs/critcl.vfs/examples/bitmap/bitmap.tcl b/src/vfs/critcl.vfs/examples/bitmap/bitmap.tcl new file mode 100644 index 00000000..6cf1243b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/bitmap/bitmap.tcl @@ -0,0 +1,66 @@ +# bitmap.tcl -- +# +# A template demonstrating the handling of bitmap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::bitmap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare a bitmap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {bitmap conversion} {encode bitmap} \ + {decode bitmap} {convert bitmap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::bitmap::def demo { + global 1 + exact 2 + filler 4 +} + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* flags} int { + int mask; + demo_encode (ip, flags, &mask); + return mask; +} + +critcl::cproc decode {Tcl_Interp* ip int mask} object { + Tcl_Obj* res = demo_decode (ip, mask); + Tcl_IncrRefCount (res); + return res; +} + +# Encode hidden in the argtype. +critcl::cproc xencode {Tcl_Interp* ip demo flags} int { + return flags; +} + +# Decode hidden in the resultype +critcl::cproc xdecode {Tcl_Interp* ip int mask} demo { + return mask; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide bitmap 1 diff --git a/src/vfs/critcl.vfs/examples/bitmap/build.tcl b/src/vfs/critcl.vfs/examples/bitmap/build.tcl new file mode 100644 index 00000000..d96ffdd2 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/bitmap/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {bitmap} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/bitmap/cr.tcl b/src/vfs/critcl.vfs/examples/bitmap/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/bitmap/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/bitmap/example.tcl b/src/vfs/critcl.vfs/examples/bitmap/example.tcl new file mode 100644 index 00000000..b9e2a447 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/bitmap/example.tcl @@ -0,0 +1,6 @@ +#!/usr/bin/env tclsh + +ex encode {exact filler} +ex decode 5 +ex xencode global +ex xdecode 6 diff --git a/src/vfs/critcl.vfs/examples/build.tcl b/src/vfs/critcl.vfs/examples/build.tcl new file mode 100644 index 00000000..9666136e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/build.tcl @@ -0,0 +1,15 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set selfdir [file dirname [file normalize [info script]]] +set self [file tail [info script]] + +# Run the build code in the sub-directories, passing any arguments. + +puts "" +foreach b [glob -directory $selfdir */$self] { + puts "$b _______________________________________________" + eval [linsert $argv 0 exec 2>@ stderr >@ stdout [info nameofexecutable] $b] + puts "" + puts "" +} diff --git a/src/vfs/critcl.vfs/examples/clist/build.tcl b/src/vfs/critcl.vfs/examples/clist/build.tcl new file mode 100644 index 00000000..4f20b9da --- /dev/null +++ b/src/vfs/critcl.vfs/examples/clist/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {clist} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug build of package.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/clist/clist.tcl b/src/vfs/critcl.vfs/examples/clist/clist.tcl new file mode 100644 index 00000000..47a7bb9a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/clist/clist.tcl @@ -0,0 +1,277 @@ +# clist.tcl -- +# +# Set of list processing primitives. A Tcl companion file is then +# used to provide structure on top, here, an ensemble command. +# +# Copyright (c) 2011,2022 Andreas Kupries + +# Example of using a Tcl companion file to put a layer of structure +# (and/or policy) on top of a set of C primitives. +# +# Here: Export of the primitives as an ensemble. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::tcl 8.6 +critcl::license {Andreas Kupries} BSD + +critcl::summary {Extended list processing command.} + +critcl::description { + This package implements an ensemble command providing + additional list processing functionality, like map, filter, + etc. +} + +critcl::subject {list processing} {extended list processing} +critcl::subject map foldl filter +critcl::subject {list map} {list foldl} {list filter} + +# # ## ### ##### ######## ############# ##################### +## Configuration + +critcl::tsources clist_tcl.tcl + +# # ## ### ##### ######## ############# ##################### +## Implementation. +## +## NOTE: This code is 8.4 based and not NRE ready. + +namespace eval ::clist {} + +# # ## ### ##### ######## ############# ##################### + +critcl::cproc ::clist::map { + Tcl_Interp* interp + Tcl_Obj* cmdprefix + Tcl_Obj* list +} Tcl_Obj* { + /* Equivalent to the following Tcl code: + * ----------------------------------------------------- + * set result {} + * foreach e $list { lappend result [{*}$cmdprefix $e] } + * return $result + * ----------------------------------------------------- + * This is at its core a specialized fold operation. + * (initial value {}, operation 'list append') + */ + + Tcl_Obj** cv; + int cc; + + Tcl_Obj** lv; + int lc; + + Tcl_Obj** cmdv; + int cmdc; + + int k, code; + Tcl_Obj* rlist; + + if (Tcl_ListObjGetElements (interp, cmdprefix, &cc, &cv) != TCL_OK) { + return NULL; + } + + if (Tcl_ListObjGetElements (interp, list, &lc, &lv) != TCL_OK) { + return NULL; + } + + cmdc = cc + 1; + cmdv = (Tcl_Obj**) ckalloc (sizeof (Tcl_Obj*) * cmdc); + + for (k = 0; k < cc; k++) { cmdv [k] = cv [k]; Tcl_IncrRefCount (cmdv [k]); } + + rlist = Tcl_NewListObj (0, NULL); + Tcl_IncrRefCount (rlist); + + for (k=0; k < lc; k++) { + cmdv [cc] = lv [k]; + Tcl_IncrRefCount (cmdv [cc]); + + code = Tcl_EvalObjv (interp, cmdc, cmdv, 0); + + Tcl_DecrRefCount (cmdv [cc]); + + if ((code != TCL_OK) || + (Tcl_ListObjAppendElement (interp, rlist, Tcl_GetObjResult (interp)) != TCL_OK)) { + goto abort; + } + } + +done: + for (k=0; k < cc; k++) { Tcl_DecrRefCount (cmdv [k]); } + ckfree ((char*) cmdv); + return rlist; + +abort: + Tcl_DecrRefCount (rlist); + rlist = NULL; + goto done; +} + +# # ## ### ##### ######## ############# ##################### + +critcl::cproc ::clist::filter { + Tcl_Interp* interp + Tcl_Obj* cmdprefix + Tcl_Obj* list +} Tcl_Obj* { + /* Equivalent to the following Tcl code: + * ----------------------------------------------------- + * set result {} + * foreach e $list { + * if {![{*}$cmdprefix $e]} continue; + * lappend result $e + * } + * return $result + * ----------------------------------------------------- + * This is at its core a specialized fold operation. + * (initial value {}, operation 'conditional list append') + */ + + Tcl_Obj** cv; + int cc; + + Tcl_Obj** lv; + int lc; + + Tcl_Obj** cmdv; + int cmdc; + + int k, code, keep; + Tcl_Obj* rlist; + + if (Tcl_ListObjGetElements (interp, cmdprefix, &cc, &cv) != TCL_OK) { + return NULL; + } + + if (Tcl_ListObjGetElements (interp, list, &lc, &lv) != TCL_OK) { + return NULL; + } + + cmdc = cc + 1; + cmdv = (Tcl_Obj**) ckalloc (sizeof (Tcl_Obj*) * cmdc); + + for (k = 0; k < cc; k++) { cmdv [k] = cv [k]; Tcl_IncrRefCount (cmdv [k]); } + + rlist = Tcl_NewListObj (0, NULL); + Tcl_IncrRefCount (rlist); + + for (k=0; k < lc; k++) { + cmdv [cc] = lv [k]; + Tcl_IncrRefCount (cmdv [cc]); + + code = Tcl_EvalObjv (interp, cmdc, cmdv, 0); + + Tcl_DecrRefCount (cmdv [cc]); + + if ((code != TCL_OK) || + (Tcl_GetBooleanFromObj (interp, Tcl_GetObjResult (interp), &keep) != TCL_OK)) { + goto abort; + } + + if (keep && + (Tcl_ListObjAppendElement (interp, rlist, lv[k]) != TCL_OK)) { + goto abort; + } + } + +done: + for (k=0; k < cc; k++) { Tcl_DecrRefCount (cmdv [k]); } + ckfree ((char*) cmdv); + return rlist; + +abort: + Tcl_DecrRefCount (rlist); + rlist = NULL; + goto done; +} + +# # ## ### ##### ######## ############# ##################### + +critcl::cproc ::clist::foldl { + Tcl_Interp* interp + Tcl_Obj* cmdprefix + Tcl_Obj* initial + Tcl_Obj* list +} Tcl_Obj* { + /* Equivalent to the following Tcl code: + * ----------------------------------------------------- + * set result $initial + * foreach e $list { + * set result [{*}$cmdprefix $result $e] + * } + * return $result + * ----------------------------------------------------- + */ + + Tcl_Obj** cv; + int cc; + + Tcl_Obj** lv; + int lc; + + Tcl_Obj** cmdv; + int cmdc; + + int k, code, keep; + Tcl_Obj* result; + + if (Tcl_ListObjGetElements (interp, cmdprefix, &cc, &cv) != TCL_OK) { + return NULL; + } + + if (Tcl_ListObjGetElements (interp, list, &lc, &lv) != TCL_OK) { + return NULL; + } + + cmdc = cc + 2; + cmdv = (Tcl_Obj**) ckalloc (sizeof (Tcl_Obj*) * cmdc); + + for (k = 0; k < cc; k++) { cmdv [k] = cv [k]; Tcl_IncrRefCount (cmdv [k]); } + + result = Tcl_DuplicateObj (initial); + Tcl_IncrRefCount (result); + + for (k=0; k < lc; k++) { + cmdv [cc] = result; + cmdv [cc+1] = lv [k]; + + Tcl_IncrRefCount (cmdv [cc]); + Tcl_IncrRefCount (cmdv [cc+1]); + + code = Tcl_EvalObjv (interp, cmdc, cmdv, 0); + + Tcl_DecrRefCount (cmdv [cc]); + Tcl_DecrRefCount (cmdv [cc+1]); + + if (code != TCL_OK) { + goto abort; + } + + Tcl_DecrRefCount (result); + result = Tcl_GetObjResult (interp); + Tcl_IncrRefCount (result); + } + +done: + for (k=0; k < cc; k++) { Tcl_DecrRefCount (cmdv [k]); } + ckfree ((char*) cmdv); + return result; + +abort: + Tcl_DecrRefCount (result); + result = NULL; + goto done; +} + +# ### ### ### ######### ######### ######### +## Ready +package provide clist 1 diff --git a/src/vfs/critcl.vfs/examples/clist/clist_tcl.tcl b/src/vfs/critcl.vfs/examples/clist/clist_tcl.tcl new file mode 100644 index 00000000..cc4c227a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/clist/clist_tcl.tcl @@ -0,0 +1,27 @@ +# clist_tcl.tcl -- +# +# Tcl companion file to clist. Takes the primitives exported +# by the C parts and arranges them into a nice and proper +# ensemble command. +# +# Copyright (c) 2011,2022 Andreas Kupries + +# Example of using a Tcl companion file to put a layer of structure +# (and/or policy) on top of a set of C primitives. + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +# See clist.tcl + +# # ## ### ##### ######## ############# ##################### +## Implementation. + +namespace eval ::clist { + namespace export map foldl filter + namespace ensemble create +} + +# ### ### ### ######### ######### ######### +## OK + diff --git a/src/vfs/critcl.vfs/examples/clist/cr.tcl b/src/vfs/critcl.vfs/examples/clist/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/clist/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/clist/example.tcl b/src/vfs/critcl.vfs/examples/clist/example.tcl new file mode 100644 index 00000000..67e63a75 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/clist/example.tcl @@ -0,0 +1,21 @@ + +package require Tcl 8.6 +package require lambda + +# Force compile and load. +catch {clist::map} + +# squares +ex clist map [lambda {x} { + expr {$x * $x} +}] {0 1 2 3 4 5 6 7 8 9} + +# filter out even numbers <=> select odd numbers +ex ::clist::filter [lambda {x} { + expr {$x % 2} +}] {0 1 2 3 4 5 6 7 8 9} + +# sum +ex ::clist foldl [lambda {a x} { + expr {$a + $x} +}] 0 {0 1 2 3 4 5 6 7 8 9} diff --git a/src/vfs/critcl.vfs/examples/cr.tcl b/src/vfs/critcl.vfs/examples/cr.tcl new file mode 100644 index 00000000..1a733102 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/cr.tcl @@ -0,0 +1,21 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- + +set selfdir [file dirname [file normalize [info script]]] +set self [file tail [info script]] + +set pattern [lindex $argv 0] +if {$pattern eq ""} { + set pattern * +} +# Perform "compile & run" in the sub-directories. + +puts "" +foreach cr [lsort -dict [glob -directory $selfdir $pattern/$self]] { + puts "$cr _______________________________________________" + catch { + eval [list exec 2>@ stderr >@ stdout [info nameofexecutable] $cr] + } + puts "" + puts "" +} diff --git a/src/vfs/critcl.vfs/examples/emap-both/build.tcl b/src/vfs/critcl.vfs/examples/emap-both/build.tcl new file mode 100644 index 00000000..2194338f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-both/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {emap-both} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/emap-both/cr.tcl b/src/vfs/critcl.vfs/examples/emap-both/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-both/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/emap-both/emap-both.tcl b/src/vfs/critcl.vfs/examples/emap-both/emap-both.tcl new file mode 100644 index 00000000..17ff52c2 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-both/emap-both.tcl @@ -0,0 +1,71 @@ +# emap_ex.tcl -- +# +# A template demonstrating the handling of emap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::emap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an emap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {emap conversion} {encode emap} \ + {decode emap} {convert emap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 +} + +critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE +} -mode {c tcl} +# Add -nocase as last argument for case-insensitive Tcl strings. + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); +} + +critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; +} + +# Encode hidden in the argtype. +critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; +} + +# Decode hidden in the resultype +critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide emap-both 1 diff --git a/src/vfs/critcl.vfs/examples/emap-both/example.tcl b/src/vfs/critcl.vfs/examples/emap-both/example.tcl new file mode 100644 index 00000000..88ffff3d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-both/example.tcl @@ -0,0 +1,16 @@ + +package require emap-both + +ex encode mix ;# 1 +ex xencode done ;# 2 + +ex decode 0 ;# init +ex xdecode 1 ;# mix + +ex encode foo +ex xencode bar +ex decode 55 +ex xdecode -2 + +ex xencode MIX + diff --git a/src/vfs/critcl.vfs/examples/emap-c/build.tcl b/src/vfs/critcl.vfs/examples/emap-c/build.tcl new file mode 100644 index 00000000..be055461 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-c/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {emap-c} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/emap-c/cr.tcl b/src/vfs/critcl.vfs/examples/emap-c/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-c/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/emap-c/emap-c.tcl b/src/vfs/critcl.vfs/examples/emap-c/emap-c.tcl new file mode 100644 index 00000000..51ca83fe --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-c/emap-c.tcl @@ -0,0 +1,61 @@ +# emap_ex.tcl -- +# +# A template demonstrating the handling of emap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::emap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an emap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {emap conversion} {encode emap} \ + {decode emap} {convert emap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 +} + +critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE +} -mode c +# Add -nocase as last argument for case-insensitive Tcl strings. + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); +} + +critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide emap-c 1 diff --git a/src/vfs/critcl.vfs/examples/emap-c/example.tcl b/src/vfs/critcl.vfs/examples/emap-c/example.tcl new file mode 100644 index 00000000..bfe7341a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap-c/example.tcl @@ -0,0 +1,8 @@ + +package require emap-c + +ex encode mix ;# 1 +ex encode foo + +ex decode 0 ;# init +ex decode 55 diff --git a/src/vfs/critcl.vfs/examples/emap/build.tcl b/src/vfs/critcl.vfs/examples/emap/build.tcl new file mode 100644 index 00000000..48ca964c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {emap} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/emap/cr.tcl b/src/vfs/critcl.vfs/examples/emap/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/emap/emap-ex.tcl b/src/vfs/critcl.vfs/examples/emap/emap-ex.tcl new file mode 100644 index 00000000..d108f2e8 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap/emap-ex.tcl @@ -0,0 +1,75 @@ +# emap_ex.tcl -- +# +# A template demonstrating the handling of emap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::emap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an emap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {emap conversion} {encode emap} \ + {decode emap} {convert emap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 +} + +critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE +} +# Add -nocase as last argument for case-insensitive Tcl strings. + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + int scode; + if (demo_encode (ip, state, &scode) != TCL_OK) { + return -1; + } + return scode; +} + +critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = demo_decode (ip, scode); + if (res) { Tcl_IncrRefCount (res); } + return res; +} + +# Encode hidden in the argtype. +critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; +} + +# Decode hidden in the resultype +critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide emap 1 diff --git a/src/vfs/critcl.vfs/examples/emap/example.tcl b/src/vfs/critcl.vfs/examples/emap/example.tcl new file mode 100644 index 00000000..b18d2f06 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emap/example.tcl @@ -0,0 +1,16 @@ + +package require emap + +ex encode mix ;# 1 +ex xencode done ;# 2 + +ex decode 0 ;# init +ex xdecode 1 ;# mix + +ex encode foo +ex xencode bar +ex decode 55 +ex xdecode -2 + +ex xencode MIX + diff --git a/src/vfs/critcl.vfs/examples/emapint-both/build.tcl b/src/vfs/critcl.vfs/examples/emapint-both/build.tcl new file mode 100644 index 00000000..06667d80 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-both/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {emapint-both} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/emapint-both/cr.tcl b/src/vfs/critcl.vfs/examples/emapint-both/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-both/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/emapint-both/emapint-both.tcl b/src/vfs/critcl.vfs/examples/emapint-both/emapint-both.tcl new file mode 100644 index 00000000..2e68c4dd --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-both/emapint-both.tcl @@ -0,0 +1,70 @@ +# emap_ex.tcl -- +# +# A template demonstrating the handling of emap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::emap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an emap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {emap conversion} {encode emap} \ + {decode emap} {convert emap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::emap::def demo { + init 0 + start 0 + mix 1 + final 2 + done 2 +} -nocase -mode {c tcl} +# Add +# loop 5 +# to the spec to see an example with a hole in the code sequence. +# Append -nocase as last arg to make encoding case-insensitive. + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); +} + +critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; +} + +# Encode hidden in the argtype. +critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; +} + +# Decode hidden in the resultype +critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide emapint-both 1 diff --git a/src/vfs/critcl.vfs/examples/emapint-both/example.tcl b/src/vfs/critcl.vfs/examples/emapint-both/example.tcl new file mode 100644 index 00000000..0227f8ad --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-both/example.tcl @@ -0,0 +1,16 @@ + +package require emapint-both + +ex encode mix ;# 1 +ex xencode done ;# 2 + +ex decode 0 ;# init +ex xdecode 1 ;# mix + +ex encode foo +ex xencode bar +ex decode 55 +ex decode 4 +ex xdecode -2 +ex xdecode 4 +ex xencode MIX diff --git a/src/vfs/critcl.vfs/examples/emapint-c/build.tcl b/src/vfs/critcl.vfs/examples/emapint-c/build.tcl new file mode 100644 index 00000000..462b2d3b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-c/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {emapint-c} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/emapint-c/cr.tcl b/src/vfs/critcl.vfs/examples/emapint-c/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-c/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/emapint-c/emapint-c.tcl b/src/vfs/critcl.vfs/examples/emapint-c/emapint-c.tcl new file mode 100644 index 00000000..bbabfe8a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-c/emapint-c.tcl @@ -0,0 +1,60 @@ +# emap_ex.tcl -- +# +# A template demonstrating the handling of emap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::emap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an emap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {emap conversion} {encode emap} \ + {decode emap} {convert emap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::emap::def demo { + init 0 + start 0 + mix 1 + final 2 + done 2 +} -nocase -mode c +# Add +# loop 5 +# to the spec to see an example with a hole in the code sequence. +# Append -nocase as last arg to make encoding case-insensitive. + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); +} + +critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide emapint-c 1 diff --git a/src/vfs/critcl.vfs/examples/emapint-c/example.tcl b/src/vfs/critcl.vfs/examples/emapint-c/example.tcl new file mode 100644 index 00000000..94cf72e7 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint-c/example.tcl @@ -0,0 +1,9 @@ + +package require emapint-c + +ex encode mix ;# 1 +ex encode foo + +ex decode 0 ;# init +ex decode 55 +ex decode 4 diff --git a/src/vfs/critcl.vfs/examples/emapint/build.tcl b/src/vfs/critcl.vfs/examples/emapint/build.tcl new file mode 100644 index 00000000..5f21fc19 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {emapint} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/emapint/cr.tcl b/src/vfs/critcl.vfs/examples/emapint/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/emapint/emapint.tcl b/src/vfs/critcl.vfs/examples/emapint/emapint.tcl new file mode 100644 index 00000000..415ac929 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint/emapint.tcl @@ -0,0 +1,74 @@ +# emap_ex.tcl -- +# +# A template demonstrating the handling of emap conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::emap 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Bitmap conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an emap + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {emap conversion} {encode emap} \ + {decode emap} {convert emap} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::emap::def demo { + init 0 + start 0 + mix 1 + final 2 + done 2 +} -nocase +# Add +# loop 5 +# to the spec to see an example with a hole in the code sequence. +# Append -nocase as last arg to make encoding case-insensitive. + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + int scode; + if (demo_encode (ip, state, &scode) != TCL_OK) { + return -1; + } + return scode; +} + +critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = demo_decode (ip, scode); + if (res) { Tcl_IncrRefCount (res); } + return res; +} + +# Encode hidden in the argtype. +critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; +} + +# Decode hidden in the resultype +critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; +} + +# encode {exact filler} => 6 +# decode 5 => {global filler} + +# ### ### ### ######### ######### ######### +## Ready +package provide emapint 1 diff --git a/src/vfs/critcl.vfs/examples/emapint/example.tcl b/src/vfs/critcl.vfs/examples/emapint/example.tcl new file mode 100644 index 00000000..0cea93a8 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/emapint/example.tcl @@ -0,0 +1,16 @@ + +package require emapint + +ex encode mix ;# 1 +ex xencode done ;# 2 + +ex decode 0 ;# init +ex xdecode 1 ;# mix + +ex encode foo +ex xencode bar +ex decode 55 +ex decode 4 +ex xdecode -2 +ex xdecode 4 +ex xencode MIX diff --git a/src/vfs/critcl.vfs/examples/enum-list/build.tcl b/src/vfs/critcl.vfs/examples/enum-list/build.tcl new file mode 100644 index 00000000..d620f847 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum-list/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {enum} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/enum-list/cr.tcl b/src/vfs/critcl.vfs/examples/enum-list/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum-list/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/enum-list/enum.tcl b/src/vfs/critcl.vfs/examples/enum-list/enum.tcl new file mode 100644 index 00000000..b38f4a68 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum-list/enum.tcl @@ -0,0 +1,51 @@ +# enum.tcl -- +# +# A template demonstrating the handling of enum conversions. +# Configured for to allow multi-access returning a list +# +# Copyright (c) 2018,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::enum 1.1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Enum conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an enum + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {enum conversion} {encode enum} \ + {decode enum} {convert enum} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::enum::def demo { + E_global global + E_exact exact + E_filler filler +} +list + +critcl::cproc decode {Tcl_Interp* ip int args} object { + Tcl_Obj* res = demo_ToObjList (ip, args.c, args.v); + Tcl_IncrRefCount (res); + return res; +} + +# decode 2 => filler +# decode 8 => panic, abort, core dump + +# ### ### ### ######### ######### ######### +## Ready +package provide enum 1 diff --git a/src/vfs/critcl.vfs/examples/enum-list/example.tcl b/src/vfs/critcl.vfs/examples/enum-list/example.tcl new file mode 100644 index 00000000..d3a45045 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum-list/example.tcl @@ -0,0 +1,5 @@ + +ex decode 2 +ex decode 1 0 2 + +#ex decode 8 => panic, abort, core dump diff --git a/src/vfs/critcl.vfs/examples/enum/build.tcl b/src/vfs/critcl.vfs/examples/enum/build.tcl new file mode 100644 index 00000000..d620f847 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {enum} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/enum/cr.tcl b/src/vfs/critcl.vfs/examples/enum/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/enum/enum.tcl b/src/vfs/critcl.vfs/examples/enum/enum.tcl new file mode 100644 index 00000000..266cd436 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum/enum.tcl @@ -0,0 +1,77 @@ +# bitmap.tcl -- +# +# A template demonstrating the handling of enum conversions. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::enum 1 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Enum conversion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare an enum + converter and use it in cproc's or ccommand's. +} + +critcl::subject demonstration {enum conversion} {encode enum} \ + {decode enum} {convert enum} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::enum::def demo { + E_global global + E_exact exact + E_filler filler +} + +critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* str} int { + int val; + demo_GetFromObj (ip, str, 0, &val); + return val; +} + +critcl::cproc decode {Tcl_Interp* ip int val} object { + Tcl_Obj* res = demo_ToObj (ip, val); + Tcl_IncrRefCount (res); + return res; +} + +# Encode hidden in the argtype. +critcl::cproc xencode {Tcl_Interp* ip demo str} int { + return str; +} + +# Encode hidden in the argtype. +critcl::cproc xencode-p {Tcl_Interp* ip demo-prefix str} int { + return str; +} + +# Decode hidden in the resultype +critcl::cproc xdecode {Tcl_Interp* ip int val} demo { + return val; +} + +# encode exact => 1 +# xencode filler => 2 +# xencode-p glob => 0 +# xencode glob => /error/ + +# decode 2 => filler +# xdecode 0 => global +# decode 8 => panic, abort, core dump + +# ### ### ### ######### ######### ######### +## Ready +package provide enum 1 diff --git a/src/vfs/critcl.vfs/examples/enum/example.tcl b/src/vfs/critcl.vfs/examples/enum/example.tcl new file mode 100644 index 00000000..402996e3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/enum/example.tcl @@ -0,0 +1,11 @@ + +ex encode exact +ex xencode filler +ex xencode-p glob +ex xencode glob + +ex decode 2 +ex xdecode 0 + +#ex decode 8 => panic, abort, core dump +#ex xdecode 8 ditto diff --git a/src/vfs/critcl.vfs/examples/icounter/build.tcl b/src/vfs/critcl.vfs/examples/icounter/build.tcl new file mode 100644 index 00000000..4209066f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/icounter/build.tcl @@ -0,0 +1,287 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {icounter} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall all packages, build for debugging.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -keep -debug symbols -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/icounter/cr.tcl b/src/vfs/critcl.vfs/examples/icounter/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/icounter/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/icounter/example.tcl b/src/vfs/critcl.vfs/examples/icounter/example.tcl new file mode 100644 index 00000000..db048941 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/icounter/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {icounter 4} + +ex icounter 0 +ex ::icounter -1 diff --git a/src/vfs/critcl.vfs/examples/icounter/icounter.tcl b/src/vfs/critcl.vfs/examples/icounter/icounter.tcl new file mode 100644 index 00000000..866f3c29 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/icounter/icounter.tcl @@ -0,0 +1,54 @@ +# icounter.tcl -- +# +# Implementation of a counter associated with an interpreter. +# This code based on critcl v3.1, API compatible to the PTI [x]. +# [x] Pure Tcl Implementation. +# +# Copyright (c) 2012,2022 Andreas Kupries +# +# 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.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::iassoc ; # Maintain an interpreter association. +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} {BSD licensed} + +critcl::summary {Per interpreter global counters.} + +critcl::description { + This package implements a per-interpreter counter. +} + +critcl::subject counter + +# # ## ### ##### ######## ############# ##################### +## Define and maintain the per-interp structure. + +critcl::iassoc::def icounter {int base} { + int counter; /* The counter variable */ +} { + data->counter = base; +} { + /* Nothing to release */ +} + +# # ## ### ##### ######## ############# ##################### +## Access and expose the per-interp structure to scripts. + +critcl::cproc icounter {Tcl_Interp* interp int base} int { + icounter_data d = icounter (interp, base); + d->counter ++; + return d->counter; +} + +# ### ### ### ######### ######### ######### +## Ready +package provide icounter 1 diff --git a/src/vfs/critcl.vfs/examples/lit-both/build.tcl b/src/vfs/critcl.vfs/examples/lit-both/build.tcl new file mode 100644 index 00000000..f013ee5d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-both/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {pool} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/lit-both/cr.tcl b/src/vfs/critcl.vfs/examples/lit-both/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-both/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/lit-both/example.tcl b/src/vfs/critcl.vfs/examples/lit-both/example.tcl new file mode 100644 index 00000000..81030771 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-both/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {str} + +ex str 1 +ex cstr 2 diff --git a/src/vfs/critcl.vfs/examples/lit-both/pool.tcl b/src/vfs/critcl.vfs/examples/lit-both/pool.tcl new file mode 100644 index 00000000..985085b9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-both/pool.tcl @@ -0,0 +1,57 @@ +# pool.tcl -- +# +# A template demonstrating the handling of string/literal pools. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::literals 1.1 ;# result-type + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {String pools} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare a shared + string pool and use it in cproc's or ccommand's +} + +critcl::subject demonstration {string pool} {literal pool} \ + {shared strings} {shared literals} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" +} {c tcl} + +critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = demo (ip, code); + Tcl_IncrRefCount (res); + return res; +} + +critcl::cproc cstr {Tcl_Interp* ip int code} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_cstr (code), -1); + Tcl_IncrRefCount (res); + return res; +} + +# str 0 +# str 7 - panic, abort, core dump + +# ### ### ### ######### ######### ######### +## Ready +package provide pool 1 diff --git a/src/vfs/critcl.vfs/examples/lit-c/build.tcl b/src/vfs/critcl.vfs/examples/lit-c/build.tcl new file mode 100644 index 00000000..f013ee5d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-c/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {pool} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/lit-c/cr.tcl b/src/vfs/critcl.vfs/examples/lit-c/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-c/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/lit-c/example.tcl b/src/vfs/critcl.vfs/examples/lit-c/example.tcl new file mode 100644 index 00000000..de5c587a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-c/example.tcl @@ -0,0 +1,5 @@ + +# Force compile and load. +catch {str} + +ex str 3 diff --git a/src/vfs/critcl.vfs/examples/lit-c/pool.tcl b/src/vfs/critcl.vfs/examples/lit-c/pool.tcl new file mode 100644 index 00000000..8194b0aa --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-c/pool.tcl @@ -0,0 +1,57 @@ +# pool.tcl -- +# +# A template demonstrating the handling of string/literal pools. +# Configured for C access, no wrappers for Tcl. +# +# Copyright (c) 2014-2017,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::literals 1.2 ;# result-type + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {String pools} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare a shared + string pool and use it in cproc's or ccommand's +} + +critcl::subject demonstration \ + {string pool} \ + {literal pool} \ + {shared strings} \ + {shared literals} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" +} c + +critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_cstr (code), -1); + Tcl_IncrRefCount (res); + return res; +} + +# str 0 +# str 7 - panic, abort, core dump + +# # ## ### ##### ######## ############# ##################### + +# ### ### ### ######### ######### ######### +## Ready +package provide pool 1 diff --git a/src/vfs/critcl.vfs/examples/lit-list/build.tcl b/src/vfs/critcl.vfs/examples/lit-list/build.tcl new file mode 100644 index 00000000..f013ee5d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-list/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {pool} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/lit-list/cr.tcl b/src/vfs/critcl.vfs/examples/lit-list/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-list/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/lit-list/example.tcl b/src/vfs/critcl.vfs/examples/lit-list/example.tcl new file mode 100644 index 00000000..725bc8bd --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-list/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {str} + +ex strs 2 +ex strs 3 0 1 diff --git a/src/vfs/critcl.vfs/examples/lit-list/pool.tcl b/src/vfs/critcl.vfs/examples/lit-list/pool.tcl new file mode 100644 index 00000000..e42a6995 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/lit-list/pool.tcl @@ -0,0 +1,54 @@ +# pool.tcl -- +# +# A template demonstrating the handling of string/literal pools. +# Configured for multi-access +# +# Copyright (c) 2018,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::literals 1.3 ;# result-type + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {String pools} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare a shared + string pool and use it in cproc's or ccommand's +} + +critcl::subject demonstration \ + {string pool} {literal pool} \ + {shared strings} {shared literals} \ + {multi-access} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" +} +list + +critcl::cproc strs {Tcl_Interp* ip int args} object { + Tcl_Obj* res = demo_list (ip, args.c, args.v); + Tcl_IncrRefCount (res); + return res; +} + +# str 0 +# str 7 - panic, abort, core dump + +# ### ### ### ######### ######### ######### +## Ready +package provide pool 1 diff --git a/src/vfs/critcl.vfs/examples/literals/build.tcl b/src/vfs/critcl.vfs/examples/literals/build.tcl new file mode 100644 index 00000000..f013ee5d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/literals/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {pool} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/literals/cr.tcl b/src/vfs/critcl.vfs/examples/literals/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/literals/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/literals/example.tcl b/src/vfs/critcl.vfs/examples/literals/example.tcl new file mode 100644 index 00000000..c0df3503 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/literals/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {str} + +ex str 1 +ex xstr 2 diff --git a/src/vfs/critcl.vfs/examples/literals/pool.tcl b/src/vfs/critcl.vfs/examples/literals/pool.tcl new file mode 100644 index 00000000..57837a88 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/literals/pool.tcl @@ -0,0 +1,56 @@ +# pool.tcl -- +# +# A template demonstrating the handling of string/literal pools. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.1.11 +package require critcl::literals 1.1 ;# result-type + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {String pools} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare a shared + string pool and use it in cproc's or ccommand's +} + +critcl::subject demonstration {string pool} {literal pool} \ + {shared strings} {shared literals} + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" +} + +critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = demo (ip, code); + Tcl_IncrRefCount (res); + return res; +} + +# Conversion hidden in the result-type +critcl::cproc xstr {Tcl_Interp* ip int code} demo { + return code; +} + +# str 0 +# str 7 - panic, abort, core dump + +# ### ### ### ######### ######### ######### +## Ready +package provide pool 1 diff --git a/src/vfs/critcl.vfs/examples/md5/cr.tcl b/src/vfs/critcl.vfs/examples/md5/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/md5/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/md5/example.tcl b/src/vfs/critcl.vfs/examples/md5/example.tcl new file mode 100644 index 00000000..f5c8284b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/md5/example.tcl @@ -0,0 +1,39 @@ + +package require critcl_md5c +#set pkgtest 1 + +#source ../../lib/critcl-md5c/md5c.tcl + + proc md5c_try {} { + foreach {msg expected} { + "" + "d41d8cd98f00b204e9800998ecf8427e" + "a" + "0cc175b9c0f1b6a831c399e269772661" + "abc" + "900150983cd24fb0d6963f7d28e17f72" + "message digest" + "f96b697d7cb7938d525a2f31aaf161d0" + "abcdefghijklmnopqrstuvwxyz" + "c3fcd3d76192e4007dfb496cca67e13b" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "d174ab98d277d9f5a5611c2c9f419d9f" + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + "57edf4a22be3c955ac49da2e2107b67a" + } { + puts "testing: md5 \"$msg\"" + binary scan [md5c $msg] H* computed + puts "computed: $computed" + if {0 != [string compare $computed $expected]} { + puts "expected: $expected" + puts "FAILED" + } + } + + foreach len {10 50 100 500 1000 5000 10000 50000 100000 500000 1000000} { + set blanks [format %$len.0s ""] + puts "input length $len: [time {md5c $blanks} 1000]" + } + } + + md5c_try diff --git a/src/vfs/critcl.vfs/examples/optional/build.tcl b/src/vfs/critcl.vfs/examples/optional/build.tcl new file mode 100644 index 00000000..e8e7dbe1 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/optional/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {optional} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/optional/cr.tcl b/src/vfs/critcl.vfs/examples/optional/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/optional/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/optional/example.tcl b/src/vfs/critcl.vfs/examples/optional/example.tcl new file mode 100644 index 00000000..466c2d15 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/optional/example.tcl @@ -0,0 +1,18 @@ +#!/usr/bin/env tclsh + +package require Tcl 8.5 +package require optional + +foreach a { + {} + {6} + {6 7} + {6 7 8} + {6 7 8 9} + {6 7 8 9 0} +} { + ex fixed {*}$a + ex optional_head {*}$a + ex optional_middle {*}$a + ex optional_tail {*}$a +} diff --git a/src/vfs/critcl.vfs/examples/optional/optional.tcl b/src/vfs/critcl.vfs/examples/optional/optional.tcl new file mode 100644 index 00000000..6dd11ea5 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/optional/optional.tcl @@ -0,0 +1,54 @@ +# optional.tcl -- +# +# A template demonstrating the handling of optional arguments to cproc. +# +# Copyright (c) 2012,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Optional arguments for cproc} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare cproc's + with optional arguments. +} + +critcl::subject demonstration {cproc optional arguments} +#critcl::config lines 0 + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::cproc fixed {int a int b int c int d} void { + printf ("F|%d|%d|%d|%d|\n", a,b,c,d); + fflush(stdout); +} + +critcl::cproc optional_head {int {a 1} int {b 2} int c int d} void { + printf ("H|%d|%d|%d|%d|\n", a,b,c,d); + fflush(stdout); +} + +critcl::cproc optional_tail {int a int b int {c 1} int {d 2}} void { + printf ("T|%d|%d|%d|%d|\n", a,b,c,d); + fflush(stdout); +} + +critcl::cproc optional_middle {int a int {b 1} int {c 2} int d} void { + printf ("M|%d|%d|%d|%d|\n", a,b,c,d); + fflush(stdout); +} + +# ### ### ### ######### ######### ######### +## Ready +package provide optional 1 diff --git a/src/vfs/critcl.vfs/examples/queue/README.txt b/src/vfs/critcl.vfs/examples/queue/README.txt new file mode 100644 index 00000000..11cfc2d6 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/queue/README.txt @@ -0,0 +1,13 @@ +Example of critcl-based packages. + +A larger example written to demonstrate + + Easy writing of C classes, with class and instances + represented as commands, through the utility package + critcl::class + +Sources + Package "queuec": queuec.tcl, queuec/*.[ch] + +Notes: + -- diff --git a/src/vfs/critcl.vfs/examples/queue/build.tcl b/src/vfs/critcl.vfs/examples/queue/build.tcl new file mode 100644 index 00000000..cc864b3a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/queue/build.tcl @@ -0,0 +1,295 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {queuec} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + package require critcl + package require critcl::class + + puts v=[set v [package present critcl]] + puts [package ifneeded critcl $v] + + puts v=[set vc [package present critcl::class]] + puts [package ifneeded critcl::class $vc] + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall all packages, build for debugging.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -keep -debug symbols -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/queue/cr.tcl b/src/vfs/critcl.vfs/examples/queue/cr.tcl new file mode 100644 index 00000000..548273b0 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/queue/cr.tcl @@ -0,0 +1,54 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] + +package require critcl 3.2 + +puts v=[set v [package present critcl]] +puts [package ifneeded critcl $v] + +package require critcl::class + +puts v=[set vc [package present critcl::class]] +puts [package ifneeded critcl::class $vc] + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/queue/example.tcl b/src/vfs/critcl.vfs/examples/queue/example.tcl new file mode 100644 index 00000000..fe4f0611 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/queue/example.tcl @@ -0,0 +1,12 @@ + +ex queuec new +ex queuec1 size +ex queuec1 clear +ex queuec1 put a b c +ex queuec1 peek 2 +ex queuec1 get 2 +ex queuec1 size +ex queuec1 clear +ex queuec1 size +ex queuec1 destroy +ex queuec1 diff --git a/src/vfs/critcl.vfs/examples/queue/queuec.tcl b/src/vfs/critcl.vfs/examples/queue/queuec.tcl new file mode 100644 index 00000000..e525e71f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/queue/queuec.tcl @@ -0,0 +1,396 @@ +# queuec.tcl -- +# +# Implementation of a queue data structure for Tcl. +# This code based on critcl v3.1, API compatible to the PTI [x]. +# [x] Pure Tcl Implementation. +# +# Mainly demonstrates the utility package for the creation of classes +# and objects in C, with both classes and their instances represented +# as Tcl commands. In contrast to the stackc demo this does not use a +# separate data structure package, nor separately written method +# implementations. +# +# Copyright (c) 2012,2022 Andreas Kupries +# +# 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.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::class ; # DSL, easy spec of Tcl class/object commands. +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} {BSD licensed} + +critcl::summary {Queue objects for Tcl.} + +critcl::description { + This package implements queue objects + for Tcl. +} + +critcl::subject queue +critcl::subject {data structure} +critcl::subject structure +critcl::subject {abstract data structure} +critcl::subject {generic data structure} + +# # ## ### ##### ######## ############# ##################### +## Configuration and implementation. + +critcl::cheaders util.h + +critcl::class::define ::queuec { + include util.h + + constructor { + if (objc > 0) { + Tcl_AppendResult (interp, "wrong#args for constructor, expected none", NULL); + goto error; + } + } + + method_introspection + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Obj* unget { + List object holding unget'ted elements. + } { + instance->unget = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->unget); + } { + Tcl_DecrRefCount (instance->unget); + } + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Obj* queue { + List object holding the main queue. + } { + instance->queue = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->queue); + } { + Tcl_DecrRefCount (instance->queue); + } + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Obj* append { + List object holding new elements + } { + instance->append = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->append); + } { + Tcl_DecrRefCount (instance->append); + } + + # # ## ### ##### ######## ############# ##################### + insvariable int at { + Index of next element to return from the main queue. + (variable: queue). + } { + instance->at = 0; + } ; # no need for a destructor + + # # ## ### ##### ######## ############# ##################### + method clear proc {} void { + /* + * Delete and recreate the queue memory. A combination of delete/new, + * except the main structure is left unchanged + */ + + Tcl_DecrRefCount (instance->unget); + Tcl_DecrRefCount (instance->queue); + Tcl_DecrRefCount (instance->append); + + instance->at = 0; + instance->unget = Tcl_NewListObj (0,NULL); + instance->queue = Tcl_NewListObj (0,NULL); + instance->append = Tcl_NewListObj (0,NULL); + + Tcl_IncrRefCount (instance->unget); + Tcl_IncrRefCount (instance->queue); + Tcl_IncrRefCount (instance->append); + } + + # # ## ### ##### ######## ############# ##################### + method get as QueueRetrieve 1 + method peek as QueueRetrieve 0 + + # # ## ### ##### ######## ############# ##################### + method put command { + item... = objv[2]... + } { + int i; + + if (objc < 3) { + Tcl_WrongNumArgs (interp, 2, objv, "item ?item ...?"); + return TCL_ERROR; + } + + for (i = 2; i < objc; i++) { + Tcl_ListObjAppendElement (interp, instance->append, objv[i]); + } + + return TCL_OK; + } + + # # ## ### ##### ######## ############# ##################### + method size proc {} int { + return QueueSize (instance, NULL, NULL, NULL); + } + + # # ## ### ##### ######## ############# ##################### + method unget proc {Tcl_Obj* item} ok { + if (instance->at == 0) { + /* Need the unget stack */ + Tcl_ListObjAppendElement (interp, instance->unget, item); + } else { + /* + * We have room in the return buffer, so splice directly instead of + * using the unget stack. + */ + + int queuec = 0; + Tcl_ListObjLength (NULL, instance->queue, &queuec); + + instance->at --; + ASSERT_BOUNDS(instance->at,queuec); + Tcl_ListObjReplace (interp, instance->queue, instance->at, 1, 1, &item); + } + + return TCL_OK; + } + + # # ## ### ##### ######## ############# ##################### + support { + static int + QueueSize (@instancetype@ q, int* u, int* r, int* a) + { + int ungetc = 0; + int queuec = 0; + int appendc = 0; + + Tcl_ListObjLength (NULL, q->unget, &ungetc); + Tcl_ListObjLength (NULL, q->queue, &queuec); + Tcl_ListObjLength (NULL, q->append, &appendc); + + if (u) *u = ungetc; + if (r) *r = queuec; + if (a) *a = appendc; + + return ungetc + queuec + appendc - q->at; + } + + static void + QueueShift (@instancetype@ q) + { + int queuec = 0; + int appendc = 0; + + /* The queue is not done yet, no shift */ + Tcl_ListObjLength (NULL, q->queue, &queuec); + if (q->at < queuec) return; + + /* The queue is done, however there is nothing + * to shift into it, so we don't + */ + Tcl_ListObjLength (NULL, q->append, &appendc); + if (!appendc) return; + + q->at = 0; + Tcl_DecrRefCount (q->queue); + q->queue = q->append; + q->append = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (q->append); + } + + static int + QueueRetrieve (@instancetype@ instance, + Tcl_Interp* interp, + int objc, + Tcl_Obj* CONST* objv, + int get) + { + /* Syntax: queue peek|get ?n? + * [0] [1] [2] + */ + + int listc = 0; + Tcl_Obj** listv; + Tcl_Obj* r; + int n = 1; + int ungetc; + int queuec; + int appendc; + + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs (interp, 2, objv, "?n?"); + return TCL_ERROR; + } + + if (objc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_OK) { + return TCL_ERROR; + } else if (n < 1) { + Tcl_AppendResult (interp, "invalid item count ", + Tcl_GetString (objv[2]), + NULL); + return TCL_ERROR; + } + } + + if (n > QueueSize(instance, &ungetc, &queuec, &appendc)) { + Tcl_AppendResult (interp, + "insufficient items in queue to fill request", + NULL); + return TCL_ERROR; + } + + /* 1. We have item on the unget stack + * a. Enough to satisfy request. + * b. Not enough. + * 2. We have items in the return buffer. + * a. Enough to satisfy request. + * b. Not enough. + * 3. We have items in the append buffer. + * a. Enough to satisfy request. + * b. Not enough. + * + * Case 3. can assume 2b, because an empty return buffer will be filled + * from the append buffer before looking at either. Case 3. cannot happen + * for n==1, the return buffer will contain at least one element. + * + * We distinguish between single and multi-element requests. + * + * XXX AK optimizations - If we can return everything from a single + * buffer, be it queue, or append, just return the buffer object, do not + * create something new. + */ + + if (n == 1) { + if (ungetc) { + /* Pull from unget stack */ + Tcl_ListObjGetElements (interp, instance->unget, &listc, &listv); + r = listv [listc-1]; + Tcl_SetObjResult (interp, r); + if (get) { + /* XXX AK : Should maintain max size info, and proper index, for discard. */ + Tcl_ListObjReplace (interp, instance->unget, listc-1, 1, 0, NULL); + } + } else { + QueueShift (instance); + Tcl_ListObjGetElements (interp, instance->queue, &listc, &listv); + ASSERT_BOUNDS(instance->at,listc); + r = listv [instance->at]; + Tcl_SetObjResult (interp, r); + /* + * Note: Doing the SetObj now is important. It increments the + * refcount of 'r', allowing it to survive if the 'QueueShift' below + * kills the internal list (instance->queue) holding it. + */ + if (get) { + instance->at ++; + QueueShift (instance); + } + } + } else { + /* + * Allocate buffer for result, then fill it using the various data + * sources. + */ + + int i = 0, j; + Tcl_Obj** resv = NALLOC(n,Tcl_Obj*); + + if (ungetc) { + Tcl_ListObjGetElements (interp, instance->unget, &listc, &listv); + /* + * Note how we are iterating backward in listv. unget is managed + * as a stack, avoiding mem-copy operations and both push and pop. + */ + for (j = listc-1; + j >= 0 && i < n; + j--, i++) { + ASSERT_BOUNDS(i,n); + ASSERT_BOUNDS(j,listc); + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + if (get) { + /* XXX AK : Should maintain max size info, and proper index, for discard. */ + Tcl_ListObjReplace (interp, instance->unget, j, i, 0, NULL); + /* XXX CHECK index calcs. */ + } + } + if (i < n) { + QueueShift (instance); + Tcl_ListObjGetElements (interp, instance->queue, &listc, &listv); + for (j = instance->at; + j < listc && i < n; + j++, i++) { + ASSERT_BOUNDS(i,n); + ASSERT_BOUNDS(j,listc); + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + + if (get) { + instance->at = j; + QueueShift (instance); + } else if (i < n) { + /* XX */ + Tcl_ListObjGetElements (interp, instance->append, &listc, &listv); + for (j = 0; + j < listc && i < n; + j++, i++) { + ASSERT_BOUNDS(i,n); + ASSERT_BOUNDS(j,listc); + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + } + } + + /* + * This can happen if and only if we have to pull data from append, + * and get is set. Without get XX would have run and filled the result + * to completion. + */ + + if (i < n) { + ASSERT(get,"Impossible 2nd return pull without get"); + QueueShift (instance); + Tcl_ListObjGetElements (interp, instance->queue, &listc, &listv); + for (j = instance->at; + j < listc && i < n; + j++, i++) { + ASSERT_BOUNDS(i,n); + ASSERT_BOUNDS(j,listc); + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + instance->at = j; + QueueShift (instance); + } + + r = Tcl_NewListObj (n, resv); + Tcl_SetObjResult (interp, r); + + for (i=0;i + +/* Allocation macros for common situations. + */ + +#define ALLOC(type) (type *) ckalloc (sizeof (type)) +#define NALLOC(n,type) (type *) ckalloc ((n) * sizeof (type)) + +/* Assertions in general, and asserting the proper range of an array index. + */ + +#undef STACKC_DEBUG +#define STACKC_DEBUG 1 + +#ifdef STACKC_DEBUG +#define XSTR(x) #x +#define STR(x) XSTR(x) +#define RANGEOK(i,n) ((0 <= (i)) && (i < (n))) +#define ASSERT(x,msg) if (!(x)) { Tcl_Panic (msg " (" #x "), in file " __FILE__ " @line " STR(__LINE__));} +#define ASSERT_BOUNDS(i,n) ASSERT (RANGEOK(i,n),"array index out of bounds: " STR(i) " > " STR(n)) +#else +#define ASSERT(x,msg) +#define ASSERT_BOUNDS(i,n) +#endif + +#endif /* _UTIL_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/random/README.txt b/src/vfs/critcl.vfs/examples/random/README.txt new file mode 100644 index 00000000..086d2868 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/random/README.txt @@ -0,0 +1,30 @@ +Example of critcl-based packages. + +A larger example written to demonstrate + + Export of an API as Tcl stubs table (Package "rnmath") + Import of an API defined as stubs-table (Package "random") + +Package "random" incidentially also demonstrates + + Programmatic access to the imported API for use in C code + generation, and + + Complex C code generation (class and instance commands) from a + few parameters (function name, arguments, ...). + +Sources + Package "rnmath": rnmath.tcl + Package "random": random.tcl + +Notes: + +* "rnmath" contains and exports low-level functions for + generating random numbers following a variety of + distributions. The functions are state-less. The system + function random() (On win: rand()) is used internally as the + basic source of random values. + +* "random" wraps the low-level math into a Tcl class/object + system where generators are objects, each represented as a Tcl + command. diff --git a/src/vfs/critcl.vfs/examples/random/build.tcl b/src/vfs/critcl.vfs/examples/random/build.tcl new file mode 100644 index 00000000..5445e44d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/random/build.tcl @@ -0,0 +1,289 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +# Order of building and installation: "rnmath", then "random", as the +# latter depends on the former. Not relevant for wrap4tea. +set packages {rnmath random} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/random/random.tcl b/src/vfs/critcl.vfs/examples/random/random.tcl new file mode 100644 index 00000000..8735415a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/random/random.tcl @@ -0,0 +1,376 @@ +# -*- tcl -*- (critcl actually, Tcl + embedded C) +# sr.tcl -- +# +# Object-based random number generators. The low-level math, i.e. +# the rnmath functions, is provided by package 'rnmath'. +# +# Concept pulled out of and derived from tcllib/modules/simulation/random.tcl +# Copyright (c) 2007 by Arjen Markus +# +# Critcl code generation and setup +# Copyright (c) 2011,2022 by Andreas Kupries +# +# Example of how to IMPORT a C-level stubs API through critcl v3. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require stubs::gen ; # Generator/iterator framework ... +} + +namespace eval ::random {} + +# # ## ### ##### ######## ############# ##################### +## Configuration + +critcl::license \ + {Arjen Markus, Andreas Kupries} \ + {BSD licensed.} + +critcl::summary {Random number generator objects for Tcl.} + +critcl::description { + This package implements random number generator objects for + Tcl. It uses the functions provided by package 'rnmath' for + the actual math. +} + +critcl::subject {random number generator} +# plus the distributions, see inside of 'genclass' + +# # ## ### ##### ######## ############# ##################### +## Dependencies. + +# C random number generator functions. +set ::random::T [critcl::api import rnmath 1] + +if {$::random::T eq {}} { + critcl::error "Unable to work without programmatic access to the rnmath API, the expected rnmath.decls was not found." +} + +# # ## ### ##### ######## ############# ##################### +## Code generation commands converting a simple RNMATH declaration into +## the necessary C code for class and object commands. + +proc ::random::wrap {} { + variable T + variable PS {} + # Iterate over the slots in the stubs table and generator wrap code for each + # rnmath_ function. + ::stubs::gen::forall $T rnmath [namespace current]::Make 0 + + # Finalize the parameter union ... + set PS "typedef union RNMATHparam \{\n${PS}\} RNMATHparam;" + + # The union is placed into a generated header, getting around + # ordering problems, namely that this is finalized after a number + # of pieces needing the type are declared. The first such piece + # has a #include to the generated header. Whic h works because the + # build happens after everything is generated. + + # critcl::stash ? command + file mkdir [critcl::cache] + set c [open [critcl::cache]/sr_param.h w] + puts $c $PS + close $c + #critcl::ccode $PS + return +} + +proc ::random::Make {name decl index} { + # Handle a single slot. + + variable PS ; # The code for the parameter union (RNMATHparam) is accumulated here. + + lassign $decl ftype fname farguments + # ASSERT ftype == void + if {$ftype ne "void"} return + + # ASSERT fname match rnmath_* + if {![string match rnmath_* $fname]} return + + # Extract generator name from function name. + regsub {^rnmath_} $fname {} rname + + # Split arguments into arguments and results. The latter are + # recognized through their pointer types (Ending in '*'). + set arguments {} + set rtypes {} + foreach a $farguments { + lassign $a atype aname aflag + # ASSERT aflag == {} + if {[string index $atype end] eq "*"} { + lappend rtypes [string range $atype 0 end-1] $aname + } else { + lappend arguments $atype $aname + } + } + + # Generate a structure to hold the function arguments. + # This is added to PS and will become a union of all + # parameter structures. + append PS " struct \{\n" + foreach {atype aname} $arguments { + append PS " $atype $aname;\n" + } + append PS " \} $rname;\n" + + # Invoke the actual code generator. + critcl::msg -nonewline " ($rname)" + genclass $rtypes $rname $arguments + return +} + +proc ::random::genclass {rtypes name arguments} { + # Extend the meta data. Same as used by 'rnmath', to put them + # together, near each other. + critcl::subject "$name probability distribution" + critcl::subject "probability distribution $name" + critcl::subject "distribution $name" + + set ingest "" + foreach {t a} $arguments { + append ingest "\t rnmathp->$name.$a = _$a;\n" + lappend theparameters "rnmathp->${name}.$a" + } + + set argnames [critcl::argnames $arguments] + set thearguments [join [critcl::argcsignature $arguments] {, }] + set argvars [indent "\t " [join [critcl::argvardecls $arguments] \n]]\n + set argcheck [indent "\t " [join [critcl::argconversion $arguments] \n]]\n + + if {[llength $rtypes] == 2} { + # Single-value result. Variables for each, and construction of a list. + + lassign $rtypes t r + + append resultvars "\t $t _$r;\n" + append resultvars "\t Tcl_Obj* _lv;\n" + + append resultget "\t _lv = Tcl_New[cap $t]Obj (_$r);\n" + append thearguments ", $t* $r" + lappend theparameters "&_$r" + set resultset "_lv" + } else { + # Multi-value result. Variables for each, and construction of a list. + set lc 0 + foreach {t r} $rtypes { + append resultvars "\t $t _$r;\n" + append resultget "\t _lv\[$lc\] = Tcl_New[cap $t]Obj (_$r);\n" + append thearguments ", $t* $r" + lappend theparameters "&_$r" + incr lc + } + append resultvars "\t Tcl_Obj* _lv\[$lc\];\n" + set resultset "Tcl_NewListObj ($lc,_lv)" + } + + set theparameters [join $theparameters {, }] + + # Low-level math function generating the numbers. Imported from rnmath stubs. + + # Instance command for the generators. Invokes the math function + # with the parameters it got through its client data. + + critcl::ccode [subst -nocommand { + static int + r_${name}_objcmd (ClientData cd, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[]) + { + RNMATHparam* rnmathp = (RNMATHparam*) cd; +$resultvars + if (objc > 1) { + Tcl_WrongNumArgs (interp, 1, objv, ""); + return TCL_ERROR; + } + + rnmath_$name ($theparameters); +$resultget + Tcl_SetObjResult (interp, $resultset); + return TCL_OK; + } + }] + + # Class command for generators of this type. Creates instance + # commands with proper client data. + set np [llength $argnames] + set nmin [expr {$np + 1}] + set nmax [expr {$np + 2}] + + critcl::ccommand ::random::$name {cd interp oc ov} [subst -nocommands { + RNMATHparam* rnmathp; + char* name; +$argvars + if (oc == $nmin) { + name = NULL; + } else if (oc == $nmax) { + name = Tcl_GetString (ov [1]); + ov++; + } else { + Tcl_WrongNumArgs (interp, 1, ov, "?name? $argnames"); + return TCL_ERROR; + } + +$argcheck + rnmathp = RNMATHnewCmd (interp, "$name", name, r_${name}_objcmd); + + if (!rnmathp) { + return TCL_ERROR; + } + +$ingest + return TCL_OK; + }] + + return +} + +proc ::random::cap {name} { + return [string toupper [string index $name 0]][string range $name 1 end] +} + +proc ::random::indent {prefix text} { + return ${prefix}[join [split $text \n] \n$prefix] +} + +# # ## ### ##### ######## ############# ##################### +## Intro and shared/common/fixed code. + +critcl::ccode { + /* -*- c -*- */ + /* .................................................. */ + /* Global generator management, per interp */ + +#include /* Generated, see random::wrap */ +#define PREFIX "random" + + typedef struct RNMATHglobal { + long int counter; + char buf [sizeof (PREFIX) + 40 + 40]; + /* 40 - generator type string, 40 - space for long integer */ + } RNMATHglobal; + + /* Union parameter structure for all generators. */ + /* So that we have one structure for all, and a single destructor function */ + /* We can't get around the need for multiple constructors for the different */ + /* generators */ + + static void + RNMATHglobalFree (ClientData cd, Tcl_Interp* interp) + { + ckfree((char*) cd); + } + + static char* + AutoName (Tcl_Interp* interp, char* rtype) + { +#define KEY "package/random" + + Tcl_InterpDeleteProc* proc = RNMATHglobalFree; + RNMATHglobal* rnmathglobal; + + rnmathglobal = Tcl_GetAssocData (interp, KEY, &proc); + if (rnmathglobal == NULL) { + rnmathglobal = (RNMATHglobal*) ckalloc (sizeof (RNMATHglobal)); + rnmathglobal->counter = 0; + + Tcl_SetAssocData (interp, KEY, proc, + (ClientData) rnmathglobal); + } + + rnmathglobal->counter ++; + sprintf (rnmathglobal->buf, PREFIX "%s%d", rtype, rnmathglobal->counter); + return rnmathglobal->buf; + +#undef KEY + } + + static void + RNMATHdeleteCmd (ClientData clientData) + { + /* Release the generator parameters */ + ckfree ((char*) clientData); + } + + static RNMATHparam* + RNMATHnewCmd (Tcl_Interp* interp, char* rtype, char* name, Tcl_ObjCmdProc p) + { + Tcl_Obj* fqn; + Tcl_CmdInfo ci; + RNMATHparam* rnmathp; + + if (!name) { + name = AutoName (interp, rtype); + } + + if (!Tcl_StringMatch (name, "::*")) { + /* Relative name. Prefix with current namespace */ + + Tcl_Eval (interp, "namespace current"); + fqn = Tcl_GetObjResult (interp); + fqn = Tcl_DuplicateObj (fqn); + Tcl_IncrRefCount (fqn); + + if (!Tcl_StringMatch (Tcl_GetString (fqn), "::")) { + Tcl_AppendToObj (fqn, "::", -1); + } + Tcl_AppendToObj (fqn, name, -1); + } else { + fqn = Tcl_NewStringObj (name, -1); + Tcl_IncrRefCount (fqn); + } + Tcl_ResetResult (interp); + + if (Tcl_GetCommandInfo (interp, + Tcl_GetString (fqn), + &ci)) { + Tcl_Obj* err; + + err = Tcl_NewObj (); + Tcl_AppendToObj (err, "command \"", -1); + Tcl_AppendObjToObj (err, fqn); + Tcl_AppendToObj (err, "\" already exists, unable to create generator", -1); + + Tcl_DecrRefCount (fqn); + Tcl_SetObjResult (interp, err); + return NULL; + } + + rnmathp = (RNMATHparam*) ckalloc (sizeof (RNMATHparam)); + + Tcl_CreateObjCommand (interp, Tcl_GetString (fqn), + p, (ClientData) rnmathp, + RNMATHdeleteCmd); + + Tcl_SetObjResult (interp, fqn); + Tcl_DecrRefCount (fqn); + + return rnmathp; + } + + static double + RANDOM (void) + { + return random () / 2147483647.0; + } +} + +# # ## ### ##### ######## ############# ##################### +## Genereate generators from the imported API. + +::random::wrap + +# # ## ### ##### ######## ############# ##################### +## Finalization; drop helper commands, and provide the package. + +unset ::random::T +rename ::random::cap {} +rename ::random::indent {} +rename ::random::genclass {} +rename ::random::wrap {} + +package provide random 1 +return diff --git a/src/vfs/critcl.vfs/examples/random/rnmath.tcl b/src/vfs/critcl.vfs/examples/random/rnmath.tcl new file mode 100644 index 00000000..930be5bf --- /dev/null +++ b/src/vfs/critcl.vfs/examples/random/rnmath.tcl @@ -0,0 +1,375 @@ +# -*- tcl -*- (critcl actually, Tcl + embedded C) +# rnmath.tcl -- +# +# Low-level functions for the generation of random numbers +# following various distributions (Poisson, Gaussian/Normal, +# etc.). +# +# Math pulled out of and derived from tcllib/modules/simulation/random.tcl +# Copyright (c) 2007 by Arjen Markus +# Note: +# Several formulae and algorithms come from "Monte Carlo Simulation" +# by C. Mooney (Sage Publications, 1997) +# +# Critcl code generation and setup +# Copyright (c) 2011,2022 by Andreas Kupries +# +# Example of how to EXPORT a C-level stubs API through critcl v3. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Configuration + +critcl::license \ + {Arjen Markus, Andreas Kupries} \ + {BSD licensed.} + +critcl::summary {C-level functions for the generation of random numbers.} + +critcl::description { + This package implements functions for the generation + of random values following various known probability + distribution. No Tcl-binding is provided. See package + 'random' for that. +} + +critcl::subject {random numbers} +# plus the distributions, see inside of 'generator' + +# # ## ### ##### ######## ############# ##################### +## Code generation helper command converting a simple RNG declaration +## into the necessary C code. + +proc generator {name parameters body rtypes} { + # Generator results are returned through pointer arguments coming + # after the generator parameters. + foreach {t r} $rtypes { + lappend parameters ${t}* $r + } + + set fname rnmath_$name + set cparameters [join [critcl::argcsignature $parameters] {, }] + + # Low-level math function generating the numbers. + + lappend map @fname@ $fname + lappend map @param@ $cparameters + lappend map @body@ $body + critcl::ccode [string map $map {void @fname@ (@param@) {@body@}}] + + # Exported through a stubs table. + critcl::api function void $fname $parameters + + # Extend the meta data. + critcl::subject "$name probability distribution" + critcl::subject "probability distribution $name" + critcl::subject "distribution $name" + return +} + +# # ## ### ##### ######## ############# ##################### +## Intro and shared/common/fixed code. + +critcl::ccode { + /* -*- c -*- */ + +#include + +#ifndef M_PI +#define M_PI (3.141592653589793238462643) +#endif + + static double + RANDOM (void) + { + /* Random numbers in range [0,1) */ +#ifdef WIN32 + return ((unsigned int) rand ()) / 2147483648.0; +#else + return ((unsigned long) random ()) / 2147483648.0; +#endif + } +} + +# # ## ### ##### ######## ############# ##################### +## Generators ... + +# Bernoulli -- +# Produce random numbers with a Bernoulli distribution +# +# Arguments: +# p Probability that the outcome will be 1 +# +# Result: +# Name of a procedure that returns a Bernoulli-distributed random number +# + +generator bernoulli {double p} { + *v = (RANDOM () < p) ? 1 : 0; +} {int v} + +# Uniform -- +# Produce random numbers with a uniform distribution in a given range +# +# Arguments: +# min Minimum value +# max Maximum value +# +# Result: +# Name of a procedure that returns a uniformly distributed +# random number +# + +generator uniform {double min double max} { + *v = min + (max-min) * RANDOM (); +} {double v} + +# Exponential -- +# Produce random numbers with an exponential distribution with given mean +# +# Arguments: +# min Minimum value +# mean Mean value +# +# Result: +# Name of a procedure that returns an exponentially distributed +# random number +# + +generator exponential {double min double mean} { + *v = min + (mean-min)*log(RANDOM ()); +} {double v} + +# Discrete -- +# Produce random numbers with a uniform but discrete distribution +# +# Arguments: +# n Outcome is an integer between 0 and n-1 +# +# Result: +# Name of a procedure that returns such a random number +# + +generator discrete {int n} { + *v = (int) (n*RANDOM ()); +} {int v} + +# Poisson -- +# Produce random numbers with a Poisson distribution +# +# Arguments: +# lambda The one parameter of the Poisson distribution +# +# Result: +# Name of a procedure that returns such a random number +# + +generator poisson {double lambda} { + double r = RANDOM (); + int number = 0; + double sum = exp(-lambda); + double rfactor = sum; + + while (r > sum) { + rfactor *= lambda / (number + 1); + sum += rfactor; + number ++; + } + + *v = number; +} {int v} + +# Normal -- +# Produce random numbers with a normal distribution +# +# Arguments: +# mean Mean of the distribution +# stdev Standard deviation of the distribution +# +# Result: +# Name of a procedure that returns such a random number +# +# Note: +# Use the Box-Mueller method to generate a normal random number +# + +generator normal {double mean double sigma} { + /* Note: RANDOM () in [0,1); log < 0 for that interval */ + double rad = sqrt (-2 * log (RANDOM ())); + double phi = 2 * M_PI * RANDOM (); + double r = rad * cos (phi); + + *v = mean + r*sigma; +} {double v} + +# Pareto -- +# Produce random numbers with a Pareto distribution +# +# Arguments: +# min Minimum value for the distribution +# steep Steepness of the descent (> 0!) +# +# Result: +# Name of a procedure that returns a Pareto-distributed number +# + +generator pareto {double min double steepness} { + *v = min * pow (1. - RANDOM (), 1./steepness); +} {double v} + +# Gumbel -- +# Produce random numbers with a Gumbel distribution +# +# Arguments: +# min Minimum value for the distribution +# f Factor to scale the value +# +# Result: +# Name of a procedure that returns a Gumbel-distributed number +# +# Note: +# The chance P(v) = exp( -exp( f*(v-min) ) ) +# + +generator gumbel {double min double f} { + *v = min + log ( -log (1. - RANDOM ()) / f); +} {double v} + +# chiSquared -- +# Produce random numbers with a chi-squared distribution +# +# Arguments: +# df Degrees of freedom +# +# Result: +# Name of a procedure that returns a chi-squared distributed number +# with mean 0 and standard deviation 1 +# + +generator chisquared {int df} { + double y = 0; + int i; + + for (i = 0; i < df; i++) { + double rad = sqrt (-log (RANDOM ())); + double phi = 2 * M_PI * RANDOM (); + double r = rad * cos (phi); + /* So far like a normal distribution */ + y += r * r; + } + + /* http://www.dsplog.com/2008/07/28/chi-square-random-variable/ */ + + *v = (y - df)/sqrt (2*df); +} {double v} + +# Disk -- +# Produce random numbers with a uniform distribution of points on a disk +# +# Arguments: +# rad Radius of the disk +# +# Result: +# Name of a procedure that returns the x- and y-coordinates of +# such a random point +# + +generator disk {double radius} { + double rad = radius * sqrt (RANDOM ()); + double phi = 2 * M_PI * RANDOM (); + + *x = rad * cos (phi); + *y = rad * sin (phi); +} {double x double y} + +# Ball -- +# Produce random numbers with a uniform distribution of points within a ball +# +# Arguments: +# rad Radius of the ball +# +# Result: +# Name of a procedure that returns the x-, y- and z-coordinates of +# such a random point +# + +generator ball {double radius} { + double rad = radius * pow (RANDOM (), 1./3.); + double phi = 2 * M_PI * RANDOM (); + double theta = acos ( 2 * RANDOM () - 1); + + *x = rad * cos (phi) * cos (theta); + *y = rad * sin (phi) * cos (theta); + *z = rad * sin (theta); +} {double x double y double z} + +# Sphere -- +# Produce random numbers with a uniform distribution of points on the surface +# of a sphere +# +# Arguments: +# rad Radius of the sphere +# +# Result: +# Name of a procedure that returns the x-, y- and z-coordinates of +# such a random point +# + +generator sphere {double radius} { + double phi = 2 * M_PI * RANDOM (); + double theta = acos ( 2 * RANDOM () - 1); + + *x = radius * cos (phi) * cos (theta); + *y = radius * sin (phi) * cos (theta); + *z = radius * sin (theta); +} {double x double y double z} + +# Rectangle -- +# Produce random numbers with a uniform distribution of points in a rectangle +# +# Arguments: +# length Length of the rectangle (x-direction) +# width Width of the rectangle (y-direction) +# +# Result: +# Name of a procedure that returns the x- and y-coordinates of +# such a random point +# + +generator rectangle {double length double width} { + *x = length * RANDOM (); + *y = width * RANDOM (); +} {double x double y} + +# Block -- +# Produce random numbers with a uniform distribution of points in a block +# +# Arguments: +# length Length of the block (x-direction) +# width Width of the block (y-direction) +# depth Depth of the block (y-direction) +# +# Result: +# Name of a procedure that returns the x-, y- and z-coordinates of +# such a random point +# + +generator block {double length double width double depth} { + *x = length * RANDOM (); + *y = width * RANDOM (); + *z = depth * RANDOM (); +} {double x double y double z} + + +# # ## ### ##### ######## ############# ##################### +## Finalization; drop the helper command, and provide the package. + +rename generator {} + +package provide rnmath 1 +return diff --git a/src/vfs/critcl.vfs/examples/selfcompanion/build.tcl b/src/vfs/critcl.vfs/examples/selfcompanion/build.tcl new file mode 100644 index 00000000..d12c1544 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/selfcompanion/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {selfcompanion} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/selfcompanion/cr.tcl b/src/vfs/critcl.vfs/examples/selfcompanion/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/selfcompanion/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/selfcompanion/example.tcl b/src/vfs/critcl.vfs/examples/selfcompanion/example.tcl new file mode 100644 index 00000000..c316ac3c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/selfcompanion/example.tcl @@ -0,0 +1,3 @@ + +ex self +ex companion diff --git a/src/vfs/critcl.vfs/examples/selfcompanion/selfcompanion.tcl b/src/vfs/critcl.vfs/examples/selfcompanion/selfcompanion.tcl new file mode 100644 index 00000000..7c03353d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/selfcompanion/selfcompanion.tcl @@ -0,0 +1,76 @@ +# selfcompanion.tcl -- +# +# A template demonstrating how to distribute the critcl file +# as its own Tcl companion file. +# +# This is not really the recommended way of handling Tcl +# companion code, however as critcl 2 supported this, and v3 is +# still supporting it, an example might still be in order. +# +# One issue this causes is a dependency on critcl itself in the +# generated package. Whereas if the Tcl code to distribute is +# properly split off into a separate companion file such a +# dependency can be avoided. +# +# Copyright (c) 2011,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Define the Tcl companion code. This is done always, as we +## might be in mode 'build & run'. + +proc companion {} { + return [self] +} + +# # ## ### ##### ######## ############# ##################### +## Determine the environment, and define/build the C parts only +## if not noted as build already. + +#puts Compiled=[critcl::compiled] + +if {[critcl::compiled]} return + +#critcl::msg "Declaring, building C parts" + +#puts Compiling=[critcl::compiling] + +if {![critcl::compiling]} { + return -code error "Unable to build the C parts of selfcompanion" +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Demonstration of using the critcl file as its own Tcl companion} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to setup and distribute + the critcl file as its own Tcl companion file. +} + +critcl::subject template demonstration self-companion + +# # ## ### ##### ######## ############# ##################### +## Configuration, setup as its own Tcl companion file. + +critcl::tsources [info script] + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::cdata self "me" + +# ... And other parts of the C level ... + +# ### ### ### ######### ######### ######### +## Ready +package provide selfcompanion 1 diff --git a/src/vfs/critcl.vfs/examples/stack/README.txt b/src/vfs/critcl.vfs/examples/stack/README.txt new file mode 100644 index 00000000..c434d1a3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/README.txt @@ -0,0 +1,32 @@ +Example of critcl-based packages. + +A larger example written to demonstrate + + Export of an API as Tcl stubs table (Package "cstack") + Import of an API defined as stubs-table (Package "stackc") + + Easy writing of C classes, with class and instances + represented as commands, through the utility package + critcl::class + +Package "cstack" also demonstrate the export of a companion header +file containing declarations of package specific data structures and +macros which are not expressible in the basic .decls file and header +derived from it, plus, incidentally, the separation of public and +internal headers. + +Package "stackc" incidentially also demonstrates the use of companion +.c and .h files in the implementation of a package. + +Sources + Package "cstack": cstack.tcl, cstack.c, cstack.h, cstackInt.h + Package "stackc": stackc.tcl, stackc/*.[ch] + +Notes: + +* "cstack" implements an abstract stack data type and exports + a C-level API for it, as a stubs table. + +* "stackc" wraps the abstract stack data type of "cstack" into + a Tcl class/object system where stacks are objects, each + represented as a Tcl command. diff --git a/src/vfs/critcl.vfs/examples/stack/build.tcl b/src/vfs/critcl.vfs/examples/stack/build.tcl new file mode 100644 index 00000000..53842338 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/build.tcl @@ -0,0 +1,289 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +# Order of building and installation: "cstack", then "stackc", as the +# latter depends on the former. Not relevant for wrap4tea. +set packages {cstack stackc} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall all packages, build for debugging.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -keep -debug symbols -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/stack/cstack.c b/src/vfs/critcl.vfs/examples/stack/cstack.c new file mode 100644 index 00000000..2d106129 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/cstack.c @@ -0,0 +1,206 @@ +#include "cstackInt.h" + +/* + * = = == === ===== ======== ============= ===================== + */ + +CSTACK +cstack_new (CSTACK_CELL_FREE freeCell, void* clientdata) +{ + CSTACK s = ALLOC (CSTACK_); + s->cell = NALLOC (CSTACK_INITIAL_SIZE, void*); + s->max = CSTACK_INITIAL_SIZE; + s->top = 0; + s->freeCell = freeCell; + s->clientData = clientdata; + + return s; +} + +void +cstack_del (CSTACK s) +{ + if (s->freeCell && s->top) { + long int i; + for (i=0; i < s->top; i++) { + ASSERT_BOUNDS(i,s->max); + s->freeCell ( s->cell [i] ); + } + } + + ckfree ((char*) s->cell); + ckfree ((char*) s); +} + +void +cstack_push (CSTACK s, void* item) +{ + if (s->top >= s->max) { + long int new = s->max ? (2 * s->max) : CSTACK_INITIAL_SIZE; + void** cell = (void**) ckrealloc ((char*) s->cell, new * sizeof(void*)); + ASSERT (cell,"Memory allocation failure for cstack"); + s->max = new; + s->cell = cell; + } + + ASSERT_BOUNDS(s->top,s->max); + s->cell [s->top] = item; + s->top ++; +} + +void* +cstack_top (CSTACK s) +{ + ASSERT_BOUNDS(s->top-1,s->max); + return s->cell [s->top - 1]; +} + +void +cstack_pop (CSTACK s, long int n) +{ + ASSERT (n >= 0, "Bad pop count"); + if (n == 0) return; + + if (s->freeCell) { + while (n) { + s->top --; + ASSERT_BOUNDS(s->top,s->max); + s->freeCell ( s->cell [s->top] ); + n --; + } + } else { + s->top -= n; + } +} + +void +cstack_trim (CSTACK s, long int n) +{ + ASSERT (n >= 0, "Bad trimsize"); + + if (s->freeCell) { + while (s->top > n) { + s->top --; + ASSERT_BOUNDS(s->top,s->max); + s->freeCell ( s->cell [s->top] ); + } + } else { + s->top = n; + } +} + +void +cstack_drop (CSTACK s, long int n) +{ + ASSERT (n >= 0, "Bad pop count"); + if (n == 0) return; + s->top -= n; +} + +void +cstack_move (CSTACK dst, CSTACK src) +{ + ASSERT (dst->freeCell == src->freeCell, "Ownership mismatch"); + + /* + * Note: The destination takes ownership of the moved cell, thus there is + * no need to run free on them. + */ + + while (src->top > 0) { + src->top --; + ASSERT_BOUNDS(src->top,src->max); + cstack_push (dst, src->cell [src->top] ); + } +} + +void +cstack_get (CSTACK s, long int n, CSTACK_DIRECTION dir, CSTACK_SLICE* slice) +{ + ASSERT (n <= s->top, "Not enough elements in the cstack"); + + /* + * Note the double negation below. To get the normal order of the result, + * the order has to be reversed. To get the reverted order, nothing is to + * be done. So we revers on dir == cstack_normal. + * + * As optimization we know that direction is irrrelevant when returning a + * single element and thus we can use the code path not doing any + * allocations. + */ + + if ((dir == cstack_revers) || (n < 2)) { + slice->dynamic = 0; + slice->cell = s->cell + (s->top - n); + } else { + int i; + + slice->dynamic = 1; + slice->cell = NALLOC (n, void*); + + for (i=0; itop-i-1,s->top); + slice->cell [i] = s->cell [s->top-i-1]; + } + } +} + +void +cstack_rol (CSTACK s, long int n, long int steps) +{ + long int i, j, start = s->top - n; + void** cell = s->cell; + void** tmp; + + steps = steps % n; + while (steps < 0) steps += n; + steps = n - steps; + cell += start; + + tmp = NALLOC(n,void*); + + for (i = 0; i < n; i++) { + j = (i + steps) % n; + ASSERT_BOUNDS (i,n); + ASSERT_BOUNDS (j,n); + tmp[i] = cell [j]; + } + for (i = 0; i < n; i++) { + ASSERT_BOUNDS (i,n); + cell [i] = tmp [i]; + } + + ckfree ((char*) tmp); +} + +long int +cstack_size (CSTACK s) +{ + return s->top; +} + +void +cstack_clientdata_set (CSTACK s, void* clientdata) +{ + s->clientData = clientdata; +} + +void* +cstack_clientdata_get (CSTACK s) +{ + return s->clientData; +} + +/* + * = = == === ===== ======== ============= ===================== + */ + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/stack/cstack.h b/src/vfs/critcl.vfs/examples/stack/cstack.h new file mode 100644 index 00000000..1501806e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/cstack.h @@ -0,0 +1,55 @@ +#ifndef CSTACK_H +#define CSTACK_H 1 + +/* + * Forward declaration of stacks (opaque handle). + */ + +typedef struct CSTACK_* CSTACK; + +/* + * Stacks are conceptually an array of void* cells, with each cell + * either directly containing the data, or a pointer to it. + * + * To handle the latter a pointer to a per-cell delete function is + * maintained, enabling the stack code to delete cells which are + * pointers to the actual data. + * + * Note however that the allocation of cell data is the responsibility + * of the stack's user. + */ + +typedef void (*CSTACK_CELL_FREE) (void* cell); + +/* + * Data structure filled by 'stack_get'. The pointer to the cells may be + * allocated on the heap, or not. If it is allocated the flag 'dynamic' is set + * to true, and false otherwise. + */ + +typedef struct CSTACK_SLICE_ { + void** cell; + int dynamic; +} CSTACK_SLICE; + +#define cstack_slice_cleanup(slice) \ + if ((slice).dynamic) { ckfree ((char*) (slice).cell); } + +/* + * Cue to 'cstack_get' where to put the top element of the stack in the returned slice. + */ + +typedef enum { + cstack_normal, /* cstack_get returns the slice with top-element at left/beginning */ + cstack_revers /* cstack_get returns the slice with top-element at right/end */ +} CSTACK_DIRECTION; + +#endif /* CSTACK_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/stack/cstack.tcl b/src/vfs/critcl.vfs/examples/stack/cstack.tcl new file mode 100644 index 00000000..28b1eba8 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/cstack.tcl @@ -0,0 +1,83 @@ +# cstack.tcl -- +# +# Low-level stack data structure. With wrapping usable as +# a Tcl-level stack. +# +# Copyright (c) 2008-2011,2022 Andreas Kupries + +# Example of exporting a C-level stubs API through critcl v3, with a +# package header file containing public type definitions, macros, +# etc., and internal C companion files. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {A C-level abstract datatype for stacks} + +critcl::description { + This package implements an abstract + data type for stacks, at the C-level. + No Tcl-binding is provided. See package + 'stackc' for that. +} + +critcl::subject stack +critcl::subject {data structure} +critcl::subject structure +critcl::subject {abstract data structure} +critcl::subject {generic data structure} + +# # ## ### ##### ######## ############# ##################### +## Configuration + +critcl::api header cstack.h +critcl::cheaders cstackInt.h + +# # ## ### ##### ######## ############# ##################### +## Exported API + +# +# Notes +# - push -- Item allocation is responsibility of caller. +# Stack takes ownership of the item. +# - pop -- Stack frees allocated item. +# - trim -- Ditto +# - top -- Provides top item, no transfer of ownership. +# - del -- Releases stack, cell array, and items, if any. +# - drop -- Like pop, but doesn't free, assumes that caller +# is taking ownership of the pointer. +# + +critcl::api function CSTACK cstack_new {CSTACK_CELL_FREE freeCell void* clientdata} +critcl::api function void cstack_del {CSTACK s} + +critcl::api function {long int} cstack_size {CSTACK s} +critcl::api function void* cstack_top {CSTACK s} +critcl::api function void cstack_push {CSTACK s void* item} +critcl::api function void cstack_pop {CSTACK s {long int} n} +critcl::api function void cstack_trim {CSTACK s {long int} n} +critcl::api function void cstack_drop {CSTACK s {long int} n} +critcl::api function void cstack_rol {CSTACK s {long int} n {long int} step} +critcl::api function void cstack_get {CSTACK s {long int} n CSTACK_DIRECTION dir CSTACK_SLICE* slice} +critcl::api function void cstack_move {CSTACK s CSTACK src} + +critcl::api function void cstack_clientdata_set {CSTACK s void* clientdata} +critcl::api function void* cstack_clientdata_get {CSTACK s} + +# # ## ### ##### ######## ############# ##################### +## Implementation. + +critcl::csources cstack.c +critcl::ccode {} ; # Fake the 'nothing to build detector' + +# ### ### ### ######### ######### ######### +## Ready +package provide cstack 1 diff --git a/src/vfs/critcl.vfs/examples/stack/cstackInt.h b/src/vfs/critcl.vfs/examples/stack/cstackInt.h new file mode 100644 index 00000000..a408c173 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/cstackInt.h @@ -0,0 +1,63 @@ +#ifndef CSTACK_INT_H +#define CSTACK_INT_H 1 + +#include "cstack/cstackDecls.h" + +/* + * Waste a bit of space (1K) on each new stack to reduce the amount of + * reallocation going on for most stacks, which should be small. + */ + +static const int CSTACK_INITIAL_SIZE = 256; + +/* + * Actual type of the stack data structure. Used only inside of the + * package. + */ + +typedef struct CSTACK_ { + long int max; /* Size of the cell array. */ + long int top; /* Index of the topmost _unused_ cell in the + * array === Index of the _next_ cell to use + * === Size of the stack. */ + CSTACK_CELL_FREE freeCell; + void* clientData; + + void** cell; /* Array of the stack cells. */ +} CSTACK_; + +/* + * Allocation macros for common situations. + */ + +#define ALLOC(type) (type *) ckalloc (sizeof (type)) +#define NALLOC(n,type) (type *) ckalloc ((n) * sizeof (type)) + +/* + * Assertions in general, and asserting the proper range of an array + * index. + */ + +#undef CSTACK_DEBUG +#define CSTACK_DEBUG 1 + +#ifdef CSTACK_DEBUG +#define XSTR(x) #x +#define STR(x) XSTR(x) +#define RANGEOK(i,n) ((0 <= (i)) && (i < (n))) +#define ASSERT(x,msg) if (!(x)) { Tcl_Panic (msg " (" #x "), in file " __FILE__ " @line " STR(__LINE__));} +#define ASSERT_BOUNDS(i,n) ASSERT (RANGEOK(i,n),"array index out of bounds: " STR(i) " > " STR(n)) +#else +#define ASSERT(x,msg) +#define ASSERT_BOUNDS(i,n) +#endif + +#endif /* CSTACK_INT_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/stack/stackc.tcl b/src/vfs/critcl.vfs/examples/stack/stackc.tcl new file mode 100644 index 00000000..0df3dab3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/stackc.tcl @@ -0,0 +1,93 @@ +# stackc.tcl -- +# +# Implementation of a stack data structure for Tcl. +# This code based on critcl v3.1, API compatible to the PTI [x]. +# [x] Pure Tcl Implementation. +# +# Demonstrates not just the stubs import and meta data declaration, +# but also the utility package for the creation of classes and objects +# in C, with both claaes and their instances represented as Tcl +# commands. +# +# Copyright (c) 2012,2022 Andreas Kupries +# +# 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.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::class ; # DSL, easy spec of Tcl class/object commands. +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} {BSD licensed} + +critcl::summary {Stack objects for Tcl.} + +critcl::description { + This package implements stack objects + for Tcl. It uses the abstract data type + provided by package 'cstack' for actual + storage and operations. +} + +critcl::subject stack +critcl::subject {data structure} +critcl::subject structure +critcl::subject {abstract data structure} +critcl::subject {generic data structure} + +# # ## ### ##### ######## ############# ##################### +## Configuration and implementation. + +critcl::api import cstack 1 + +critcl::cheaders stackc/*.h ; # Method declarations and implementation, +critcl::csources stackc/*.c ; # outside of this main file. + +critcl::class::define ::stackc { + include m.h ; # Method function declarations. + include cstack/cstackDecls.h ; # API of the generic CSTACK we are binding to. + type CSTACK + + constructor { + instance = cstack_new (StackcFreeCell, 0); + } { + /* Set back reference from CSTACK instance to instance command */ + cstack_clientdata_set (instance, (ClientData) cmd); + } + + destructor { + /* Release the whole stack. */ + cstack_del (instance); + } + + method clear as stm_CLEAR + method destroy as stm_DESTROY + method peek as stm_PEEK 0 0 + method peekr as stm_PEEK 0 1 + method pop as stm_PEEK 1 0 + method push as stm_PUSH + method rotate as stm_ROTATE + method size as stm_SIZE + method get as stm_GET 0 + method getr as stm_GET 1 + method trim as stm_TRIM 1 + method trimv as stm_TRIM 0 + + support { + static void + StackcFreeCell (void* cell) { + /* Release the cell. */ + Tcl_DecrRefCount ((Tcl_Obj*) cell); + } + } +} + +# ### ### ### ######### ######### ######### +## Ready +package provide stackc 1 diff --git a/src/vfs/critcl.vfs/examples/stack/stackc/m.c b/src/vfs/critcl.vfs/examples/stack/stackc/m.c new file mode 100644 index 00000000..e97e7334 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/stackc/m.c @@ -0,0 +1,372 @@ +/* ::stack - critcl - layer 3 definitions. + * + * -> Method functions. + * Implementations for all stack methods. + */ + +#include "util.h" +#include "m.h" + +/* .................................................. */ + +/* + *--------------------------------------------------------------------------- + * + * stm_CLEAR -- + * + * Removes all elements currently on the stack. I.e empties the stack. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Only internal, memory allocation changes ... + * + *--------------------------------------------------------------------------- + */ + +int +stm_CLEAR (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: stack clear + * [0] [1] + */ + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 2, objv, NULL); + return TCL_ERROR; + } + + cstack_pop (s, cstack_size (s)); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_DESTROY -- + * + * Destroys the whole stack object. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Releases memory. + * + *--------------------------------------------------------------------------- + */ + +int +stm_DESTROY (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: stack destroy + * [0] [1] + */ + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 2, objv, NULL); + return TCL_ERROR; + } + + Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cstack_clientdata_get (s)); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_GET -- + * + * Non-destructively retrieves all elements of the stack. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Only internal, memory allocation changes ... + * + *--------------------------------------------------------------------------- + */ + +int +stm_GET (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv, int revers) +{ + /* Syntax: stack get + * [0] [1] + */ + + long int n; + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 2, objv, NULL); + return TCL_ERROR; + } + + n = cstack_size (s); + + if (!n) { + Tcl_SetObjResult (interp, Tcl_NewListObj (0,NULL)); + } else { + CSTACK_SLICE sl; + + cstack_get (s, n, (CSTACK_DIRECTION) revers, &sl); + Tcl_SetObjResult (interp, Tcl_NewListObj (n, (Tcl_Obj**) sl.cell)); + cstack_slice_cleanup (sl); + } + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_TRIM -- + * + * Destructively retrieves one or more elements from the top of the + * stack, trims the stack to a new size. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Only internal, memory allocation changes ... + * + *--------------------------------------------------------------------------- + */ + +int +stm_TRIM (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv, int ret) +{ + /* Syntax: stack trim N + * [0] [1] [2] + */ + + int n, len; + + if (objc != 3) { + Tcl_WrongNumArgs (interp, 2, objv, "newsize"); + return TCL_ERROR; + } + + if (Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_OK) { + return TCL_ERROR; + } else if (n < 0) { + Tcl_AppendResult (interp, "invalid size ", + Tcl_GetString (objv[2]), + NULL); + return TCL_ERROR; + } + + len = cstack_size (s); + + if (len <= n) { + Tcl_SetObjResult (interp, Tcl_NewListObj (0,NULL)); + } else { + if (ret) { + CSTACK_SLICE sl; + + cstack_get (s, len-n, cstack_normal, &sl); + + Tcl_SetObjResult (interp, Tcl_NewListObj (len-n, (Tcl_Obj**) sl.cell)); + + cstack_slice_cleanup (sl); + } + cstack_trim (s, n); + } + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_PEEK/POP -- + * + * (Non-)destructively retrieves one or more elements from the top of the + * stack. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Only internal, memory allocation changes ... + * + *--------------------------------------------------------------------------- + */ + +int +stm_PEEK (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv, int pop, int revers) +{ + /* Syntax: stack peek|pop ?n? + * [0] [1] [2] + */ + + int n = 1; + + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs (interp, 2, objv, "?n?"); + return TCL_ERROR; + } + + if (objc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_OK) { + return TCL_ERROR; + } else if (n < 1) { + Tcl_AppendResult (interp, "invalid item count ", + Tcl_GetString (objv[2]), + NULL); + return TCL_ERROR; + } + } + + if (n > cstack_size (s)) { + Tcl_AppendResult (interp, + "insufficient items on stack to fill request", + NULL); + return TCL_ERROR; + } else { + CSTACK_SLICE sl; + + cstack_get (s, n, (CSTACK_DIRECTION) revers, &sl); + + if (n == 1) { + Tcl_SetObjResult (interp, (Tcl_Obj*) sl.cell[0]); + } else { + Tcl_SetObjResult (interp, Tcl_NewListObj (n, (Tcl_Obj**) sl.cell)); + } + + cstack_slice_cleanup (sl); + + if (pop) { + cstack_pop (s, n); + } + } + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_PUSH -- + * + * Adds one or more elements to the stack. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +stm_PUSH (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: stack push item... + * [0] [1] [2] + */ + + int i; + + if (objc < 3) { + Tcl_WrongNumArgs (interp, 2, objv, "item ?item ...?"); + return TCL_ERROR; + } + + for (i = 2; i < objc; i++) { + cstack_push (s, objv[i]); + Tcl_IncrRefCount (objv[i]); + } + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_ROTATE -- + * + * Rotates the N top elements of the stack by K steps. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +stm_ROTATE (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: stack rotate count steps + * [0] [1] [2] [3] + */ + + int n, steps; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "count steps"); + return TCL_ERROR; + } + + if (Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_OK) { + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[3], &steps) != TCL_OK) { + return TCL_ERROR; + } + + if (n > cstack_size (s)) { + Tcl_AppendResult (interp, "insufficient items on stack to fill request", + NULL); + return TCL_ERROR; + } + + cstack_rol (s, n, steps); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * stm_SIZE -- + * + * Returns the number of elements currently held by the stack. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +stm_SIZE (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: stack size + * [0] [1] + */ + + if ((objc != 2)) { + Tcl_WrongNumArgs (interp, 2, objv, NULL); + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, Tcl_NewIntObj (cstack_size (s))); + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/stack/stackc/m.h b/src/vfs/critcl.vfs/examples/stack/stackc/m.h new file mode 100644 index 00000000..dd842dd5 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/stackc/m.h @@ -0,0 +1,28 @@ +/* ::stack - critcl - layer 3 declarations + * Method functions. + */ + +#ifndef _M_H +#define _M_H 1 + +#include "tcl.h" +#include + +int stm_CLEAR (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv); +int stm_DESTROY (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv); +int stm_PEEK (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv, int pop, int revers); +int stm_PUSH (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv); +int stm_ROTATE (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv); +int stm_SIZE (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv); +int stm_GET (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv, int revers); +int stm_TRIM (CSTACK s, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv, int ret); + +#endif /* _M_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/stack/stackc/util.h b/src/vfs/critcl.vfs/examples/stack/stackc/util.h new file mode 100644 index 00000000..380c2f9c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/stack/stackc/util.h @@ -0,0 +1,41 @@ +/* stackc - critcl - layer 0 declarations + * API general utilities + */ + +#ifndef _UTIL_H +#define _UTIL_H 1 + +#include + +/* Allocation macros for common situations. + */ + +#define ALLOC(type) (type *) ckalloc (sizeof (type)) +#define NALLOC(n,type) (type *) ckalloc ((n) * sizeof (type)) + +/* Assertions in general, and asserting the proper range of an array index. + */ + +#undef STACKC_DEBUG +#define STACKC_DEBUG 1 + +#ifdef STACKC_DEBUG +#define XSTR(x) #x +#define STR(x) XSTR(x) +#define RANGEOK(i,n) ((0 <= (i)) && (i < (n))) +#define ASSERT(x,msg) if (!(x)) { Tcl_Panic (msg " (" #x "), in file " __FILE__ " @line " STR(__LINE__));} +#define ASSERT_BOUNDS(i,n) ASSERT (RANGEOK(i,n),"array index out of bounds: " STR(i) " > " STR(n)) +#else +#define ASSERT(x,msg) +#define ASSERT_BOUNDS(i,n) +#endif + +#endif /* _UTIL_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/examples/tk8.4/build.tcl b/src/vfs/critcl.vfs/examples/tk8.4/build.tcl new file mode 100644 index 00000000..4209066f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.4/build.tcl @@ -0,0 +1,287 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {icounter} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall all packages, build for debugging.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -keep -debug symbols -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/tk8.4/cr.tcl b/src/vfs/critcl.vfs/examples/tk8.4/cr.tcl new file mode 100644 index 00000000..96fef714 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.4/cr.tcl @@ -0,0 +1,48 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +catch {puts [package ifneeded critcl::platform [package present critcl::platform]]} +catch {puts [package ifneeded platform [package present platform]]} + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/tk8.4/example.tcl b/src/vfs/critcl.vfs/examples/tk8.4/example.tcl new file mode 100644 index 00000000..db048941 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.4/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {icounter 4} + +ex icounter 0 +ex ::icounter -1 diff --git a/src/vfs/critcl.vfs/examples/tk8.4/icounter.tcl b/src/vfs/critcl.vfs/examples/tk8.4/icounter.tcl new file mode 100644 index 00000000..d61f5b63 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.4/icounter.tcl @@ -0,0 +1,47 @@ +# tk8.4.tcl -- +# +# Implementation of a counter associated an interpreter. +# This code based on critcl v3.1, API compatible to the PTI [x]. +# [x] Pure Tcl Implementation. +# +# Copyright (c) 2016,2022 Andreas Kupries +# +# 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.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::iassoc ; # Maintain an interpreter association. +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::tcl 8.4 +critcl::tk + +# # ## ### ##### ######## ############# ##################### +## Define and maintain the per-interp structure. + +critcl::iassoc::def icounter {int base} { + int counter; /* The counter variable */ +} { + data->counter = base; +} { + /* Nothing to release */ +} + +# # ## ### ##### ######## ############# ##################### +## Access and expose the per-interp structure to scripts. + +critcl::cproc icounter {Tcl_Interp* interp int base} int { + icounter_data d = icounter (interp, base); + d->counter ++; + return d->counter; +} + +# ### ### ### ######### ######### ######### +## Ready +package provide icounter 1 diff --git a/src/vfs/critcl.vfs/examples/tk8.5/build.tcl b/src/vfs/critcl.vfs/examples/tk8.5/build.tcl new file mode 100644 index 00000000..4209066f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.5/build.tcl @@ -0,0 +1,287 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {icounter} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall all packages, build for debugging.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -keep -debug symbols -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/tk8.5/cr.tcl b/src/vfs/critcl.vfs/examples/tk8.5/cr.tcl new file mode 100644 index 00000000..96fef714 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.5/cr.tcl @@ -0,0 +1,48 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +catch {puts [package ifneeded critcl::platform [package present critcl::platform]]} +catch {puts [package ifneeded platform [package present platform]]} + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/tk8.5/example.tcl b/src/vfs/critcl.vfs/examples/tk8.5/example.tcl new file mode 100644 index 00000000..db048941 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.5/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {icounter 4} + +ex icounter 0 +ex ::icounter -1 diff --git a/src/vfs/critcl.vfs/examples/tk8.5/icounter.tcl b/src/vfs/critcl.vfs/examples/tk8.5/icounter.tcl new file mode 100644 index 00000000..b88a9ab4 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.5/icounter.tcl @@ -0,0 +1,47 @@ +# tk8.5.tcl -- +# +# Implementation of a counter associated an interpreter. +# This code based on critcl v3.1, API compatible to the PTI [x]. +# [x] Pure Tcl Implementation. +# +# Copyright (c) 2016,2022 Andreas Kupries +# +# 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.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::iassoc ; # Maintain an interpreter association. +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::tcl 8.5 +critcl::tk + +# # ## ### ##### ######## ############# ##################### +## Define and maintain the per-interp structure. + +critcl::iassoc::def icounter {int base} { + int counter; /* The counter variable */ +} { + data->counter = base; +} { + /* Nothing to release */ +} + +# # ## ### ##### ######## ############# ##################### +## Access and expose the per-interp structure to scripts. + +critcl::cproc icounter {Tcl_Interp* interp int base} int { + icounter_data d = icounter (interp, base); + d->counter ++; + return d->counter; +} + +# ### ### ### ######### ######### ######### +## Ready +package provide icounter 1 diff --git a/src/vfs/critcl.vfs/examples/tk8.6/build.tcl b/src/vfs/critcl.vfs/examples/tk8.6/build.tcl new file mode 100644 index 00000000..4209066f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.6/build.tcl @@ -0,0 +1,287 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {icounter} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall all packages, build for debugging.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + puts "" + + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -keep -debug symbols -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/tk8.6/cr.tcl b/src/vfs/critcl.vfs/examples/tk8.6/cr.tcl new file mode 100644 index 00000000..96fef714 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.6/cr.tcl @@ -0,0 +1,48 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +catch {puts [package ifneeded critcl::platform [package present critcl::platform]]} +catch {puts [package ifneeded platform [package present platform]]} + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/tk8.6/example.tcl b/src/vfs/critcl.vfs/examples/tk8.6/example.tcl new file mode 100644 index 00000000..db048941 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.6/example.tcl @@ -0,0 +1,6 @@ + +# Force compile and load. +catch {icounter 4} + +ex icounter 0 +ex ::icounter -1 diff --git a/src/vfs/critcl.vfs/examples/tk8.6/icounter.tcl b/src/vfs/critcl.vfs/examples/tk8.6/icounter.tcl new file mode 100644 index 00000000..29cc4a22 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/tk8.6/icounter.tcl @@ -0,0 +1,47 @@ +# tk8.6.tcl -- +# +# Implementation of a counter associated an interpreter. +# This code based on critcl v3.1, API compatible to the PTI [x]. +# [x] Pure Tcl Implementation. +# +# Copyright (c) 2012,2022 Andreas Kupries +# +# 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.6 +package require critcl 3.2 + +critcl::buildrequirement { + package require critcl::iassoc ; # Maintain an interpreter association. +} + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::tcl 8.6 +critcl::tk + +# # ## ### ##### ######## ############# ##################### +## Define and maintain the per-interp structure. + +critcl::iassoc::def icounter {int base} { + int counter; /* The counter variable */ +} { + data->counter = base; +} { + /* Nothing to release */ +} + +# # ## ### ##### ######## ############# ##################### +## Access and expose the per-interp structure to scripts. + +critcl::cproc icounter {Tcl_Interp* interp int base} int { + icounter_data d = icounter (interp, base); + d->counter ++; + return d->counter; +} + +# ### ### ### ######### ######### ######### +## Ready +package provide icounter 1 diff --git a/src/vfs/critcl.vfs/examples/trace/build.tcl b/src/vfs/critcl.vfs/examples/trace/build.tcl new file mode 100644 index 00000000..cdd0f38f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/trace/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {pool} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -keep -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/trace/cr.tcl b/src/vfs/critcl.vfs/examples/trace/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/trace/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/trace/example.tcl b/src/vfs/critcl.vfs/examples/trace/example.tcl new file mode 100644 index 00000000..6273f5b0 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/trace/example.tcl @@ -0,0 +1,9 @@ + +# Force compile and load. +catch {str} + +ex str 1 +ex xstr 3 +ex moon +ex nothing +ex xstr sun diff --git a/src/vfs/critcl.vfs/examples/trace/pool.tcl b/src/vfs/critcl.vfs/examples/trace/pool.tcl new file mode 100644 index 00000000..cec3d02a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/trace/pool.tcl @@ -0,0 +1,65 @@ +# pool.tcl -- +# +# A template demonstrating the cproc/ccommand tracing facility. +# Built on top of the string pool demonstrator. +# +# Copyright (c) 2014,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 +package require critcl::literals 1.1 ;# result-type + +# Activate tracing code +critcl::config trace yes + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Tracing cproc, ccomands, etc} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to activate the builtin + tracing of cprocs, ccommands, etc. +} + +critcl::subject demonstration trace {narrative trace} debug + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" +} + +critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = demo (ip, code); + Tcl_IncrRefCount (res); + return res; +} + +critcl::cproc xstr {Tcl_Interp* ip int code} demo { + return code; +} + +critcl::cconst moon int 55 + +critcl::ccommand nothing {} { + /* Set nothing */ + return TCL_OK; +} + +# str 0 +# str 7 - panic, abort, core dump + +# ### ### ### ######### ######### ######### +## Ready +package provide pool 1 diff --git a/src/vfs/critcl.vfs/examples/variadic/build.tcl b/src/vfs/critcl.vfs/examples/variadic/build.tcl new file mode 100644 index 00000000..05c87e96 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/variadic/build.tcl @@ -0,0 +1,283 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {variadic} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\]." } +proc _install {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\]." } +proc _debug {{ldir {}}} { + global packages + if {[llength [info level 0]] < 2} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + critcl::app::main [list -cache [pwd]/BUILD.$p -keep -debug all -libdir $ldir -includedir $idir -pkg $src] + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/variadic/cr.tcl b/src/vfs/critcl.vfs/examples/variadic/cr.tcl new file mode 100644 index 00000000..3d3c180c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/variadic/cr.tcl @@ -0,0 +1,45 @@ +#!/usr/bin/env tclsh +# -*- tcl -*- +# Run the example via mode "compile & run". +# Note: generic code, same in all examples. + +cd [file dirname [file normalize [info script]]] +source ../../lib/critcl/critcl.tcl + +# Show the config +puts "" +puts "target-config: [critcl::targetconfig]" +puts "target-platform: [critcl::targetplatform]" +puts "target-actual: [critcl::actualtarget]" +puts "build-platform: [critcl::buildplatform]" +puts "cache: [critcl::cache]" +puts "" + +# Pull the package, ignoring build and examples ... +foreach f [glob *.tcl] { + if {[string match build* $f]} continue + if {[string match cr* $f]} continue + if {[string match example* $f]} continue + + puts "Reading $f ..." + source $f +} + +proc ex {args} { + set code [catch {uplevel 1 $args} result] + set code [string map {0 ok 1 error 2 break 3 continue} $code] + set max [expr {80 - [string length $args] - [string length "Example: "]}] + puts "Example: $args [string repeat _ $max]" + puts "Code: (($code))" + puts "Result: (($result))" + puts "" + return +} + +# ... and run the examples. +foreach f [glob -nocomplain example*] { + puts "Running $f ..." + source $f +} + +exit diff --git a/src/vfs/critcl.vfs/examples/variadic/example.tcl b/src/vfs/critcl.vfs/examples/variadic/example.tcl new file mode 100644 index 00000000..ad220d92 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/variadic/example.tcl @@ -0,0 +1,16 @@ +#!/usr/bin/env tclsh + +package require Tcl 8.5 +package require variadic + +foreach a { + {} + {6} + {6 7} + {6 7 8} + {6 7 8 9} + {6 7 8 9 0} +} { + ex variadic {*}$a + ex ovariadic {*}$a +} diff --git a/src/vfs/critcl.vfs/examples/variadic/variadic.tcl b/src/vfs/critcl.vfs/examples/variadic/variadic.tcl new file mode 100644 index 00000000..d0f53a11 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/variadic/variadic.tcl @@ -0,0 +1,48 @@ +# variadic.tcl -- +# +# A template demonstrating the handling of variadic arguments +# to cproc. +# +# Copyright (c) 2012,2022 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {Variadic arguments for cproc} + +critcl::description { + This package implements nothing. It serves only as a + demonstration and template on how to declare cproc's + with variadic arguments. +} + +critcl::subject demonstration {cproc variadic arguments} +#critcl::config lines 0 + +# # ## ### ##### ######## ############# ##################### +## C code. + +critcl::cproc variadic {int args} void { + int i; + for (i=0; i < args.c; i++) printf ("[%2d] = %d\n", i, args.v[i]); + fflush(stdout); +} + +critcl::cproc ovariadic {Tcl_Obj* args} void { + int i; + for (i=0; i < args.c; i++) printf ("[%2d] = '%s'\n", i, Tcl_GetString(args.v[i])); + fflush(stdout); +} + + +# ### ### ### ######### ######### ######### +## Ready +package provide variadic 1 diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/README.txt b/src/vfs/critcl.vfs/examples/zlibwrap/README.txt new file mode 100644 index 00000000..26174bae --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/README.txt @@ -0,0 +1,15 @@ +Example of critcl-based packages. + +A larger example written to demonstrate + + Export of an API from an external 3rd party library as Tcl stubs table. + Build switchability between + linking a system instance of the 3rd party library + and building a static library from local sources and + linking against this. + +Sources + Package "zlib": zlib.tcl + Local sources of C zlib: zlib/ + +Notes: diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/build.tcl b/src/vfs/critcl.vfs/examples/zlibwrap/build.tcl new file mode 100644 index 00000000..dabb3cfa --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/build.tcl @@ -0,0 +1,293 @@ +#!/bin/sh +# -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} +set me [file normalize [info script]] +set packages {zlib} +proc main {} { + global argv tcl_platform tag + set tag {} + if {![llength $argv]} { + if {$tcl_platform(platform) eq "windows"} { + set argv gui + } else { + set argv help + } + } + if {[catch { + eval _$argv + }]} usage + exit 0 +} +proc usage {{status 1}} { + global errorInfo + if {[info exists errorInfo] && ($errorInfo ne {}) && + ![string match {invalid command name "_*"*} $errorInfo] + } { + puts stderr $::errorInfo + exit + } + + global argv0 + set prefix "Usage: " + foreach c [lsort -dict [info commands _*]] { + set c [string range $c 1 end] + if {[catch { + H${c} + } res]} { + puts stderr "$prefix$argv0 $c args...\n" + } else { + puts stderr "$prefix$argv0 $c $res\n" + } + set prefix " " + } + exit $status +} +proc tag {t} { + global tag + set tag $t + return +} +proc myexit {} { + tag ok + puts DONE + return +} +proc log {args} { + global tag + set newline 1 + if {[lindex $args 0] eq "-nonewline"} { + set newline 0 + set args [lrange $args 1 end] + } + if {[llength $args] == 2} { + lassign $args chan text + if {$chan ni {stdout stderr}} { + ::_puts {*}[lrange [info level 0] 1 end] + return + } + } else { + set text [lindex $args 0] + set chan stdout + } + # chan <=> tag, if not overriden + if {[string match {Files left*} $text]} { + set tag warn + set text \n$text + } + if {$tag eq {}} { set tag $chan } + #::_puts $tag/$text + + .t insert end-1c $text $tag + set tag {} + if {$newline} { + .t insert end-1c \n + } + + update + return +} +proc +x {path} { + catch { file attributes $path -permissions u+x } + return +} +proc grep {file pattern} { + set lines [split [read [set chan [open $file r]]] \n] + close $chan + return [lsearch -all -inline -glob $lines $pattern] +} +proc version {file} { + set provisions [grep $file {*package provide*}] + #puts /$provisions/ + return [lindex $provisions 0 3] +} +proc Hhelp {} { return "\n\tPrint this help" } +proc _help {} { + usage 0 + return +} +proc Hrecipes {} { return "\n\tList all brew commands, without details." } +proc _recipes {} { + set r {} + foreach c [info commands _*] { + lappend r [string range $c 1 end] + } + puts [lsort -dict $r] + return +} +proc Hinstall {} { return "?destination? ?mode?\n\tInstall all packages, and application.\n\tdestination = path of package directory, default \[info library\].\n\tmode = Build mode, one of system, system-static, or local. Default is system." } +proc _install {{ldir {}} {mode {}}} { + global packages + if {$ldir eq {}} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + + if {$mode eq {}} { + critcl::app::main [list -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + } else { + critcl::app::main [list -with-mode $mode -cache [pwd]/BUILD -libdir $ldir -includedir $idir -pkg $src] + } + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hdebug {} { return "?destination? ?mode?\n\tInstall debug builds of all packages.\n\tdestination = path of package directory, default \[info library\].\n\tmode = Build mode, one of system, system-static, or local. Default is system." } +proc _debug {{ldir {}} {mode {}}} { + global packages + if {$ldir eq {}} { + set ldir [info library] + set idir [file dirname [file dirname $ldir]]/include + } else { + set idir [file dirname $ldir]/include + } + + # Create directories, might not exist. + file mkdir $idir + file mkdir $ldir + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD.$p + + if {$mode eq {}} { + critcl::app::main [list -keep -debug all -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + } else { + critcl::app::main [list -keep -debug all -with-mode $mode -cache [pwd]/BUILD.$p -libdir $ldir -includedir $idir -pkg $src] + } + + if {![file exists $ldir/$p]} { + set ::NOTE {warn {DONE, with FAILURES}} + break + } + + file delete -force $ldir/$p$version + file rename $ldir/$p $ldir/$p$version + + puts -nonewline "Installed package: " + tag ok + puts $ldir/$p$version + } + return +} +proc Hgui {} { return "\n\tInstall all packages, and application.\n\tDone from a small GUI." } +proc _gui {} { + global INSTALLPATH + package require Tk + package require widget::scrolledwindow + + wm protocol . WM_DELETE_WINDOW ::_exit + + label .l -text {Install Path: } + entry .e -textvariable ::INSTALLPATH + button .i -command Install -text Install + + widget::scrolledwindow .st -borderwidth 1 -relief sunken + text .t + .st setwidget .t + + .t tag configure stdout -font {Helvetica 8} + .t tag configure stderr -background red -font {Helvetica 12} + .t tag configure ok -background green -font {Helvetica 8} + .t tag configure warn -background yellow -font {Helvetica 12} + + grid .l -row 0 -column 0 -sticky new + grid .e -row 0 -column 1 -sticky new + grid .i -row 0 -column 2 -sticky new + grid .st -row 1 -column 0 -sticky swen -columnspan 2 + + grid rowconfigure . 0 -weight 0 + grid rowconfigure . 1 -weight 1 + + grid columnconfigure . 0 -weight 0 + grid columnconfigure . 1 -weight 1 + grid columnconfigure . 2 -weight 0 + + set INSTALLPATH [info library] + + # Redirect all output into our log window, and disable uncontrolled exit. + rename ::puts ::_puts + rename ::log ::puts + rename ::exit ::_exit + rename ::myexit ::exit + + # And start to interact with the user. + vwait forever + return +} +proc Install {} { + global INSTALLPATH NOTE + .i configure -state disabled + + set NOTE {ok DONE} + set fail [catch { + _install $INSTALLPATH + + puts "" + tag [lindex $NOTE 0] + puts [lindex $NOTE 1] + } e o] + + .i configure -state normal + .i configure -command ::_exit -text Exit -bg green + + if {$fail} { + # rethrow + return {*}$o $e + } + return +} +proc Hwrap4tea {} { return "?destination?\n\tGenerate a source package with TEA-based build system wrapped around critcl.\n\tdestination = path of source package directory, default is sub-directory 'tea' of the CWD." } +proc _wrap4tea {{dst {}}} { + global packages + + if {[llength [info level 0]] < 2} { + set dst [file join [pwd] tea] + } + + file mkdir $dst + + package require critcl::app + + foreach p $packages { + set src [file dirname $::me]/$p.tcl + set version [version $src] + + file delete -force [pwd]/BUILD + critcl::app::main [list -cache [pwd]/BUILD -libdir $dst -tea $src] + file delete -force $dst/$p$version + file rename $dst/$p $dst/$p$version + + puts "Wrapped package: $dst/$p$version" + } + return +} +main diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib.tcl b/src/vfs/critcl.vfs/examples/zlibwrap/zlib.tcl new file mode 100644 index 00000000..d03210b8 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib.tcl @@ -0,0 +1,327 @@ +# zlib.tcl -- +# +# Low-level wrapper around libz, making it a Tcl package. +# +# Copyright (c) 2011,2022 Andreas Kupries + +# Example of exporting a C-level stubs API through critcl v3, linking +# against an external library and/or baking in the library using its sources. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 +package require critcl 3.2 + +# # ## ### ##### ######## ############# ##################### +## Administrivia + +critcl::license {Andreas Kupries} BSD + +critcl::summary {A C-level wrapper of the zlib compression library} +critcl::description { + This package wraps around zlib, making its + C-level functions available as Tcl package, + with stubs. No Tcl-binding is provided. +} + +critcl::subject gzip zip zlib libz +critcl::subject compression {data compression} +critcl::subject decompression {data decompression} + +# # ## ### ##### ######## ############# ##################### +## Configuration + +critcl::userconfig define mode { + choose the zlib to build and link against. +} { + system + system-static + local +} + +# # ## ### ##### ######## ############# ##################### +## Exported API + +critcl::api scspec ZEXTERN + +# # ## ### ##### ######## ############# ##################### +## Misc. interfaces + +critcl::api function {const char *} zlibVersion {} +critcl::api function {const char *} zError {int err} + +critcl::api function uLong crc32 { + uLong crc + {const Bytef *} buf + uInt len +} + +critcl::api function uLong adler32 { + uLong adler + {const Bytef *} buf + uInt len +} + +# # ## ### ##### ######## ############# ##################### +## Deflate = Compression + +critcl::api function int deflateInit_ { + z_streamp stream + int level + {const char *} version + int stream_size +} + +critcl::api function int deflateInit2_ { + z_streamp stream + int level + int method + int windowBits + int memLevel + int strategy + {const char *} version + int stream_size +} + +critcl::api function int deflate { + z_streamp stream + int flush +} + +critcl::api function int deflateEnd { + z_streamp stream +} + +critcl::api function int deflateSetDictionary { + z_streamp stream + {const Bytef *} dict + uInt dictLength +} + +critcl::api function int deflateCopy { + z_streamp dst + z_streamp src +} + +critcl::api function int deflateReset { + z_streamp stream +} + +critcl::api function int deflateParams { + z_streamp stream + int level + int strategy +} + +# # ## ### ##### ######## ############# ##################### +## + +critcl::api function int compress { + {Bytef *} dest + {uLongf *} destLen + {const Bytef *} source + uLong sourceLen +} + +critcl::api function int compress2 { + {Bytef *} dest + {uLongf *} destLen + {const Bytef *} source + uLong sourceLen + int level +} + +# # ## ### ##### ######## ############# ##################### +## Inflate = Decompression + +critcl::api function int inflateInit_ { + z_streamp stream + {const char *} version + int stream_size +} + +critcl::api function int inflateInit2_ { + z_streamp stream + int windowBits + {const char *} version + int stream_size +} + +critcl::api function int inflate { + z_streamp stream + int flush +} + +critcl::api function int inflateEnd { + z_streamp stream +} + +critcl::api function int inflateSetDictionary { + z_streamp stream + {const Bytef *} dict + uInt dictLength +} + +critcl::api function int inflateSync {z_streamp stream} +critcl::api function int inflateReset {z_streamp stream} + +# # ## ### ##### ######## ############# ##################### +## + +critcl::api function int uncompress { + {Bytef *} dest + {uLongf *} destLen + {const Bytef *} source + uLong sourceLen +} + +# # ## ### ##### ######## ############# ##################### +## gz'ip layer + +critcl::api function gzFile gzopen { + {const char *} path + {const char *} mode +} + +critcl::api function gzFile gzdopen { + int fd + {const char *} mode +} + +critcl::api function int gzsetparams { + gzFile file + int level + int strategy +} + +critcl::api function int gzread { + gzFile file + voidp buf + unsigned len +} + +critcl::api function int gzwrite { + gzFile file + voidpc buf + unsigned len +} + +critcl::api function int gzprintf { + gzFile file + {const char *} format + ... +} + +critcl::api function int gzputs { + gzFile file + {const char *} s +} + +critcl::api function {char *} gzgets { + gzFile file + {char *} buf + int len +} + +critcl::api function int gzputc { + gzFile file + int c +} + +critcl::api function int gzgetc { + gzFile file +} + +critcl::api function int gzflush { + gzFile file + int flush +} + +critcl::api function z_off_t gzseek { + gzFile file + z_off_t offset + int whence +} + +critcl::api function int gzrewind {gzFile file} +critcl::api function z_off_t gztell {gzFile file} +critcl::api function int gzeof {gzFile file} +critcl::api function int gzclose {gzFile file} + +critcl::api function {const char *} gzerror { + gzFile file + {int *} errnum +} + +# # ## ### ##### ######## ############# ##################### +## Implementation. + +namespace eval ::zlib {} + +# Export zlib version number. Together with the 'variant' (see below), +# we know what this package is an interface to. +critcl::cproc ::zlib::version {} vstring { + return zlibVersion (); +} + +critcl::cdata ::zlib::variant [critcl::userconfig query mode] +critcl::msg -nonewline " /[critcl::userconfig query mode]" + +switch -exact -- [critcl::userconfig query mode] { + local { + # Build against the local z/lib/z sources. + critcl::api header zlib/zconf.h + critcl::api header zlib/zlib.h + + critcl::cheaders zlib/*.h + critcl::csources zlib/adler32.c + critcl::csources zlib/compress.c + critcl::csources zlib/crc32.c + critcl::csources zlib/deflate.c + critcl::csources zlib/gzclose.c + critcl::csources zlib/gzlib.c + critcl::csources zlib/gzread.c + critcl::csources zlib/gzwrite.c + critcl::csources zlib/infback.c + critcl::csources zlib/inffast.c + critcl::csources zlib/inflate.c + critcl::csources zlib/inftrees.c + critcl::csources zlib/trees.c + critcl::csources zlib/uncompr.c + critcl::csources zlib/zutil.c + } + system { + # Build against system z/lib/z + + critcl::api extheader zconf.h + critcl::api extheader zlib.h + + critcl::clibraries -lz + } + system-static { + # Build against system z/lib/z, statically + + critcl::api extheader zconf.h + critcl::api extheader zlib.h + + set ok 0 + foreach p { + /lib + /usr/lib + /usr/local/lib + } { + if {![file exists $p/libz.a]} continue + critcl::clibraries $p/libz.a + set ok 1 + break + } + if {!$ok} { + critcl::error "Unable to find static libz.a" + } + } +} + +# ### ### ### ######### ######### ######### +## Ready +package provide zlib 1 ; # for libz 1.2.5 diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/CMakeLists.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/CMakeLists.txt new file mode 100644 index 00000000..a64fe0b2 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/CMakeLists.txt @@ -0,0 +1,190 @@ +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +project(zlib C) + +if(NOT DEFINED BUILD_SHARED_LIBS) + option(BUILD_SHARED_LIBS "Build a shared library form of zlib" ON) +endif() + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +enable_testing() + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# +# Check for unistd.h +# +check_include_file(unistd.h Z_HAVE_UNISTD_H) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) +endif() + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) + message(FATAL_ERROR + "You must remove ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h " + "from the source tree. This file is included with zlib " + "but CMake generates this file for you automatically " + "in the build directory.") + endif() +endif() + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + zlib.h +) +set(ZLIB_PRIVATE_HDRS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h +) +set(ZLIB_SRCS + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c + win32/zlib1.rc +) + +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) + +if(MINGW) + # This gets us DLL resource information when compiling on MinGW. + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + COMMAND windres.exe + -D GCC_WINDRES + -I ${CMAKE_CURRENT_SOURCE_DIR} + -I ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) + set(ZLIB_SRCS ${ZLIB_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) +endif(MINGW) + +add_library(zlib ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) + +set_target_properties(zlib PROPERTIES SOVERSION 1) + +if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) +endif() + +if(UNIX) + # On unix-like platforms the library is almost always called libz + set_target_properties(zlib PROPERTIES OUTPUT_NAME z) +elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") +endif() + +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS zlib + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib ) +endif() +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION include) +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES zlib.3 DESTINATION share/man/man3) +endif() + +#============================================================================ +# Example binaries +#============================================================================ + +add_executable(example example.c) +target_link_libraries(example zlib) +add_test(example example) + +add_executable(minigzip minigzip.c) +target_link_libraries(minigzip zlib) + +if(HAVE_OFF64_T) + add_executable(example64 example.c) + target_link_libraries(example64 zlib) + set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") + add_test(example64 example64) + + add_executable(minigzip64 minigzip.c) + target_link_libraries(minigzip64 zlib) + set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +endif() diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/ChangeLog b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/ChangeLog new file mode 100644 index 00000000..fd5bca11 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/ChangeLog @@ -0,0 +1,1208 @@ + + ChangeLog file for zlib + +Changes in 1.2.5 (19 Apr 2010) +- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] +- Default to libdir as sharedlibdir in configure [Nieder] +- Update copyright dates on modified source files +- Update trees.c to be able to generate modified trees.h +- Exit configure for MinGW, suggesting win32/Makefile.gcc + +Changes in 1.2.4.5 (18 Apr 2010) +- Set sharedlibdir in configure [Torok] +- Set LDFLAGS in Makefile.in [Bar-Lev] +- Avoid mkdir objs race condition in Makefile.in [Bowler] +- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays +- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C +- Don't use hidden attribute when it is a warning generator (e.g. Solaris) + +Changes in 1.2.4.4 (18 Apr 2010) +- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] +- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty +- Try to use bash or ksh regardless of functionality of /bin/sh +- Fix configure incompatibility with NetBSD sh +- Remove attempt to run under bash or ksh since have better NetBSD fix +- Fix win32/Makefile.gcc for MinGW [Bar-Lev] +- Add diagnostic messages when using CROSS_PREFIX in configure +- Added --sharedlibdir option to configure [Weigelt] +- Use hidden visibility attribute when available [Frysinger] + +Changes in 1.2.4.3 (10 Apr 2010) +- Only use CROSS_PREFIX in configure for ar and ranlib if they exist +- Use CROSS_PREFIX for nm [Bar-Lev] +- Assume _LARGEFILE64_SOURCE defined is equivalent to true +- Avoid use of undefined symbols in #if with && and || +- Make *64 prototypes in gzguts.h consistent with functions +- Add -shared load option for MinGW in configure [Bowler] +- Move z_off64_t to public interface, use instead of off64_t +- Remove ! from shell test in configure (not portable to Solaris) +- Change +0 macro tests to -0 for possibly increased portability + +Changes in 1.2.4.2 (9 Apr 2010) +- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 +- Really provide prototypes for *64 functions when building without LFS +- Only define unlink() in minigzip.c if unistd.h not included +- Update README to point to contrib/vstudio project files +- Move projects/vc6 to old/ and remove projects/ +- Include stdlib.h in minigzip.c for setmode() definition under WinCE +- Clean up assembler builds in win32/Makefile.msc [Rowe] +- Include sys/types.h for Microsoft for off_t definition +- Fix memory leak on error in gz_open() +- Symbolize nm as $NM in configure [Weigelt] +- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] +- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined +- Fix bug in gzeof() to take into account unused input data +- Avoid initialization of structures with variables in puff.c +- Updated win32/README-WIN32.txt [Rowe] + +Changes in 1.2.4.1 (28 Mar 2010) +- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] +- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] +- Restore "for debugging" comment on sprintf() in gzlib.c +- Remove fdopen for MVS from gzguts.h +- Put new README-WIN32.txt in win32 [Rowe] +- Add check for shell to configure and invoke another shell if needed +- Fix big fat stinking bug in gzseek() on uncompressed files +- Remove vestigial F_OPEN64 define in zutil.h +- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE +- Avoid errors on non-LFS systems when applications define LFS macros +- Set EXE to ".exe" in configure for MINGW [Kahle] +- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] +- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] +- Add DLL install in win32/makefile.gcc [Bar-Lev] +- Allow Linux* or linux* from uname in configure [Bar-Lev] +- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] +- Add cross-compilation prefixes to configure [Bar-Lev] +- Match type exactly in gz_load() invocation in gzread.c +- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func +- Provide prototypes for *64 functions when building zlib without LFS +- Don't use -lc when linking shared library on MinGW +- Remove errno.h check in configure and vestigial errno code in zutil.h + +Changes in 1.2.4 (14 Mar 2010) +- Fix VER3 extraction in configure for no fourth subversion +- Update zlib.3, add docs to Makefile.in to make .pdf out of it +- Add zlib.3.pdf to distribution +- Don't set error code in gzerror() if passed pointer is NULL +- Apply destination directory fixes to CMakeLists.txt [Lowman] +- Move #cmakedefine's to a new zconf.in.cmakein +- Restore zconf.h for builds that don't use configure or cmake +- Add distclean to dummy Makefile for convenience +- Update and improve INDEX, README, and FAQ +- Update CMakeLists.txt for the return of zconf.h [Lowman] +- Update contrib/vstudio/vc9 and vc10 [Vollant] +- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc +- Apply license and readme changes to contrib/asm686 [Raiter] +- Check file name lengths and add -c option in minigzip.c [Li] +- Update contrib/amd64 and contrib/masmx86/ [Vollant] +- Avoid use of "eof" parameter in trees.c to not shadow library variable +- Update make_vms.com for removal of zlibdefs.h [Zinser] +- Update assembler code and vstudio projects in contrib [Vollant] +- Remove outdated assembler code contrib/masm686 and contrib/asm586 +- Remove old vc7 and vc8 from contrib/vstudio +- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] +- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() +- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] +- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) +- Fix bug in void-returning vsprintf() case in gzwrite.c +- Fix name change from inflate.h in contrib/inflate86/inffas86.c +- Check if temporary file exists before removing in make_vms.com [Zinser] +- Fix make install and uninstall for --static option +- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] +- Update readme.txt in contrib/masmx64 and masmx86 to assemble + +Changes in 1.2.3.9 (21 Feb 2010) +- Expunge gzio.c +- Move as400 build information to old +- Fix updates in contrib/minizip and contrib/vstudio +- Add const to vsnprintf test in configure to avoid warnings [Weigelt] +- Delete zconf.h (made by configure) [Weigelt] +- Change zconf.in.h to zconf.h.in per convention [Weigelt] +- Check for NULL buf in gzgets() +- Return empty string for gzgets() with len == 1 (like fgets()) +- Fix description of gzgets() in zlib.h for end-of-file, NULL return +- Update minizip to 1.1 [Vollant] +- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c +- Note in zlib.h that gzerror() should be used to distinguish from EOF +- Remove use of snprintf() from gzlib.c +- Fix bug in gzseek() +- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] +- Fix zconf.h generation in CMakeLists.txt [Lowman] +- Improve comments in zconf.h where modified by configure + +Changes in 1.2.3.8 (13 Feb 2010) +- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] +- Use z_off64_t in gz_zero() and gz_skip() to match state->skip +- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) +- Revert to Makefile.in from 1.2.3.6 (live with the clutter) +- Fix missing error return in gzflush(), add zlib.h note +- Add *64 functions to zlib.map [Levin] +- Fix signed/unsigned comparison in gz_comp() +- Use SFLAGS when testing shared linking in configure +- Add --64 option to ./configure to use -m64 with gcc +- Fix ./configure --help to correctly name options +- Have make fail if a test fails [Levin] +- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] +- Remove assembler object files from contrib + +Changes in 1.2.3.7 (24 Jan 2010) +- Always gzopen() with O_LARGEFILE if available +- Fix gzdirect() to work immediately after gzopen() or gzdopen() +- Make gzdirect() more precise when the state changes while reading +- Improve zlib.h documentation in many places +- Catch memory allocation failure in gz_open() +- Complete close operation if seek forward in gzclose_w() fails +- Return Z_ERRNO from gzclose_r() if close() fails +- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL +- Return zero for gzwrite() errors to match zlib.h description +- Return -1 on gzputs() error to match zlib.h description +- Add zconf.in.h to allow recovery from configure modification [Weigelt] +- Fix static library permissions in Makefile.in [Weigelt] +- Avoid warnings in configure tests that hide functionality [Weigelt] +- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] +- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] +- Avoid access of uninitialized data for first inflateReset2 call [Gomes] +- Keep object files in subdirectories to reduce the clutter somewhat +- Remove default Makefile and zlibdefs.h, add dummy Makefile +- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ +- Remove zlibdefs.h completely -- modify zconf.h instead + +Changes in 1.2.3.6 (17 Jan 2010) +- Avoid void * arithmetic in gzread.c and gzwrite.c +- Make compilers happier with const char * for gz_error message +- Avoid unused parameter warning in inflate.c +- Avoid signed-unsigned comparison warning in inflate.c +- Indent #pragma's for traditional C +- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() +- Correct email address in configure for system options +- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] +- Update zlib.map [Brown] +- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] +- Apply various fixes to CMakeLists.txt [Lowman] +- Add checks on len in gzread() and gzwrite() +- Add error message for no more room for gzungetc() +- Remove zlib version check in gzwrite() +- Defer compression of gzprintf() result until need to +- Use snprintf() in gzdopen() if available +- Remove USE_MMAP configuration determination (only used by minigzip) +- Remove examples/pigz.c (available separately) +- Update examples/gun.c to 1.6 + +Changes in 1.2.3.5 (8 Jan 2010) +- Add space after #if in zutil.h for some compilers +- Fix relatively harmless bug in deflate_fast() [Exarevsky] +- Fix same problem in deflate_slow() +- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] +- Add deflate_rle() for faster Z_RLE strategy run-length encoding +- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding +- Change name of "write" variable in inffast.c to avoid library collisions +- Fix premature EOF from gzread() in gzio.c [Brown] +- Use zlib header window size if windowBits is 0 in inflateInit2() +- Remove compressBound() call in deflate.c to avoid linking compress.o +- Replace use of errno in gz* with functions, support WinCE [Alves] +- Provide alternative to perror() in minigzip.c for WinCE [Alves] +- Don't use _vsnprintf on later versions of MSVC [Lowman] +- Add CMake build script and input file [Lowman] +- Update contrib/minizip to 1.1 [Svensson, Vollant] +- Moved nintendods directory from contrib to . +- Replace gzio.c with a new set of routines with the same functionality +- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above +- Update contrib/minizip to 1.1b +- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h + +Changes in 1.2.3.4 (21 Dec 2009) +- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility +- Update comments in configure and Makefile.in for default --shared +- Fix test -z's in configure [Marquess] +- Build examplesh and minigzipsh when not testing +- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h +- Import LDFLAGS from the environment in configure +- Fix configure to populate SFLAGS with discovered CFLAGS options +- Adapt make_vms.com to the new Makefile.in [Zinser] +- Add zlib2ansi script for C++ compilation [Marquess] +- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) +- Add AMD64 assembler code for longest match to contrib [Teterin] +- Include options from $SFLAGS when doing $LDSHARED +- Simplify 64-bit file support by introducing z_off64_t type +- Make shared object files in objs directory to work around old Sun cc +- Use only three-part version number for Darwin shared compiles +- Add rc option to ar in Makefile.in for when ./configure not run +- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* +- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile +- Protect against _FILE_OFFSET_BITS being defined when compiling zlib +- Rename Makefile.in targets allstatic to static and allshared to shared +- Fix static and shared Makefile.in targets to be independent +- Correct error return bug in gz_open() by setting state [Brown] +- Put spaces before ;;'s in configure for better sh compatibility +- Add pigz.c (parallel implementation of gzip) to examples/ +- Correct constant in crc32.c to UL [Leventhal] +- Reject negative lengths in crc32_combine() +- Add inflateReset2() function to work like inflateEnd()/inflateInit2() +- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] +- Correct typo in doc/algorithm.txt [Janik] +- Fix bug in adler32_combine() [Zhu] +- Catch missing-end-of-block-code error in all inflates and in puff + Assures that random input to inflate eventually results in an error +- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ +- Update ENOUGH and its usage to reflect discovered bounds +- Fix gzerror() error report on empty input file [Brown] +- Add ush casts in trees.c to avoid pedantic runtime errors +- Fix typo in zlib.h uncompress() description [Reiss] +- Correct inflate() comments with regard to automatic header detection +- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) +- Put new version of gzlog (2.0) in examples with interruption recovery +- Add puff compile option to permit invalid distance-too-far streams +- Add puff TEST command options, ability to read piped input +- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but + _LARGEFILE64_SOURCE not defined +- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart +- Fix deflateSetDictionary() to use all 32K for output consistency +- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) +- Clear bytes after deflate lookahead to avoid use of uninitialized data +- Change a limit in inftrees.c to be more transparent to Coverity Prevent +- Update win32/zlib.def with exported symbols from zlib.h +- Correct spelling error in zlib.h [Willem] +- Allow Z_BLOCK for deflate() to force a new block +- Allow negative bits in inflatePrime() to delete existing bit buffer +- Add Z_TREES flush option to inflate() to return at end of trees +- Add inflateMark() to return current state information for random access +- Add Makefile for NintendoDS to contrib [Costa] +- Add -w in configure compile tests to avoid spurious warnings [Beucler] +- Fix typos in zlib.h comments for deflateSetDictionary() +- Fix EOF detection in transparent gzread() [Maier] + +Changes in 1.2.3.3 (2 October 2006) +- Make --shared the default for configure, add a --static option +- Add compile option to permit invalid distance-too-far streams +- Add inflateUndermine() function which is required to enable above +- Remove use of "this" variable name for C++ compatibility [Marquess] +- Add testing of shared library in make test, if shared library built +- Use ftello() and fseeko() if available instead of ftell() and fseek() +- Provide two versions of all functions that use the z_off_t type for + binary compatibility -- a normal version and a 64-bit offset version, + per the Large File Support Extension when _LARGEFILE64_SOURCE is + defined; use the 64-bit versions by default when _FILE_OFFSET_BITS + is defined to be 64 +- Add a --uname= option to configure to perhaps help with cross-compiling + +Changes in 1.2.3.2 (3 September 2006) +- Turn off silly Borland warnings [Hay] +- Use off64_t and define _LARGEFILE64_SOURCE when present +- Fix missing dependency on inffixed.h in Makefile.in +- Rig configure --shared to build both shared and static [Teredesai, Truta] +- Remove zconf.in.h and instead create a new zlibdefs.h file +- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] +- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] + +Changes in 1.2.3.1 (16 August 2006) +- Add watcom directory with OpenWatcom make files [Daniel] +- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] +- Update make_vms.com [Zinser] +- Use -fPIC for shared build in configure [Teredesai, Nicholson] +- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] +- Use fdopen() (not _fdopen()) for Interix in zutil.h [BŠck] +- Add some FAQ entries about the contrib directory +- Update the MVS question in the FAQ +- Avoid extraneous reads after EOF in gzio.c [Brown] +- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] +- Add comments to zlib.h about gzerror() usage [Brown] +- Set extra flags in gzip header in gzopen() like deflate() does +- Make configure options more compatible with double-dash conventions + [Weigelt] +- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] +- Fix uninstall target in Makefile.in [Truta] +- Add pkgconfig support [Weigelt] +- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] +- Replace set_data_type() with a more accurate detect_data_type() in + trees.c, according to the txtvsbin.txt document [Truta] +- Swap the order of #include and #include "zlib.h" in + gzio.c, example.c and minigzip.c [Truta] +- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, + Truta] (where?) +- Fix target "clean" from win32/Makefile.bor [Truta] +- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] +- Update zlib www home address in win32/DLL_FAQ.txt [Truta] +- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] +- Enable browse info in the "Debug" and "ASM Debug" configurations in + the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] +- Add pkgconfig support [Weigelt] +- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, + for use in win32/zlib1.rc [Polushin, Rowe, Truta] +- Add a document that explains the new text detection scheme to + doc/txtvsbin.txt [Truta] +- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] +- Move algorithm.txt into doc/ [Truta] +- Synchronize FAQ with website +- Fix compressBound(), was low for some pathological cases [Fearnley] +- Take into account wrapper variations in deflateBound() +- Set examples/zpipe.c input and output to binary mode for Windows +- Update examples/zlib_how.html with new zpipe.c (also web site) +- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems + that gcc became pickier in 4.0) +- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain + un-versioned, the patch adds versioning only for symbols introduced in + zlib-1.2.0 or later. It also declares as local those symbols which are + not designed to be exported." [Levin] +- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure +- Do not initialize global static by default in trees.c, add a response + NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] +- Don't use strerror() in gzio.c under WinCE [Yakimov] +- Don't use errno.h in zutil.h under WinCE [Yakimov] +- Move arguments for AR to its usage to allow replacing ar [Marot] +- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] +- Improve inflateInit() and inflateInit2() documentation +- Fix structure size comment in inflate.h +- Change configure help option from --h* to --help [Santos] + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Add zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id: ChangeLog 246 2010-04-23 10:54:55Z nijtmans $. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/FAQ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/FAQ new file mode 100644 index 00000000..1a22750a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/FAQ @@ -0,0 +1,366 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://zlib.net/ which may have more recent information. +The lastest zlib FAQ is at http://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the + precompiled DLL are found in the zlib web site at http://zlib.net/ . + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files example.c and + minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + make clean + ./configure -s + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.pdflib.com/ . To modify PDF forms, see + http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specficiation in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/INDEX b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/INDEX new file mode 100644 index 00000000..f6c51ca1 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/INDEX @@ -0,0 +1,65 @@ +CMakeLists.txt cmake build file +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile dummy Makefile that tells you to ./configure +Makefile.in template for Unix Makefile +README guess what +configure configure script for Unix +make_vms.com makefile for VMS +treebuild.xml XML description of source file dependencies +zconf.h.cmakein zconf.h template for cmake +zconf.h.in zconf.h template for configure +zlib.3 Man page for zlib +zlib.3.pdf Man page in PDF format +zlib.map Linux symbol information +zlib.pc.in Template for pkg-config descriptor +zlib2ansi perl script to convert source files for C++ compilation + +amiga/ makefiles for Amiga SAS C +doc/ documentation for formats and algorithms +msdos/ makefiles for MSDOS +nintendods/ makefile for Nintendo DS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +watcom/ makefiles for OpenWatcom +win32/ makefiles for Windows + + zlib public header files (required for library use): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzclose.c +gzguts.h +gzlib.c +gzread.c +gzwrite.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs: +example.c +minigzip.c +See examples/README.examples for more + + unsupported contribution by third parties +See contrib/README.contrib diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/Makefile b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/Makefile new file mode 100644 index 00000000..6bba86c7 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/Makefile @@ -0,0 +1,5 @@ +all: + -@echo "Please use ./configure first. Thank you." + +distclean: + make -f Makefile.in distclean diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/Makefile.in b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/Makefile.in new file mode 100644 index 00000000..5b15bd00 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/Makefile.in @@ -0,0 +1,257 @@ +# Makefile for zlib +# Copyright (C) 1995-2010 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +SFLAGS=-O +LDFLAGS= +TEST_LDFLAGS=-L. libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +STATICLIB=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.5 +SHAREDLIBM=libz.so.1 +LIBS=$(STATICLIB) $(SHAREDLIBV) + +AR=ar rc +RANLIB=ranlib +LDCONFIG=ldconfig +LDSHAREDLIBC=-lc +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +sharedlibdir = ${libdir} +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 +pkgconfigdir = ${libdir}/pkgconfig + +OBJC = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o + +PIC_OBJC = adler32.lo compress.lo crc32.lo deflate.lo gzclose.lo gzlib.lo gzread.lo \ + gzwrite.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo uncompr.lo zutil.lo + +# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo +OBJA = +PIC_OBJA = + +OBJS = $(OBJC) $(OBJA) + +PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA) + +all: static shared + +static: example$(EXE) minigzip$(EXE) + +shared: examplesh$(EXE) minigzipsh$(EXE) + +all64: example64$(EXE) minigzip64$(EXE) + +check: test + +test: all teststatic testshared + +teststatic: static + @if echo hello world | ./minigzip | ./minigzip -d && ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; false; \ + fi + -@rm -f foo.gz + +testshared: shared + @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \ + DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ + SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \ + if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh; then \ + echo ' *** zlib shared test OK ***'; \ + else \ + echo ' *** zlib shared test FAILED ***'; false; \ + fi + -@rm -f foo.gz + +test64: all64 + @if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64; then \ + echo ' *** zlib 64-bit test OK ***'; \ + else \ + echo ' *** zlib 64-bit test FAILED ***'; false; \ + fi + -@rm -f foo.gz + +libz.a: $(OBJS) + $(AR) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +match.lo: match.S + $(CPP) match.S > _match.s + $(CC) -c -fPIC _match.s + mv _match.o match.lo + rm -f _match.s + +example64.o: example.c zlib.h zconf.h + $(CC) $(CFLAGS) -D_FILE_OFFSET_BITS=64 -c -o $@ example.c + +minigzip64.o: minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -D_FILE_OFFSET_BITS=64 -c -o $@ minigzip.c + +.SUFFIXES: .lo + +.c.lo: + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) -DPIC -c -o objs/$*.o $< + -@mv objs/$*.o $@ + +$(SHAREDLIBV): $(PIC_OBJS) + $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + -@rmdir objs + +example$(EXE): example.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) + +minigzip$(EXE): minigzip.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) + +examplesh$(EXE): example.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV) + +minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV) + +example64$(EXE): example64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) + +minigzip64$(EXE): minigzip64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS) + +install-libs: $(LIBS) + -@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi + -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi + -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi + -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi + -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi + cp $(STATICLIB) $(DESTDIR)$(libdir) + cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir) + cd $(DESTDIR)$(libdir); chmod u=rw,go=r $(STATICLIB) + -@(cd $(DESTDIR)$(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + -@cd $(DESTDIR)$(sharedlibdir); if test "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \ + chmod 755 $(SHAREDLIBV); \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + ($(LDCONFIG) || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(DESTDIR)$(man3dir) + chmod 644 $(DESTDIR)$(man3dir)/zlib.3 + cp zlib.pc $(DESTDIR)$(pkgconfigdir) + chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +install: install-libs + -@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi + cp zlib.h zconf.h $(DESTDIR)$(includedir) + chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h + +uninstall: + cd $(DESTDIR)$(includedir); rm -f zlib.h zconf.h + cd $(DESTDIR)$(libdir); rm -f libz.a; \ + if test "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(DESTDIR)$(man3dir); rm -f zlib.3 + cd $(DESTDIR)$(pkgconfigdir); rm -f zlib.pc + +docs: zlib.3.pdf + +zlib.3.pdf: zlib.3 + groff -mandoc -f H -T ps zlib.3 | ps2pdf - zlib.3.pdf + +zconf.h.in: zconf.h.cmakein + sed "/^#cmakedefine/D" < zconf.h.cmakein > zconf.h.in + touch -r zconf.h.cmakein zconf.h.in + +zconf: zconf.h.in + cp -p zconf.h.in zconf.h + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ \ + example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \ + example64$(EXE) minigzip64$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + rm -rf objs + +maintainer-clean: distclean +distclean: clean zconf docs + rm -f Makefile zlib.pc + -@rm -f .DS_Store + -@printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile + -@printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile + -@touch -r Makefile.in Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o zutil.o: zutil.h zlib.h zconf.h +gzclose.o gzlib.o gzread.o gzwrite.o: zlib.h zconf.h gzguts.h +compress.o example.o minigzip.o uncompr.o: zlib.h zconf.h +crc32.o: zutil.h zlib.h zconf.h crc32.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +infback.o inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h + +adler32.lo zutil.lo: zutil.h zlib.h zconf.h +gzclose.lo gzlib.lo gzread.lo gzwrite.lo: zlib.h zconf.h gzguts.h +compress.lo example.lo minigzip.lo uncompr.lo: zlib.h zconf.h +crc32.lo: zutil.h zlib.h zconf.h crc32.h +deflate.lo: deflate.h zutil.h zlib.h zconf.h +infback.lo inflate.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h +inffast.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.lo: zutil.h zlib.h zconf.h inftrees.h +trees.lo: deflate.h zutil.h zlib.h zconf.h trees.h diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/README new file mode 100644 index 00000000..d4219bf8 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/README @@ -0,0 +1,115 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.5 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use one +of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +http://marknelson.us/1997/01/01/zlib-engine/ . + +The changes made in version 1.2.5 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package, documented at +http://java.sun.com/developer/technicalArticles/Programming/compression/ . + +A Perl interface to zlib written by Paul Marquess is available +at CPAN (Comprehensive Perl Archive Network) sites, including +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/adler32.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/adler32.c new file mode 100644 index 00000000..64eb4b94 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/adler32.c @@ -0,0 +1,169 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2007 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +#include "zutil.h" + +#define local static + +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/amiga/Makefile.pup b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/amiga/Makefile.pup new file mode 100644 index 00000000..8940c120 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/amiga/Makefile.pup @@ -0,0 +1,69 @@ +# Amiga powerUP (TM) Makefile +# makefile for libpng and SAS C V6.58/7.00 PPC compiler +# Copyright (C) 1998 by Andreas R. Kleinert + +LIBNAME = libzip.a + +CC = scppc +CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \ + OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER +AR = ppc-amigaos-ar cr +RANLIB = ppc-amigaos-ranlib +LD = ppc-amigaos-ld -r +LDFLAGS = -o +LDLIBS = LIB:scppc.a LIB:end.o +RM = delete quiet + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +$(LIBNAME): $(OBJS) + $(AR) $@ $(OBJS) + -$(RANLIB) $@ + +example: example.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +minigzip: minigzip.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +mostlyclean: clean +clean: + $(RM) *.o example minigzip $(LIBNAME) foo.gz + +zip: + zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \ + descrip.mms *.[ch] + +tgz: + cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \ + zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzclose.o: zlib.h zconf.h gzguts.h +gzlib.o: zlib.h zconf.h gzguts.h +gzread.o: zlib.h zconf.h gzguts.h +gzwrite.o: zlib.h zconf.h gzguts.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/amiga/Makefile.sas b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/amiga/Makefile.sas new file mode 100644 index 00000000..749e2915 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/amiga/Makefile.sas @@ -0,0 +1,68 @@ +# SMakefile for zlib +# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly +# Osma Ahvenlampi +# Amiga, SAS/C 6.56 & Smake + +CC=sc +CFLAGS=OPT +#CFLAGS=OPT CPU=68030 +#CFLAGS=DEBUG=LINE +LDFLAGS=LIB z.lib + +SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \ + NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \ + DEF=POSTINC + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: SCOPTIONS example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +install: z.lib + copy clone zlib.h zconf.h INCLUDE: + copy clone z.lib LIB: + +z.lib: $(OBJS) + oml z.lib r $(OBJS) + +example: example.o z.lib + $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS) + +minigzip: minigzip.o z.lib + $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS) + +mostlyclean: clean +clean: + -delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS + +SCOPTIONS: Makefile.sas + copy to $@ 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/configure b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/configure new file mode 100644 index 00000000..bd9edd26 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/configure @@ -0,0 +1,596 @@ +#!/bin/sh +# configure script for zlib. +# +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +if [ -n "${CHOST}" ]; then + uname="$(echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/')" + CROSS_PREFIX="${CHOST}-" +fi + +STATICLIB=libz.a +LDFLAGS="${LDFLAGS} -L. ${STATICLIB}" +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h` +VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < zlib.h` +VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h` +VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h` +if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then + AR=${AR-"${CROSS_PREFIX}ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} +else + AR=${AR-"ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} +fi +AR_RC="${AR} rc" +if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then + RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"} + test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} +else + RANLIB=${RANLIB-"ranlib"} +fi +if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then + NM=${NM-"${CROSS_PREFIX}nm"} + test -n "${CROSS_PREFIX}" && echo Using ${NM} +else + NM=${NM-"nm"} +fi +LDCONFIG=${LDCONFIG-"ldconfig"} +LDSHAREDLIBC="${LDSHAREDLIBC--lc}" +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +sharedlibdir=${sharedlibdir-'${libdir}'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=1 +zprefix=0 +build64=0 +gcc=0 +old_cc="$CC" +old_cflags="$CFLAGS" + +while test $# -ge 1 +do +case "$1" in + -h* | --help) + echo 'usage:' + echo ' configure [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' + echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' + echo ' [--includedir=INCLUDEDIR]' + exit 0 ;; + -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;; + --sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;; + -u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;; + -p* | --prefix) prefix="$2"; shift; shift ;; + -e* | --eprefix) exec_prefix="$2"; shift; shift ;; + -l* | --libdir) libdir="$2"; shift; shift ;; + -i* | --includedir) includedir="$2"; shift; shift ;; + -s* | --shared | --enable-shared) shared=1; shift ;; + -t | --static) shared=0; shift ;; + -z* | --zprefix) zprefix=1; shift ;; + -6* | --64) build64=1; shift ;; + --sysconfdir=*) echo "ignored option: --sysconfdir"; shift ;; + --localstatedir=*) echo "ignored option: --localstatedir"; shift ;; + *) echo "unknown option: $1"; echo "$0 --help for help"; exit 1 ;; + esac +done + +test=ztest$$ +cat > $test.c </dev/null; then + CC="$cc" + SFLAGS="${CFLAGS--O3} -fPIC" + CFLAGS="${CFLAGS--O3}" + if test $build64 -eq 1; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + fi + if test "${ZLIBGCCWARN}" = "YES"; then + CFLAGS="${CFLAGS} -Wall -Wextra -pedantic" + fi + if test -z "$uname"; then + uname=`(uname -s || echo unknown) 2>/dev/null` + fi + case "$uname" in + Linux* | linux* | GNU | GNU/* | *BSD | DragonFly) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} ;; + CYGWIN* | Cygwin* | cygwin* | OS/2*) + EXE='.exe' ;; + MINGW*|mingw*) +# temporary bypass + rm -f $test.[co] $test $test$shared_ext + echo "Please use win32/Makefile.gcc instead." + exit 1 + LDSHARED=${LDSHARED-"$cc -shared"} + LDSHAREDLIBC="" + EXE='.exe' ;; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; + HP-UX*) + LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + Darwin*) shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} ;; + *) LDSHARED=${LDSHARED-"$cc -shared"} ;; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + gcc=0 + if test -z "$uname"; then + uname=`(uname -sr || echo unknown) 2>/dev/null` + fi + case "$uname" in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDFLAGS="${LDFLAGS} -Wl,-rpath,." + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR_RC="cc -A" ;; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;; + SunOS\ 5*) LDSHARED=${LDSHARED-"cc -G"} + case `(uname -m || echo unknown) 2>/dev/null` in + i86*) + SFLAGS=${CFLAGS-"-xpentium -fast -KPIC -R."} + CFLAGS=${CFLAGS-"-xpentium -fast"} ;; + *) + SFLAGS=${CFLAGS-"-fast -xcg92 -KPIC -R."} + CFLAGS=${CFLAGS-"-fast -xcg92"} ;; + esac ;; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"} ;; + SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"} + CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"} + LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + OpenUNIX\ 5) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc -G"} ;; + # send working options for other systems to zlib@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"} ;; + esac +fi + +SHAREDLIB=${SHAREDLIB-"libz$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"} + +if test $shared -eq 1; then + echo Checking for shared library support... + # we must test in two steps (cc then ld), required at least on SunOS 4.x + if test "`($CC -w -c $SFLAGS $test.c) 2>&1`" = "" && + test "`($LDSHARED $SFLAGS -o $test$shared_ext $test.o) 2>&1`" = ""; then + echo Building shared library $SHAREDLIBV with $CC. + elif test -z "$old_cc" -a -z "$old_cflags"; then + echo No shared library support. + shared=0; + else + echo Tested $CC -w -c $SFLAGS $test.c + $CC -w -c $SFLAGS $test.c + echo Tested $LDSHARED $SFLAGS -o $test$shared_ext $test.o + $LDSHARED $SFLAGS -o $test$shared_ext $test.o + echo 'No shared library support; try without defining CC and CFLAGS' + shared=0; + fi +fi +if test $shared -eq 0; then + LDSHARED="$CC" + ALL="static" + TEST="all teststatic" + SHAREDLIB="" + SHAREDLIBV="" + SHAREDLIBM="" + echo Building static library $STATICLIB version $VER with $CC. +else + ALL="static shared" + TEST="all teststatic testshared" +fi + +cat > $test.c < +off64_t dummy = 0; +EOF +if test "`($CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c) 2>&1`" = ""; then + CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1" + SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1" + ALL="${ALL} all64" + TEST="${TEST} test64" + echo "Checking for off64_t... Yes." + echo "Checking for fseeko... Yes." +else + echo "Checking for off64_t... No." + cat > $test.c < +int main(void) { + fseeko(NULL, 0, 0); + return 0; +} +EOF + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for fseeko... Yes." + else + CFLAGS="${CFLAGS} -DNO_FSEEKO" + SFLAGS="${SFLAGS} -DNO_FSEEKO" + echo "Checking for fseeko... No." + fi +fi + +cp -p zconf.h.in zconf.h + +cat > $test.c < +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for unistd.h... Yes." +else + echo "Checking for unistd.h... No." +fi + +if test $zprefix -eq 1; then + sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Using z_ prefix on all symbols." +fi + +cat > $test.c < +#include +#include "zconf.h" + +int main() +{ +#ifndef STDC + choke me +#endif + + return 0; +} +EOF + +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." + + cat > $test.c < +#include + +int mytest(const char *fmt, ...) +{ + char buf[20]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for vsnprintf() in stdio.h... Yes." + + cat >$test.c < +#include + +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return n; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of vsnprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_vsnprintf_void" + SFLAGS="$SFLAGS -DHAS_vsnprintf_void" + echo "Checking for return value of vsnprintf()... No." + echo " WARNING: apparently vsnprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + CFLAGS="$CFLAGS -DNO_vsnprintf" + SFLAGS="$SFLAGS -DNO_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... No." + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c < +#include + +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + n = vsprintf(buf, fmt, ap); + va_end(ap); + return n; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of vsprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_vsprintf_void" + SFLAGS="$SFLAGS -DHAS_vsprintf_void" + echo "Checking for return value of vsprintf()... No." + echo " WARNING: apparently vsprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +else + echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." + + cat >$test.c < + +int mytest() +{ + char buf[20]; + + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for snprintf() in stdio.h... Yes." + + cat >$test.c < + +int mytest() +{ + char buf[20]; + + return snprintf(buf, sizeof(buf), "%s", "foo"); +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of snprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_snprintf_void" + SFLAGS="$SFLAGS -DHAS_snprintf_void" + echo "Checking for return value of snprintf()... No." + echo " WARNING: apparently snprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + CFLAGS="$CFLAGS -DNO_snprintf" + SFLAGS="$SFLAGS -DNO_snprintf" + echo "Checking for snprintf() in stdio.h... No." + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c < + +int mytest() +{ + char buf[20]; + + return sprintf(buf, "%s", "foo"); +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of sprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_sprintf_void" + SFLAGS="$SFLAGS -DHAS_sprintf_void" + echo "Checking for return value of sprintf()... No." + echo " WARNING: apparently sprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +fi + +if test "$gcc" -eq 1; then + cat > $test.c <= 33) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif +int ZLIB_INTERNAL foo; +int main() +{ + return 0; +} +EOF + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for attribute(visibility) support... Yes." + else + CFLAGS="$CFLAGS -DNO_VIZ" + SFLAGS="$SFLAGS -DNO_VIZ" + echo "Checking for attribute(visibility) support... No." + fi +fi + +CPP=${CPP-"$CC -E"} +case $CFLAGS in + *ASMV*) + if test "`$NM $test.o | grep _hello`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. + else + echo Checking for underline in external names... Yes. + fi ;; +esac + +rm -f $test.[co] $test $test$shared_ext + +# udpate Makefile +sed < Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^CPP *=/s#=.*#=$CPP# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR_RC# +/^RANLIB *=/s#=.*#=$RANLIB# +/^LDCONFIG *=/s#=.*#=$LDCONFIG# +/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^all: */s#:.*#: $ALL# +/^test: */s#:.*#: $TEST# +" > Makefile + +sed < zlib.pc.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^CPP *=/s#=.*#=$CPP# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR_RC# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" | sed -e " +s/\@VERSION\@/$VER/g; +" > zlib.pc diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/README.contrib b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/README.contrib new file mode 100644 index 00000000..dd2285d9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/README.contrib @@ -0,0 +1,77 @@ +All files under this contrib directory are UNSUPPORTED. There were +provided by users of zlib and were not tested by the authors of zlib. +Use at your own risk. Please contact the authors of the contributions +for help about these, not the zlib authors. Thanks. + + +ada/ by Dmitriy Anisimkov + Support for Ada + See http://zlib-ada.sourceforge.net/ + +amd64/ by Mikhail Teterin + asm code for AMD64 + See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393 + +asm686/ by Brian Raiter + asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax + See http://www.muppetlabs.com/~breadbox/software/assembly.html + +blast/ by Mark Adler + Decompressor for output of PKWare Data Compression Library (DCL) + +delphi/ by Cosmin Truta + Support for Delphi and C++ Builder + +dotzlib/ by Henrik Ravn + Support for Microsoft .Net and Visual C++ .Net + +gcc_gvmat64/by Gilles Vollant + GCC Version of x86 64-bit (AMD64 and Intel EM64t) code for x64 + assembler to replace longest_match() and inflate_fast() + +infback9/ by Mark Adler + Unsupported diffs to infback to decode the deflate64 format + +inflate86/ by Chris Anderson + Tuned x86 gcc asm code to replace inflate_fast() + +iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + +iostream2/ by Tyge Løvset + Another C++ I/O streams interface + +iostream3/ by Ludwig Schwardt + and Kevin Ruland + Yet another C++ I/O streams interface + +masmx64/ by Gilles Vollant + x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to + replace longest_match() and inflate_fast(), also masm x86 + 64-bits translation of Chris Anderson inflate_fast() + +masmx86/ by Gilles Vollant + x86 asm code to replace longest_match() and inflate_fast(), + for Visual C++ and MASM (32 bits). + Based on Brian Raiter (asm686) and Chris Anderson (inflate86) + +minizip/ by Gilles Vollant + Mini zip and unzip based on zlib + Includes Zip64 support by Mathias Svensson + See http://www.winimage.com/zLibDll/unzip.html + +pascal/ by Bob Dellaca et al. + Support for Pascal + +puff/ by Mark Adler + Small, low memory usage inflate. Also serves to provide an + unambiguous description of the deflate format. + +testzlib/ by Gilles Vollant + Example of the use of zlib + +untgz/ by Pedro A. Aranda Gutierrez + A very simple tar.gz file extractor using zlib + +vstudio/ by Gilles Vollant + Building a minizip-enhanced zlib with Microsoft Visual Studio diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/buffer_demo.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/buffer_demo.adb new file mode 100644 index 00000000..0410c508 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/buffer_demo.adb @@ -0,0 +1,106 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- +-- $Id: buffer_demo.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +-- This demo program provided by Dr Steve Sangwine +-- +-- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer +-- of exactly the correct size is used for decompressed data, and the last +-- few bytes passed in to Zlib are checksum bytes. + +-- This program compresses a string of text, and then decompresses the +-- compressed text into a buffer of the same size as the original text. + +with Ada.Streams; use Ada.Streams; +with Ada.Text_IO; + +with ZLib; use ZLib; + +procedure Buffer_Demo is + EOL : Character renames ASCII.LF; + Text : constant String + := "Four score and seven years ago our fathers brought forth," & EOL & + "upon this continent, a new nation, conceived in liberty," & EOL & + "and dedicated to the proposition that `all men are created equal'."; + + Source : Stream_Element_Array (1 .. Text'Length); + for Source'Address use Text'Address; + +begin + Ada.Text_IO.Put (Text); + Ada.Text_IO.New_Line; + Ada.Text_IO.Put_Line + ("Uncompressed size : " & Positive'Image (Text'Length) & " bytes"); + + declare + Compressed_Data : Stream_Element_Array (1 .. Text'Length); + L : Stream_Element_Offset; + begin + Compress : declare + Compressor : Filter_Type; + I : Stream_Element_Offset; + begin + Deflate_Init (Compressor); + + -- Compress the whole of T at once. + + Translate (Compressor, Source, I, Compressed_Data, L, Finish); + pragma Assert (I = Source'Last); + + Close (Compressor); + + Ada.Text_IO.Put_Line + ("Compressed size : " + & Stream_Element_Offset'Image (L) & " bytes"); + end Compress; + + -- Now we decompress the data, passing short blocks of data to Zlib + -- (because this demonstrates the problem - the last block passed will + -- contain checksum information and there will be no output, only a + -- check inside Zlib that the checksum is correct). + + Decompress : declare + Decompressor : Filter_Type; + + Uncompressed_Data : Stream_Element_Array (1 .. Text'Length); + + Block_Size : constant := 4; + -- This makes sure that the last block contains + -- only Adler checksum data. + + P : Stream_Element_Offset := Compressed_Data'First - 1; + O : Stream_Element_Offset; + begin + Inflate_Init (Decompressor); + + loop + Translate + (Decompressor, + Compressed_Data + (P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)), + P, + Uncompressed_Data + (Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last), + O, + No_Flush); + + Ada.Text_IO.Put_Line + ("Total in : " & Count'Image (Total_In (Decompressor)) & + ", out : " & Count'Image (Total_Out (Decompressor))); + + exit when P = L; + end loop; + + Ada.Text_IO.New_Line; + Ada.Text_IO.Put_Line + ("Decompressed text matches original text : " + & Boolean'Image (Uncompressed_Data = Source)); + end Decompress; + end; +end Buffer_Demo; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/mtest.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/mtest.adb new file mode 100644 index 00000000..4b064096 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/mtest.adb @@ -0,0 +1,156 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- Continuous test for ZLib multithreading. If the test would fail +-- we should provide thread safe allocation routines for the Z_Stream. +-- +-- $Id: mtest.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +with ZLib; +with Ada.Streams; +with Ada.Numerics.Discrete_Random; +with Ada.Text_IO; +with Ada.Exceptions; +with Ada.Task_Identification; + +procedure MTest is + use Ada.Streams; + use ZLib; + + Stop : Boolean := False; + + pragma Atomic (Stop); + + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + task type Test_Task; + + task body Test_Task is + Buffer : Stream_Element_Array (1 .. 100_000); + Gen : Random_Elements.Generator; + + Buffer_First : Stream_Element_Offset; + Compare_First : Stream_Element_Offset; + + Deflate : Filter_Type; + Inflate : Filter_Type; + + procedure Further (Item : in Stream_Element_Array); + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + ------------- + -- Further -- + ------------- + + procedure Further (Item : in Stream_Element_Array) is + + procedure Compare (Item : in Stream_Element_Array); + + ------------- + -- Compare -- + ------------- + + procedure Compare (Item : in Stream_Element_Array) is + Next_First : Stream_Element_Offset := Compare_First + Item'Length; + begin + if Buffer (Compare_First .. Next_First - 1) /= Item then + raise Program_Error; + end if; + + Compare_First := Next_First; + end Compare; + + procedure Compare_Write is new ZLib.Write (Write => Compare); + begin + Compare_Write (Inflate, Item, No_Flush); + end Further; + + ----------------- + -- Read_Buffer -- + ----------------- + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset) + is + Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First; + Next_First : Stream_Element_Offset; + begin + if Item'Length <= Buff_Diff then + Last := Item'Last; + + Next_First := Buffer_First + Item'Length; + + Item := Buffer (Buffer_First .. Next_First - 1); + + Buffer_First := Next_First; + else + Last := Item'First + Buff_Diff; + Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last); + Buffer_First := Buffer'Last + 1; + end if; + end Read_Buffer; + + procedure Translate is new Generic_Translate + (Data_In => Read_Buffer, + Data_Out => Further); + + begin + Random_Elements.Reset (Gen); + + Buffer := (others => 20); + + Main : loop + for J in Buffer'Range loop + Buffer (J) := Random_Elements.Random (Gen); + + Deflate_Init (Deflate); + Inflate_Init (Inflate); + + Buffer_First := Buffer'First; + Compare_First := Buffer'First; + + Translate (Deflate); + + if Compare_First /= Buffer'Last + 1 then + raise Program_Error; + end if; + + Ada.Text_IO.Put_Line + (Ada.Task_Identification.Image + (Ada.Task_Identification.Current_Task) + & Stream_Element_Offset'Image (J) + & ZLib.Count'Image (Total_Out (Deflate))); + + Close (Deflate); + Close (Inflate); + + exit Main when Stop; + end loop; + end loop Main; + exception + when E : others => + Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E)); + Stop := True; + end Test_Task; + + Test : array (1 .. 4) of Test_Task; + + pragma Unreferenced (Test); + + Dummy : Character; + +begin + Ada.Text_IO.Get_Immediate (Dummy); + Stop := True; +end MTest; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/read.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/read.adb new file mode 100644 index 00000000..06273ecf --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/read.adb @@ -0,0 +1,156 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: read.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +-- Test/demo program for the generic read interface. + +with Ada.Numerics.Discrete_Random; +with Ada.Streams; +with Ada.Text_IO; + +with ZLib; + +procedure Read is + + use Ada.Streams; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Stream_Element_Offset := 100_000; + + Continuous : constant Boolean := False; + -- If this constant is True, the test would be repeated again and again, + -- with increment File_Size for every iteration. + + Header : constant ZLib.Header_Type := ZLib.Default; + -- Do not use Header other than Default in ZLib versions 1.1.4 and older. + + Init_Random : constant := 8; + -- We are using the same random sequence, in case of we catch bug, + -- so we would be able to reproduce it. + + -- End -- + + Pack_Size : Stream_Element_Offset; + Offset : Stream_Element_Offset; + + Filter : ZLib.Filter_Type; + + subtype Visible_Symbols + is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is new + Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Period : constant Stream_Element_Offset := 200; + -- Period constant variable for random generator not to be very random. + -- Bigger period, harder random. + + Read_Buffer : Stream_Element_Array (1 .. 2048); + Read_First : Stream_Element_Offset; + Read_Last : Stream_Element_Offset; + + procedure Reset; + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Read + -- reading data from the File_In. + + procedure Read is new ZLib.Read + (Read, + Read_Buffer, + Rest_First => Read_First, + Rest_Last => Read_Last); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Last := Stream_Element_Offset'Min + (Item'Last, + Item'First + File_Size - Offset); + + for J in Item'First .. Last loop + if J < Item'First + Period then + Item (J) := Random_Elements.Random (Gen); + else + Item (J) := Item (J - Period); + end if; + + Offset := Offset + 1; + end loop; + end Read; + + ----------- + -- Reset -- + ----------- + + procedure Reset is + begin + Random_Elements.Reset (Gen, Init_Random); + Pack_Size := 0; + Offset := 1; + Read_First := Read_Buffer'Last + 1; + Read_Last := Read_Buffer'Last; + end Reset; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter, + Level, + Header => Header); + + Reset; + + Ada.Text_IO.Put + (Stream_Element_Offset'Image (File_Size) & " ->"); + + loop + declare + Buffer : Stream_Element_Array (1 .. 1024); + Last : Stream_Element_Offset; + begin + Read (Filter, Buffer, Last); + + Pack_Size := Pack_Size + Last - Buffer'First + 1; + + exit when Last < Buffer'Last; + end; + end loop; + + Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size)); + + ZLib.Close (Filter); + end loop; + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Read; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/readme.txt new file mode 100644 index 00000000..ce4d2cad --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/readme.txt @@ -0,0 +1,65 @@ + ZLib for Ada thick binding (ZLib.Ada) + Release 1.3 + +ZLib.Ada is a thick binding interface to the popular ZLib data +compression library, available at http://www.gzip.org/zlib/. +It provides Ada-style access to the ZLib C library. + + + Here are the main changes since ZLib.Ada 1.2: + +- Attension: ZLib.Read generic routine have a initialization requirement + for Read_Last parameter now. It is a bit incompartible with previous version, + but extends functionality, we could use new parameters Allow_Read_Some and + Flush now. + +- Added Is_Open routines to ZLib and ZLib.Streams packages. + +- Add pragma Assert to check Stream_Element is 8 bit. + +- Fix extraction to buffer with exact known decompressed size. Error reported by + Steve Sangwine. + +- Fix definition of ULong (changed to unsigned_long), fix regression on 64 bits + computers. Patch provided by Pascal Obry. + +- Add Status_Error exception definition. + +- Add pragma Assertion that Ada.Streams.Stream_Element size is 8 bit. + + + How to build ZLib.Ada under GNAT + +You should have the ZLib library already build on your computer, before +building ZLib.Ada. Make the directory of ZLib.Ada sources current and +issue the command: + + gnatmake test -largs -L -lz + +Or use the GNAT project file build for GNAT 3.15 or later: + + gnatmake -Pzlib.gpr -L + + + How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2 + +1. Make a project with all *.ads and *.adb files from the distribution. +2. Build the libz.a library from the ZLib C sources. +3. Rename libz.a to z.lib. +4. Add the library z.lib to the project. +5. Add the libc.lib library from the ObjectAda distribution to the project. +6. Build the executable using test.adb as a main procedure. + + + How to use ZLib.Ada + +The source files test.adb and read.adb are small demo programs that show +the main functionality of ZLib.Ada. + +The routines from the package specifications are commented. + + +Homepage: http://zlib-ada.sourceforge.net/ +Author: Dmitriy Anisimkov + +Contributors: Pascal Obry , Steve Sangwine diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/test.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/test.adb new file mode 100644 index 00000000..4733f76a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/test.adb @@ -0,0 +1,463 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: test.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +-- The program has a few aims. +-- 1. Test ZLib.Ada95 thick binding functionality. +-- 2. Show the example of use main functionality of the ZLib.Ada95 binding. +-- 3. Build this program automatically compile all ZLib.Ada95 packages under +-- GNAT Ada95 compiler. + +with ZLib.Streams; +with Ada.Streams.Stream_IO; +with Ada.Numerics.Discrete_Random; + +with Ada.Text_IO; + +with Ada.Calendar; + +procedure Test is + + use Ada.Streams; + use Stream_IO; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Count := 100_000; + Continuous : constant Boolean := False; + + Header : constant ZLib.Header_Type := ZLib.Default; + -- ZLib.None; + -- ZLib.Auto; + -- ZLib.GZip; + -- Do not use Header other then Default in ZLib versions 1.1.4 + -- and older. + + Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy; + Init_Random : constant := 10; + + -- End -- + + In_File_Name : constant String := "testzlib.in"; + -- Name of the input file + + Z_File_Name : constant String := "testzlib.zlb"; + -- Name of the compressed file. + + Out_File_Name : constant String := "testzlib.out"; + -- Name of the decompressed file. + + File_In : File_Type; + File_Out : File_Type; + File_Back : File_Type; + File_Z : ZLib.Streams.Stream_Type; + + Filter : ZLib.Filter_Type; + + Time_Stamp : Ada.Calendar.Time; + + procedure Generate_File; + -- Generate file of spetsified size with some random data. + -- The random data is repeatable, for the good compression. + + procedure Compare_Streams + (Left, Right : in out Root_Stream_Type'Class); + -- The procedure compearing data in 2 streams. + -- It is for compare data before and after compression/decompression. + + procedure Compare_Files (Left, Right : String); + -- Compare files. Based on the Compare_Streams. + + procedure Copy_Streams + (Source, Target : in out Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024); + -- Copying data from one stream to another. It is for test stream + -- interface of the library. + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- reading data from the File_In. + + procedure Data_Out (Item : in Stream_Element_Array); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- writing data to the File_Out. + + procedure Stamp; + -- Store the timestamp to the local variable. + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count); + -- Print the time statistic with the message. + + procedure Translate is new ZLib.Generic_Translate + (Data_In => Data_In, + Data_Out => Data_Out); + -- This procedure is moving data from File_In to File_Out + -- with compression or decompression, depend on initialization of + -- Filter parameter. + + ------------------- + -- Compare_Files -- + ------------------- + + procedure Compare_Files (Left, Right : String) is + Left_File, Right_File : File_Type; + begin + Open (Left_File, In_File, Left); + Open (Right_File, In_File, Right); + Compare_Streams (Stream (Left_File).all, Stream (Right_File).all); + Close (Left_File); + Close (Right_File); + end Compare_Files; + + --------------------- + -- Compare_Streams -- + --------------------- + + procedure Compare_Streams + (Left, Right : in out Ada.Streams.Root_Stream_Type'Class) + is + Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#); + Left_Last, Right_Last : Stream_Element_Offset; + begin + loop + Read (Left, Left_Buffer, Left_Last); + Read (Right, Right_Buffer, Right_Last); + + if Left_Last /= Right_Last then + Ada.Text_IO.Put_Line ("Compare error :" + & Stream_Element_Offset'Image (Left_Last) + & " /= " + & Stream_Element_Offset'Image (Right_Last)); + + raise Constraint_Error; + + elsif Left_Buffer (0 .. Left_Last) + /= Right_Buffer (0 .. Right_Last) + then + Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal."); + raise Constraint_Error; + + end if; + + exit when Left_Last < Left_Buffer'Last; + end loop; + end Compare_Streams; + + ------------------ + -- Copy_Streams -- + ------------------ + + procedure Copy_Streams + (Source, Target : in out Ada.Streams.Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Read (Source, Buffer, Last); + Write (Target, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Copy_Streams; + + ------------- + -- Data_In -- + ------------- + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Read (File_In, Item, Last); + end Data_In; + + -------------- + -- Data_Out -- + -------------- + + procedure Data_Out (Item : in Stream_Element_Array) is + begin + Write (File_Out, Item); + end Data_Out; + + ------------------- + -- Generate_File -- + ------------------- + + procedure Generate_File is + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10; + + Buffer_Count : constant Count := File_Size / Buffer'Length; + -- Number of same buffers in the packet. + + Density : constant Count := 30; -- from 0 to Buffer'Length - 2; + + procedure Fill_Buffer (J, D : in Count); + -- Change the part of the buffer. + + ----------------- + -- Fill_Buffer -- + ----------------- + + procedure Fill_Buffer (J, D : in Count) is + begin + for K in 0 .. D loop + Buffer + (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1)) + := Random_Elements.Random (Gen); + + end loop; + end Fill_Buffer; + + begin + Random_Elements.Reset (Gen, Init_Random); + + Create (File_In, Out_File, In_File_Name); + + Fill_Buffer (1, Buffer'Length - 2); + + for J in 1 .. Buffer_Count loop + Write (File_In, Buffer); + + Fill_Buffer (J, Density); + end loop; + + -- fill remain size. + + Write + (File_In, + Buffer + (1 .. Stream_Element_Offset + (File_Size - Buffer'Length * Buffer_Count))); + + Flush (File_In); + Close (File_In); + end Generate_File; + + --------------------- + -- Print_Statistic -- + --------------------- + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is + use Ada.Calendar; + use Ada.Text_IO; + + package Count_IO is new Integer_IO (ZLib.Count); + + Curr_Dur : Duration := Clock - Time_Stamp; + begin + Put (Msg); + + Set_Col (20); + Ada.Text_IO.Put ("size ="); + + Count_IO.Put + (Data_Size, + Width => Stream_IO.Count'Image (File_Size)'Length); + + Put_Line (" duration =" & Duration'Image (Curr_Dur)); + end Print_Statistic; + + ----------- + -- Stamp -- + ----------- + + procedure Stamp is + begin + Time_Stamp := Ada.Calendar.Clock; + end Stamp; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + Generate_File; + + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put_Line ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Test generic interface. + Open (File_In, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + Stamp; + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter => Filter, + Level => Level, + Strategy => Strategy, + Header => Header); + + Translate (Filter); + Print_Statistic ("Generic compress", ZLib.Total_Out (Filter)); + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Open (File_In, In_File, Z_File_Name); + Create (File_Out, Out_File, Out_File_Name); + + Stamp; + + -- Inflate using generic instantiation. + + ZLib.Inflate_Init (Filter, Header => Header); + + Translate (Filter); + Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter)); + + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Compare_Files (In_File_Name, Out_File_Name); + + -- Test stream interface. + + -- Compress to the back stream. + + Open (File_In, In_File, In_File_Name); + Create (File_Back, Out_File, Z_File_Name); + + Stamp; + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Level => Level, + Strategy => Strategy, + Header => Header); + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + -- Flushing internal buffers to the back stream. + + ZLib.Streams.Flush (File_Z, ZLib.Finish); + + Print_Statistic ("Write compress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_In); + Close (File_Back); + + -- Compare reading from original file and from + -- decompression stream. + + Open (File_In, In_File, In_File_Name); + Open (File_Back, In_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Header => Header); + + Stamp; + Compare_Streams (Stream (File_In).all, File_Z); + + Print_Statistic ("Read decompress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + -- Compress by reading from compression stream. + + Open (File_Back, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Level => Level, + Strategy => Strategy, + Header => Header); + + Stamp; + Copy_Streams + (Source => File_Z, + Target => Stream (File_Out).all); + + Print_Statistic ("Read compress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_Out); + Close (File_Back); + + -- Decompress to decompression stream. + + Open (File_In, In_File, Z_File_Name); + Create (File_Back, Out_File, Out_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Header => Header); + + Stamp; + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + Print_Statistic ("Write decompress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + Compare_Files (In_File_Name, Out_File_Name); + end loop; + + Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok."); + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Test; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-streams.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-streams.adb new file mode 100644 index 00000000..3eb8a279 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-streams.adb @@ -0,0 +1,225 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +with Ada.Unchecked_Deallocation; + +package body ZLib.Streams is + + ----------- + -- Close -- + ----------- + + procedure Close (Stream : in out Stream_Type) is + procedure Free is new Ada.Unchecked_Deallocation + (Stream_Element_Array, Buffer_Access); + begin + if Stream.Mode = Out_Stream or Stream.Mode = Duplex then + -- We should flush the data written by the writer. + + Flush (Stream, Finish); + + Close (Stream.Writer); + end if; + + if Stream.Mode = In_Stream or Stream.Mode = Duplex then + Close (Stream.Reader); + Free (Stream.Buffer); + end if; + end Close; + + ------------ + -- Create -- + ------------ + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size) + is + + subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size); + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean); + + ----------------- + -- Init_Filter -- + ----------------- + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean) is + begin + if Compress then + Deflate_Init + (Filter, Level, Strategy, Header => Header); + else + Inflate_Init (Filter, Header => Header); + end if; + end Init_Filter; + + begin + Stream.Back := Back; + Stream.Mode := Mode; + + if Mode = Out_Stream or Mode = Duplex then + Init_Filter (Stream.Writer, Back_Compressed); + Stream.Buffer_Size := Write_Buffer_Size; + else + Stream.Buffer_Size := 0; + end if; + + if Mode = In_Stream or Mode = Duplex then + Init_Filter (Stream.Reader, not Back_Compressed); + + Stream.Buffer := new Buffer_Subtype; + Stream.Rest_First := Stream.Buffer'Last + 1; + Stream.Rest_Last := Stream.Buffer'Last; + end if; + end Create; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush) + is + Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Flush (Stream.Writer, Buffer, Last, Mode); + + Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Flush; + + ------------- + -- Is_Open -- + ------------- + + function Is_Open (Stream : Stream_Type) return Boolean is + begin + return Is_Open (Stream.Reader) or else Is_Open (Stream.Writer); + end Is_Open; + + ---------- + -- Read -- + ---------- + + procedure Read + (Stream : in out Stream_Type; + Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) + is + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Ada.Streams.Read (Stream.Back.all, Item, Last); + end Read; + + procedure Read is new ZLib.Read + (Read => Read, + Buffer => Stream.Buffer.all, + Rest_First => Stream.Rest_First, + Rest_Last => Stream.Rest_Last); + + begin + Read (Stream.Reader, Item, Last); + end Read; + + ------------------- + -- Read_Total_In -- + ------------------- + + function Read_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Reader); + end Read_Total_In; + + -------------------- + -- Read_Total_Out -- + -------------------- + + function Read_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Reader); + end Read_Total_Out; + + ----------- + -- Write -- + ----------- + + procedure Write + (Stream : in out Stream_Type; + Item : in Stream_Element_Array) + is + + procedure Write (Item : in Stream_Element_Array); + + ----------- + -- Write -- + ----------- + + procedure Write (Item : in Stream_Element_Array) is + begin + Ada.Streams.Write (Stream.Back.all, Item); + end Write; + + procedure Write is new ZLib.Write + (Write => Write, + Buffer_Size => Stream.Buffer_Size); + + begin + Write (Stream.Writer, Item, No_Flush); + end Write; + + -------------------- + -- Write_Total_In -- + -------------------- + + function Write_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Writer); + end Write_Total_In; + + --------------------- + -- Write_Total_Out -- + --------------------- + + function Write_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Writer); + end Write_Total_Out; + +end ZLib.Streams; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-streams.ads b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-streams.ads new file mode 100644 index 00000000..36b9109a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-streams.ads @@ -0,0 +1,114 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.ads 66 2005-08-17 18:20:58Z andreas_kupries $ + +package ZLib.Streams is + + type Stream_Mode is (In_Stream, Out_Stream, Duplex); + + type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class; + + type Stream_Type is + new Ada.Streams.Root_Stream_Type with private; + + procedure Read + (Stream : in out Stream_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + procedure Write + (Stream : in out Stream_Type; + Item : in Ada.Streams.Stream_Element_Array); + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush); + -- Flush the written data to the back stream, + -- all data placed to the compressor is flushing to the Back stream. + -- Should not be used untill necessary, becouse it is decreasing + -- compression. + + function Read_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_In); + -- Return total number of bytes read from back stream so far. + + function Read_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_Out); + -- Return total number of bytes read so far. + + function Write_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_In); + -- Return total number of bytes written so far. + + function Write_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_Out); + -- Return total number of bytes written to the back stream. + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size); + -- Create the Comression/Decompression stream. + -- If mode is In_Stream then Write operation is disabled. + -- If mode is Out_Stream then Read operation is disabled. + + -- If Back_Compressed is true then + -- Data written to the Stream is compressing to the Back stream + -- and data read from the Stream is decompressed data from the Back stream. + + -- If Back_Compressed is false then + -- Data written to the Stream is decompressing to the Back stream + -- and data read from the Stream is compressed data from the Back stream. + + -- !!! When the Need_Header is False ZLib-Ada is using undocumented + -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers. + + function Is_Open (Stream : Stream_Type) return Boolean; + + procedure Close (Stream : in out Stream_Type); + +private + + use Ada.Streams; + + type Buffer_Access is access all Stream_Element_Array; + + type Stream_Type + is new Root_Stream_Type with + record + Mode : Stream_Mode; + + Buffer : Buffer_Access; + Rest_First : Stream_Element_Offset; + Rest_Last : Stream_Element_Offset; + -- Buffer for Read operation. + -- We need to have this buffer in the record + -- becouse not all read data from back stream + -- could be processed during the read operation. + + Buffer_Size : Stream_Element_Offset; + -- Buffer size for write operation. + -- We do not need to have this buffer + -- in the record becouse all data could be + -- processed in the write operation. + + Back : Stream_Access; + Reader : Filter_Type; + Writer : Filter_Type; + end record; + +end ZLib.Streams; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-thin.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-thin.adb new file mode 100644 index 00000000..2e4a0174 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-thin.adb @@ -0,0 +1,141 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +package body ZLib.Thin is + + ZLIB_VERSION : constant Chars_Ptr := zlibVersion; + + Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit; + + -------------- + -- Avail_In -- + -------------- + + function Avail_In (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_In; + end Avail_In; + + --------------- + -- Avail_Out -- + --------------- + + function Avail_Out (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_Out; + end Avail_Out; + + ------------------ + -- Deflate_Init -- + ------------------ + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int is + begin + return deflateInit2 + (strm, + level, + method, + windowBits, + memLevel, + strategy, + ZLIB_VERSION, + Z_Stream_Size); + end Deflate_Init; + + ------------------ + -- Inflate_Init -- + ------------------ + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is + begin + return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size); + end Inflate_Init; + + ------------------------ + -- Last_Error_Message -- + ------------------------ + + function Last_Error_Message (Strm : in Z_Stream) return String is + use Interfaces.C.Strings; + begin + if Strm.msg = Null_Ptr then + return ""; + else + return Value (Strm.msg); + end if; + end Last_Error_Message; + + ------------ + -- Set_In -- + ------------ + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Strm.Next_In := Buffer; + Strm.Avail_In := Size; + end Set_In; + + ------------------ + -- Set_Mem_Func -- + ------------------ + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func) is + begin + Strm.opaque := Opaque; + Strm.zalloc := Alloc; + Strm.zfree := Free; + end Set_Mem_Func; + + ------------- + -- Set_Out -- + ------------- + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Strm.Next_Out := Buffer; + Strm.Avail_Out := Size; + end Set_Out; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_In; + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_Out; + end Total_Out; + +end ZLib.Thin; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-thin.ads b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-thin.ads new file mode 100644 index 00000000..e48c4f15 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib-thin.ads @@ -0,0 +1,450 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.ads 66 2005-08-17 18:20:58Z andreas_kupries $ + +with Interfaces.C.Strings; + +with System; + +private package ZLib.Thin is + + -- From zconf.h + + MAX_MEM_LEVEL : constant := 9; -- zconf.h:105 + -- zconf.h:105 + MAX_WBITS : constant := 15; -- zconf.h:115 + -- 32K LZ77 window + -- zconf.h:115 + SEEK_SET : constant := 8#0000#; -- zconf.h:244 + -- Seek from beginning of file. + -- zconf.h:244 + SEEK_CUR : constant := 1; -- zconf.h:245 + -- Seek from current position. + -- zconf.h:245 + SEEK_END : constant := 2; -- zconf.h:246 + -- Set file pointer to EOF plus "offset" + -- zconf.h:246 + + type Byte is new Interfaces.C.unsigned_char; -- 8 bits + -- zconf.h:214 + type UInt is new Interfaces.C.unsigned; -- 16 bits or more + -- zconf.h:216 + type Int is new Interfaces.C.int; + + type ULong is new Interfaces.C.unsigned_long; -- 32 bits or more + -- zconf.h:217 + subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr; + + type ULong_Access is access ULong; + type Int_Access is access Int; + + subtype Voidp is System.Address; -- zconf.h:232 + + subtype Byte_Access is Voidp; + + Nul : constant Voidp := System.Null_Address; + -- end from zconf + + Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125 + -- zlib.h:125 + Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126 + -- will be removed, use + -- Z_SYNC_FLUSH instead + -- zlib.h:126 + Z_SYNC_FLUSH : constant := 2; -- zlib.h:127 + -- zlib.h:127 + Z_FULL_FLUSH : constant := 3; -- zlib.h:128 + -- zlib.h:128 + Z_FINISH : constant := 4; -- zlib.h:129 + -- zlib.h:129 + Z_OK : constant := 8#0000#; -- zlib.h:132 + -- zlib.h:132 + Z_STREAM_END : constant := 1; -- zlib.h:133 + -- zlib.h:133 + Z_NEED_DICT : constant := 2; -- zlib.h:134 + -- zlib.h:134 + Z_ERRNO : constant := -1; -- zlib.h:135 + -- zlib.h:135 + Z_STREAM_ERROR : constant := -2; -- zlib.h:136 + -- zlib.h:136 + Z_DATA_ERROR : constant := -3; -- zlib.h:137 + -- zlib.h:137 + Z_MEM_ERROR : constant := -4; -- zlib.h:138 + -- zlib.h:138 + Z_BUF_ERROR : constant := -5; -- zlib.h:139 + -- zlib.h:139 + Z_VERSION_ERROR : constant := -6; -- zlib.h:140 + -- zlib.h:140 + Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145 + -- zlib.h:145 + Z_BEST_SPEED : constant := 1; -- zlib.h:146 + -- zlib.h:146 + Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147 + -- zlib.h:147 + Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148 + -- zlib.h:148 + Z_FILTERED : constant := 1; -- zlib.h:151 + -- zlib.h:151 + Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152 + -- zlib.h:152 + Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153 + -- zlib.h:153 + Z_BINARY : constant := 8#0000#; -- zlib.h:156 + -- zlib.h:156 + Z_ASCII : constant := 1; -- zlib.h:157 + -- zlib.h:157 + Z_UNKNOWN : constant := 2; -- zlib.h:158 + -- zlib.h:158 + Z_DEFLATED : constant := 8; -- zlib.h:161 + -- zlib.h:161 + Z_NULL : constant := 8#0000#; -- zlib.h:164 + -- for initializing zalloc, zfree, opaque + -- zlib.h:164 + type gzFile is new Voidp; -- zlib.h:646 + + type Z_Stream is private; + + type Z_Streamp is access all Z_Stream; -- zlib.h:89 + + type alloc_func is access function + (Opaque : Voidp; + Items : UInt; + Size : UInt) + return Voidp; -- zlib.h:63 + + type free_func is access procedure (opaque : Voidp; address : Voidp); + + function zlibVersion return Chars_Ptr; + + function Deflate (strm : Z_Streamp; flush : Int) return Int; + + function DeflateEnd (strm : Z_Streamp) return Int; + + function Inflate (strm : Z_Streamp; flush : Int) return Int; + + function InflateEnd (strm : Z_Streamp) return Int; + + function deflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; + + function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int; + -- zlib.h:478 + + function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495 + + function deflateParams + (strm : Z_Streamp; + level : Int; + strategy : Int) + return Int; -- zlib.h:506 + + function inflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; -- zlib.h:548 + + function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565 + + function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580 + + function compress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; -- zlib.h:601 + + function compress2 + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong; + level : Int) + return Int; -- zlib.h:615 + + function uncompress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; + + function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile; + + function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile; + + function gzsetparams + (file : gzFile; + level : Int; + strategy : Int) + return Int; + + function gzread + (file : gzFile; + buf : Voidp; + len : UInt) + return Int; + + function gzwrite + (file : in gzFile; + buf : in Voidp; + len : in UInt) + return Int; + + function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int; + + function gzputs (file : in gzFile; s : in Chars_Ptr) return Int; + + function gzgets + (file : gzFile; + buf : Chars_Ptr; + len : Int) + return Chars_Ptr; + + function gzputc (file : gzFile; char : Int) return Int; + + function gzgetc (file : gzFile) return Int; + + function gzflush (file : gzFile; flush : Int) return Int; + + function gzseek + (file : gzFile; + offset : Int; + whence : Int) + return Int; + + function gzrewind (file : gzFile) return Int; + + function gztell (file : gzFile) return Int; + + function gzeof (file : gzFile) return Int; + + function gzclose (file : gzFile) return Int; + + function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr; + + function adler32 + (adler : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function crc32 + (crc : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function deflateInit + (strm : Z_Streamp; + level : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function deflateInit2 + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int; + pragma Inline (Deflate_Init); + + function inflateInit + (strm : Z_Streamp; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function inflateInit2 + (strm : in Z_Streamp; + windowBits : in Int; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + + function inflateBackInit + (strm : in Z_Streamp; + windowBits : in Int; + window : in Byte_Access; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + -- Size of window have to be 2**windowBits. + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int; + pragma Inline (Inflate_Init); + + function zError (err : Int) return Chars_Ptr; + + function inflateSyncPoint (z : Z_Streamp) return Int; + + function get_crc_table return ULong_Access; + + -- Interface to the available fields of the z_stream structure. + -- The application must update next_in and avail_in when avail_in has + -- dropped to zero. It must update next_out and avail_out when avail_out + -- has dropped to zero. The application must initialize zalloc, zfree and + -- opaque before calling the init function. + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_In); + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_Out); + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func); + pragma Inline (Set_Mem_Func); + + function Last_Error_Message (Strm : in Z_Stream) return String; + pragma Inline (Last_Error_Message); + + function Avail_Out (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_Out); + + function Avail_In (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_In); + + function Total_In (Strm : in Z_Stream) return ULong; + pragma Inline (Total_In); + + function Total_Out (Strm : in Z_Stream) return ULong; + pragma Inline (Total_Out); + + function inflateCopy + (dest : in Z_Streamp; + Source : in Z_Streamp) + return Int; + + function compressBound (Source_Len : in ULong) return ULong; + + function deflateBound + (Strm : in Z_Streamp; + Source_Len : in ULong) + return ULong; + + function gzungetc (C : in Int; File : in gzFile) return Int; + + function zlibCompileFlags return ULong; + +private + + type Z_Stream is record -- zlib.h:68 + Next_In : Voidp := Nul; -- next input byte + Avail_In : UInt := 0; -- number of bytes available at next_in + Total_In : ULong := 0; -- total nb of input bytes read so far + Next_Out : Voidp := Nul; -- next output byte should be put there + Avail_Out : UInt := 0; -- remaining free space at next_out + Total_Out : ULong := 0; -- total nb of bytes output so far + msg : Chars_Ptr; -- last error message, NULL if no error + state : Voidp; -- not visible by applications + zalloc : alloc_func := null; -- used to allocate the internal state + zfree : free_func := null; -- used to free the internal state + opaque : Voidp; -- private data object passed to + -- zalloc and zfree + data_type : Int; -- best guess about the data type: + -- ascii or binary + adler : ULong; -- adler32 value of the uncompressed + -- data + reserved : ULong; -- reserved for future use + end record; + + pragma Convention (C, Z_Stream); + + pragma Import (C, zlibVersion, "zlibVersion"); + pragma Import (C, Deflate, "deflate"); + pragma Import (C, DeflateEnd, "deflateEnd"); + pragma Import (C, Inflate, "inflate"); + pragma Import (C, InflateEnd, "inflateEnd"); + pragma Import (C, deflateSetDictionary, "deflateSetDictionary"); + pragma Import (C, deflateCopy, "deflateCopy"); + pragma Import (C, deflateReset, "deflateReset"); + pragma Import (C, deflateParams, "deflateParams"); + pragma Import (C, inflateSetDictionary, "inflateSetDictionary"); + pragma Import (C, inflateSync, "inflateSync"); + pragma Import (C, inflateReset, "inflateReset"); + pragma Import (C, compress, "compress"); + pragma Import (C, compress2, "compress2"); + pragma Import (C, uncompress, "uncompress"); + pragma Import (C, gzopen, "gzopen"); + pragma Import (C, gzdopen, "gzdopen"); + pragma Import (C, gzsetparams, "gzsetparams"); + pragma Import (C, gzread, "gzread"); + pragma Import (C, gzwrite, "gzwrite"); + pragma Import (C, gzprintf, "gzprintf"); + pragma Import (C, gzputs, "gzputs"); + pragma Import (C, gzgets, "gzgets"); + pragma Import (C, gzputc, "gzputc"); + pragma Import (C, gzgetc, "gzgetc"); + pragma Import (C, gzflush, "gzflush"); + pragma Import (C, gzseek, "gzseek"); + pragma Import (C, gzrewind, "gzrewind"); + pragma Import (C, gztell, "gztell"); + pragma Import (C, gzeof, "gzeof"); + pragma Import (C, gzclose, "gzclose"); + pragma Import (C, gzerror, "gzerror"); + pragma Import (C, adler32, "adler32"); + pragma Import (C, crc32, "crc32"); + pragma Import (C, deflateInit, "deflateInit_"); + pragma Import (C, inflateInit, "inflateInit_"); + pragma Import (C, deflateInit2, "deflateInit2_"); + pragma Import (C, inflateInit2, "inflateInit2_"); + pragma Import (C, zError, "zError"); + pragma Import (C, inflateSyncPoint, "inflateSyncPoint"); + pragma Import (C, get_crc_table, "get_crc_table"); + + -- since zlib 1.2.0: + + pragma Import (C, inflateCopy, "inflateCopy"); + pragma Import (C, compressBound, "compressBound"); + pragma Import (C, deflateBound, "deflateBound"); + pragma Import (C, gzungetc, "gzungetc"); + pragma Import (C, zlibCompileFlags, "zlibCompileFlags"); + + pragma Import (C, inflateBackInit, "inflateBackInit_"); + + -- I stopped binding the inflateBack routines, becouse realize that + -- it does not support zlib and gzip headers for now, and have no + -- symmetric deflateBack routines. + -- ZLib-Ada is symmetric regarding deflate/inflate data transformation + -- and has a similar generic callback interface for the + -- deflate/inflate transformation based on the regular Deflate/Inflate + -- routines. + + -- pragma Import (C, inflateBack, "inflateBack"); + -- pragma Import (C, inflateBackEnd, "inflateBackEnd"); + +end ZLib.Thin; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.adb b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.adb new file mode 100644 index 00000000..24917f84 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.adb @@ -0,0 +1,701 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib.adb 66 2005-08-17 18:20:58Z andreas_kupries $ + +with Ada.Exceptions; +with Ada.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; + +with Interfaces.C.Strings; + +with ZLib.Thin; + +package body ZLib is + + use type Thin.Int; + + type Z_Stream is new Thin.Z_Stream; + + type Return_Code_Enum is + (OK, + STREAM_END, + NEED_DICT, + ERRNO, + STREAM_ERROR, + DATA_ERROR, + MEM_ERROR, + BUF_ERROR, + VERSION_ERROR); + + type Flate_Step_Function is access + function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int; + pragma Convention (C, Flate_Step_Function); + + type Flate_End_Function is access + function (Ctrm : in Thin.Z_Streamp) return Thin.Int; + pragma Convention (C, Flate_End_Function); + + type Flate_Type is record + Step : Flate_Step_Function; + Done : Flate_End_Function; + end record; + + subtype Footer_Array is Stream_Element_Array (1 .. 8); + + Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) + := (16#1f#, 16#8b#, -- Magic header + 16#08#, -- Z_DEFLATED + 16#00#, -- Flags + 16#00#, 16#00#, 16#00#, 16#00#, -- Time + 16#00#, -- XFlags + 16#03# -- OS code + ); + -- The simplest gzip header is not for informational, but just for + -- gzip format compatibility. + -- Note that some code below is using assumption + -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make + -- Simple_GZip_Header'Last <= Footer_Array'Last. + + Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum + := (0 => OK, + 1 => STREAM_END, + 2 => NEED_DICT, + -1 => ERRNO, + -2 => STREAM_ERROR, + -3 => DATA_ERROR, + -4 => MEM_ERROR, + -5 => BUF_ERROR, + -6 => VERSION_ERROR); + + Flate : constant array (Boolean) of Flate_Type + := (True => (Step => Thin.Deflate'Access, + Done => Thin.DeflateEnd'Access), + False => (Step => Thin.Inflate'Access, + Done => Thin.InflateEnd'Access)); + + Flush_Finish : constant array (Boolean) of Flush_Mode + := (True => Finish, False => No_Flush); + + procedure Raise_Error (Stream : in Z_Stream); + pragma Inline (Raise_Error); + + procedure Raise_Error (Message : in String); + pragma Inline (Raise_Error); + + procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int); + + procedure Free is new Ada.Unchecked_Deallocation + (Z_Stream, Z_Stream_Access); + + function To_Thin_Access is new Ada.Unchecked_Conversion + (Z_Stream_Access, Thin.Z_Streamp); + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Separate translate routine for make gzip header. + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- translate routine without additional headers. + + ----------------- + -- Check_Error -- + ----------------- + + procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is + use type Thin.Int; + begin + if Code /= Thin.Z_OK then + Raise_Error + (Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Last_Error_Message (Stream)); + end if; + end Check_Error; + + ----------- + -- Close -- + ----------- + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False) + is + Code : Thin.Int; + begin + if not Ignore_Error and then not Is_Open (Filter) then + raise Status_Error; + end if; + + Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm)); + + if Ignore_Error or else Code = Thin.Z_OK then + Free (Filter.Strm); + else + declare + Error_Message : constant String + := Last_Error_Message (Filter.Strm.all); + begin + Free (Filter.Strm); + Ada.Exceptions.Raise_Exception + (ZLib_Error'Identity, + Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Error_Message); + end; + end if; + end Close; + + ----------- + -- CRC32 -- + ----------- + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32 + is + use Thin; + begin + return Unsigned_32 (crc32 (ULong (CRC), + Data'Address, + Data'Length)); + end CRC32; + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) is + begin + CRC := CRC32 (CRC, Data); + end CRC32; + + ------------------ + -- Deflate_Init -- + ------------------ + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Memory_Level : in Memory_Level_Type := Default_Memory_Level; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + begin + if Is_Open (Filter) then + raise Status_Error; + end if; + + -- We allow ZLib to make header only in case of default header type. + -- Otherwise we would either do header by ourselfs, or do not do + -- header at all. + + if Header = None or else Header = GZip then + Win_Bits := -Win_Bits; + end if; + + -- For the GZip CRC calculation and make headers. + + if Header = GZip then + Filter.CRC := 0; + Filter.Offset := Simple_GZip_Header'First; + else + Filter.Offset := Simple_GZip_Header'Last + 1; + end if; + + Filter.Strm := new Z_Stream; + Filter.Compression := True; + Filter.Stream_End := False; + Filter.Header := Header; + + if Thin.Deflate_Init + (To_Thin_Access (Filter.Strm), + Level => Thin.Int (Level), + method => Thin.Int (Method), + windowBits => Win_Bits, + memLevel => Thin.Int (Memory_Level), + strategy => Thin.Int (Strategy)) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Deflate_Init; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + No_Data : Stream_Element_Array := (1 .. 0 => 0); + Last : Stream_Element_Offset; + begin + Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); + end Flush; + + ----------------------- + -- Generic_Translate -- + ----------------------- + + procedure Generic_Translate + (Filter : in out ZLib.Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size) + is + In_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (In_Buffer_Size)); + Out_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (Out_Buffer_Size)); + Last : Stream_Element_Offset; + In_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + begin + Main : loop + Data_In (In_Buffer, Last); + + In_First := In_Buffer'First; + + loop + Translate + (Filter => Filter, + In_Data => In_Buffer (In_First .. Last), + In_Last => In_Last, + Out_Data => Out_Buffer, + Out_Last => Out_Last, + Flush => Flush_Finish (Last < In_Buffer'First)); + + if Out_Buffer'First <= Out_Last then + Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); + end if; + + exit Main when Stream_End (Filter); + + -- The end of in buffer. + + exit when In_Last = Last; + + In_First := In_Last + 1; + end loop; + end loop Main; + + end Generic_Translate; + + ------------------ + -- Inflate_Init -- + ------------------ + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + + procedure Check_Version; + -- Check the latest header types compatibility. + + procedure Check_Version is + begin + if Version <= "1.1.4" then + Raise_Error + ("Inflate header type " & Header_Type'Image (Header) + & " incompatible with ZLib version " & Version); + end if; + end Check_Version; + + begin + if Is_Open (Filter) then + raise Status_Error; + end if; + + case Header is + when None => + Check_Version; + + -- Inflate data without headers determined + -- by negative Win_Bits. + + Win_Bits := -Win_Bits; + when GZip => + Check_Version; + + -- Inflate gzip data defined by flag 16. + + Win_Bits := Win_Bits + 16; + when Auto => + Check_Version; + + -- Inflate with automatic detection + -- of gzip or native header defined by flag 32. + + Win_Bits := Win_Bits + 32; + when Default => null; + end case; + + Filter.Strm := new Z_Stream; + Filter.Compression := False; + Filter.Stream_End := False; + Filter.Header := Header; + + if Thin.Inflate_Init + (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Inflate_Init; + + ------------- + -- Is_Open -- + ------------- + + function Is_Open (Filter : in Filter_Type) return Boolean is + begin + return Filter.Strm /= null; + end Is_Open; + + ----------------- + -- Raise_Error -- + ----------------- + + procedure Raise_Error (Message : in String) is + begin + Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); + end Raise_Error; + + procedure Raise_Error (Stream : in Z_Stream) is + begin + Raise_Error (Last_Error_Message (Stream)); + end Raise_Error; + + ---------- + -- Read -- + ---------- + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode := No_Flush) + is + In_Last : Stream_Element_Offset; + Item_First : Ada.Streams.Stream_Element_Offset := Item'First; + V_Flush : Flush_Mode := Flush; + + begin + pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); + pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); + + loop + if Rest_Last = Buffer'First - 1 then + V_Flush := Finish; + + elsif Rest_First > Rest_Last then + Read (Buffer, Rest_Last); + Rest_First := Buffer'First; + + if Rest_Last < Buffer'First then + V_Flush := Finish; + end if; + end if; + + Translate + (Filter => Filter, + In_Data => Buffer (Rest_First .. Rest_Last), + In_Last => In_Last, + Out_Data => Item (Item_First .. Item'Last), + Out_Last => Last, + Flush => V_Flush); + + Rest_First := In_Last + 1; + + exit when Stream_End (Filter) + or else Last = Item'Last + or else (Last >= Item'First and then Allow_Read_Some); + + Item_First := Last + 1; + end loop; + end Read; + + ---------------- + -- Stream_End -- + ---------------- + + function Stream_End (Filter : in Filter_Type) return Boolean is + begin + if Filter.Header = GZip and Filter.Compression then + return Filter.Stream_End + and then Filter.Offset = Footer_Array'Last + 1; + else + return Filter.Stream_End; + end if; + end Stream_End; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); + end Total_Out; + + --------------- + -- Translate -- + --------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) is + begin + if Filter.Header = GZip and then Filter.Compression then + Translate_GZip + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + else + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + end if; + end Translate; + + -------------------- + -- Translate_Auto -- + -------------------- + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + use type Thin.Int; + Code : Thin.Int; + + begin + if not Is_Open (Filter) then + raise Status_Error; + end if; + + if Out_Data'Length = 0 and then In_Data'Length = 0 then + raise Constraint_Error; + end if; + + Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); + Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length); + + Code := Flate (Filter.Compression).Step + (To_Thin_Access (Filter.Strm), + Thin.Int (Flush)); + + if Code = Thin.Z_STREAM_END then + Filter.Stream_End := True; + else + Check_Error (Filter.Strm.all, Code); + end if; + + In_Last := In_Data'Last + - Stream_Element_Offset (Avail_In (Filter.Strm.all)); + Out_Last := Out_Data'Last + - Stream_Element_Offset (Avail_Out (Filter.Strm.all)); + end Translate_Auto; + + -------------------- + -- Translate_GZip -- + -------------------- + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + Out_First : Stream_Element_Offset; + + procedure Add_Data (Data : in Stream_Element_Array); + -- Add data to stream from the Filter.Offset till necessary, + -- used for add gzip headr/footer. + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32); + pragma Inline (Put_32); + + -------------- + -- Add_Data -- + -------------- + + procedure Add_Data (Data : in Stream_Element_Array) is + Data_First : Stream_Element_Offset renames Filter.Offset; + Data_Last : Stream_Element_Offset; + Data_Len : Stream_Element_Offset; -- -1 + Out_Len : Stream_Element_Offset; -- -1 + begin + Out_First := Out_Last + 1; + + if Data_First > Data'Last then + return; + end if; + + Data_Len := Data'Last - Data_First; + Out_Len := Out_Data'Last - Out_First; + + if Data_Len <= Out_Len then + Out_Last := Out_First + Data_Len; + Data_Last := Data'Last; + else + Out_Last := Out_Data'Last; + Data_Last := Data_First + Out_Len; + end if; + + Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); + + Data_First := Data_Last + 1; + Out_First := Out_Last + 1; + end Add_Data; + + ------------ + -- Put_32 -- + ------------ + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32) + is + D : Unsigned_32 := Data; + begin + for J in Item'First .. Item'First + 3 loop + Item (J) := Stream_Element (D and 16#FF#); + D := Shift_Right (D, 8); + end loop; + end Put_32; + + begin + Out_Last := Out_Data'First - 1; + + if not Filter.Stream_End then + Add_Data (Simple_GZip_Header); + + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data (Out_First .. Out_Data'Last), + Out_Last => Out_Last, + Flush => Flush); + + CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); + end if; + + if Filter.Stream_End and then Out_Last <= Out_Data'Last then + -- This detection method would work only when + -- Simple_GZip_Header'Last > Footer_Array'Last + + if Filter.Offset = Simple_GZip_Header'Last + 1 then + Filter.Offset := Footer_Array'First; + end if; + + declare + Footer : Footer_Array; + begin + Put_32 (Footer, Filter.CRC); + Put_32 (Footer (Footer'First + 4 .. Footer'Last), + Unsigned_32 (Total_In (Filter))); + Add_Data (Footer); + end; + end if; + end Translate_GZip; + + ------------- + -- Version -- + ------------- + + function Version return String is + begin + return Interfaces.C.Strings.Value (Thin.zlibVersion); + end Version; + + ----------- + -- Write -- + ----------- + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode := No_Flush) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + In_Last : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset := Item'First; + begin + if Item'Length = 0 and Flush = No_Flush then + return; + end if; + + loop + Translate + (Filter => Filter, + In_Data => Item (In_First .. Item'Last), + In_Last => In_Last, + Out_Data => Buffer, + Out_Last => Out_Last, + Flush => Flush); + + if Out_Last >= Buffer'First then + Write (Buffer (1 .. Out_Last)); + end if; + + exit when In_Last = Item'Last or Stream_End (Filter); + + In_First := In_Last + 1; + end loop; + end Write; + +end ZLib; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.ads b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.ads new file mode 100644 index 00000000..d909fc3e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.ads @@ -0,0 +1,328 @@ +------------------------------------------------------------------------------ +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- This library is free software; you can redistribute it and/or modify -- +-- it under the terms of the GNU General Public License as published by -- +-- the Free Software Foundation; either version 2 of the License, or (at -- +-- your option) any later version. -- +-- -- +-- This library is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of -- +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- +-- General Public License for more details. -- +-- -- +-- You should have received a copy of the GNU General Public License -- +-- along with this library; if not, write to the Free Software Foundation, -- +-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +------------------------------------------------------------------------------ + +-- $Id: zlib.ads 66 2005-08-17 18:20:58Z andreas_kupries $ + +with Ada.Streams; + +with Interfaces; + +package ZLib is + + ZLib_Error : exception; + Status_Error : exception; + + type Compression_Level is new Integer range -1 .. 9; + + type Flush_Mode is private; + + type Compression_Method is private; + + type Window_Bits_Type is new Integer range 8 .. 15; + + type Memory_Level_Type is new Integer range 1 .. 9; + + type Unsigned_32 is new Interfaces.Unsigned_32; + + type Strategy_Type is private; + + type Header_Type is (None, Auto, Default, GZip); + -- Header type usage have a some limitation for inflate. + -- See comment for Inflate_Init. + + subtype Count is Ada.Streams.Stream_Element_Count; + + Default_Memory_Level : constant Memory_Level_Type := 8; + Default_Window_Bits : constant Window_Bits_Type := 15; + + ---------------------------------- + -- Compression method constants -- + ---------------------------------- + + Deflated : constant Compression_Method; + -- Only one method allowed in this ZLib version + + --------------------------------- + -- Compression level constants -- + --------------------------------- + + No_Compression : constant Compression_Level := 0; + Best_Speed : constant Compression_Level := 1; + Best_Compression : constant Compression_Level := 9; + Default_Compression : constant Compression_Level := -1; + + -------------------------- + -- Flush mode constants -- + -------------------------- + + No_Flush : constant Flush_Mode; + -- Regular way for compression, no flush + + Partial_Flush : constant Flush_Mode; + -- Will be removed, use Z_SYNC_FLUSH instead + + Sync_Flush : constant Flush_Mode; + -- All pending output is flushed to the output buffer and the output + -- is aligned on a byte boundary, so that the decompressor can get all + -- input data available so far. (In particular avail_in is zero after the + -- call if enough output space has been provided before the call.) + -- Flushing may degrade compression for some compression algorithms and so + -- it should be used only when necessary. + + Block_Flush : constant Flush_Mode; + -- Z_BLOCK requests that inflate() stop + -- if and when it get to the next deflate block boundary. When decoding the + -- zlib or gzip format, this will cause inflate() to return immediately + -- after the header and before the first block. When doing a raw inflate, + -- inflate() will go ahead and process the first block, and will return + -- when it gets to the end of that block, or when it runs out of data. + + Full_Flush : constant Flush_Mode; + -- All output is flushed as with SYNC_FLUSH, and the compression state + -- is reset so that decompression can restart from this point if previous + -- compressed data has been damaged or if random access is desired. Using + -- Full_Flush too often can seriously degrade the compression. + + Finish : constant Flush_Mode; + -- Just for tell the compressor that input data is complete. + + ------------------------------------ + -- Compression strategy constants -- + ------------------------------------ + + -- RLE stategy could be used only in version 1.2.0 and later. + + Filtered : constant Strategy_Type; + Huffman_Only : constant Strategy_Type; + RLE : constant Strategy_Type; + Default_Strategy : constant Strategy_Type; + + Default_Buffer_Size : constant := 4096; + + type Filter_Type is tagged limited private; + -- The filter is for compression and for decompression. + -- The usage of the type is depend of its initialization. + + function Version return String; + pragma Inline (Version); + -- Return string representation of the ZLib version. + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Memory_Level : in Memory_Level_Type := Default_Memory_Level; + Header : in Header_Type := Default); + -- Compressor initialization. + -- When Header parameter is Auto or Default, then default zlib header + -- would be provided for compressed data. + -- When Header is GZip, then gzip header would be set instead of + -- default header. + -- When Header is None, no header would be set for compressed data. + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Header : in Header_Type := Default); + -- Decompressor initialization. + -- Default header type mean that ZLib default header is expecting in the + -- input compressed stream. + -- Header type None mean that no header is expecting in the input stream. + -- GZip header type mean that GZip header is expecting in the + -- input compressed stream. + -- Auto header type mean that header type (GZip or Native) would be + -- detected automatically in the input stream. + -- Note that header types parameter values None, GZip and Auto are + -- supported for inflate routine only in ZLib versions 1.2.0.2 and later. + -- Deflate_Init is supporting all header types. + + function Is_Open (Filter : in Filter_Type) return Boolean; + pragma Inline (Is_Open); + -- Is the filter opened for compression or decompression. + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False); + -- Closing the compression or decompressor. + -- If stream is closing before the complete and Ignore_Error is False, + -- The exception would be raised. + + generic + with procedure Data_In + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + with procedure Data_Out + (Item : in Ada.Streams.Stream_Element_Array); + procedure Generic_Translate + (Filter : in out Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size); + -- Compress/decompress data fetch from Data_In routine and pass the result + -- to the Data_Out routine. User should provide Data_In and Data_Out + -- for compression/decompression data flow. + -- Compression or decompression depend on Filter initialization. + + function Total_In (Filter : in Filter_Type) return Count; + pragma Inline (Total_In); + -- Returns total number of input bytes read so far + + function Total_Out (Filter : in Filter_Type) return Count; + pragma Inline (Total_Out); + -- Returns total number of bytes output so far + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32; + pragma Inline (CRC32); + -- Compute CRC32, it could be necessary for make gzip format + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array); + pragma Inline (CRC32); + -- Compute CRC32, it could be necessary for make gzip format + + ------------------------------------------------- + -- Below is more complex low level routines. -- + ------------------------------------------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Compress/decompress the In_Data buffer and place the result into + -- Out_Data. In_Last is the index of last element from In_Data accepted by + -- the Filter. Out_Last is the last element of the received data from + -- Filter. To tell the filter that incoming data are complete put the + -- Flush parameter to Finish. + + function Stream_End (Filter : in Filter_Type) return Boolean; + pragma Inline (Stream_End); + -- Return the true when the stream is complete. + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + pragma Inline (Flush); + -- Flushing the data from the compressor. + + generic + with procedure Write + (Item : in Ada.Streams.Stream_Element_Array); + -- User should provide this routine for accept + -- compressed/decompressed data. + + Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + -- Buffer size for Write user routine. + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode := No_Flush); + -- Compress/Decompress data from Item to the generic parameter procedure + -- Write. Output buffer size could be set in Buffer_Size generic parameter. + + generic + with procedure Read + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + -- User should provide data for compression/decompression + -- thru this routine. + + Buffer : in out Ada.Streams.Stream_Element_Array; + -- Buffer for keep remaining data from the previous + -- back read. + + Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset; + -- Rest_First have to be initialized to Buffer'Last + 1 + -- Rest_Last have to be initialized to Buffer'Last + -- before usage. + + Allow_Read_Some : in Boolean := False; + -- Is it allowed to return Last < Item'Last before end of data. + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode := No_Flush); + -- Compress/Decompress data from generic parameter procedure Read to the + -- Item. User should provide Buffer and initialized Rest_First, Rest_Last + -- indicators. If Allow_Read_Some is True, Read routines could return + -- Last < Item'Last only at end of stream. + +private + + use Ada.Streams; + + pragma Assert (Ada.Streams.Stream_Element'Size = 8); + pragma Assert (Ada.Streams.Stream_Element'Modulus = 2**8); + + type Flush_Mode is new Integer range 0 .. 5; + + type Compression_Method is new Integer range 8 .. 8; + + type Strategy_Type is new Integer range 0 .. 3; + + No_Flush : constant Flush_Mode := 0; + Partial_Flush : constant Flush_Mode := 1; + Sync_Flush : constant Flush_Mode := 2; + Full_Flush : constant Flush_Mode := 3; + Finish : constant Flush_Mode := 4; + Block_Flush : constant Flush_Mode := 5; + + Filtered : constant Strategy_Type := 1; + Huffman_Only : constant Strategy_Type := 2; + RLE : constant Strategy_Type := 3; + Default_Strategy : constant Strategy_Type := 0; + + Deflated : constant Compression_Method := 8; + + type Z_Stream; + + type Z_Stream_Access is access all Z_Stream; + + type Filter_Type is tagged limited record + Strm : Z_Stream_Access; + Compression : Boolean; + Stream_End : Boolean; + Header : Header_Type; + CRC : Unsigned_32; + Offset : Stream_Element_Offset; + -- Offset for gzip header/footer output. + end record; + +end ZLib; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.gpr b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.gpr new file mode 100644 index 00000000..296b22aa --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/ada/zlib.gpr @@ -0,0 +1,20 @@ +project Zlib is + + for Languages use ("Ada"); + for Source_Dirs use ("."); + for Object_Dir use "."; + for Main use ("test.adb", "mtest.adb", "read.adb", "buffer_demo"); + + package Compiler is + for Default_Switches ("ada") use ("-gnatwcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst"); + end Compiler; + + package Linker is + for Default_Switches ("ada") use ("-lz"); + end Linker; + + package Builder is + for Default_Switches ("ada") use ("-s", "-gnatQ"); + end Builder; + +end Zlib; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/amd64/amd64-match.S b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/amd64/amd64-match.S new file mode 100644 index 00000000..81d4a1c9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/amd64/amd64-match.S @@ -0,0 +1,452 @@ +/* + * match.S -- optimized version of longest_match() + * based on the similar work by Gilles Vollant, and Brian Raiter, written 1998 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the BSD License. Use by owners of Che Guevarra + * parafernalia is prohibited, where possible, and highly discouraged + * elsewhere. + */ + +#ifndef NO_UNDERLINE +# define match_init _match_init +# define longest_match _longest_match +#endif + +#define scanend ebx +#define scanendw bx +#define chainlenwmask edx /* high word: current chain len low word: s->wmask */ +#define curmatch rsi +#define curmatchd esi +#define windowbestlen r8 +#define scanalign r9 +#define scanalignd r9d +#define window r10 +#define bestlen r11 +#define bestlend r11d +#define scanstart r12d +#define scanstartw r12w +#define scan r13 +#define nicematch r14d +#define limit r15 +#define limitd r15d +#define prev rcx + +/* + * The 258 is a "magic number, not a parameter -- changing it + * breaks the hell loose + */ +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ +#define LocalVarsSize (112) +#define _chainlenwmask ( 8-LocalVarsSize)(%rsp) +#define _windowbestlen (16-LocalVarsSize)(%rsp) +#define save_r14 (24-LocalVarsSize)(%rsp) +#define save_rsi (32-LocalVarsSize)(%rsp) +#define save_rbx (40-LocalVarsSize)(%rsp) +#define save_r12 (56-LocalVarsSize)(%rsp) +#define save_r13 (64-LocalVarsSize)(%rsp) +#define save_r15 (80-LocalVarsSize)(%rsp) + + +.globl match_init, longest_match + +/* + * On AMD64 the first argument of a function (in our case -- the pointer to + * deflate_state structure) is passed in %rdi, hence our offsets below are + * all off of that. + */ + +/* you can check the structure offset by running + +#include +#include +#include "deflate.h" + +void print_depl() +{ +deflate_state ds; +deflate_state *s=&ds; +printf("size pointer=%u\n",(int)sizeof(void*)); + +printf("#define dsWSize (%3u)(%%rdi)\n",(int)(((char*)&(s->w_size))-((char*)s))); +printf("#define dsWMask (%3u)(%%rdi)\n",(int)(((char*)&(s->w_mask))-((char*)s))); +printf("#define dsWindow (%3u)(%%rdi)\n",(int)(((char*)&(s->window))-((char*)s))); +printf("#define dsPrev (%3u)(%%rdi)\n",(int)(((char*)&(s->prev))-((char*)s))); +printf("#define dsMatchLen (%3u)(%%rdi)\n",(int)(((char*)&(s->match_length))-((char*)s))); +printf("#define dsPrevMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_match))-((char*)s))); +printf("#define dsStrStart (%3u)(%%rdi)\n",(int)(((char*)&(s->strstart))-((char*)s))); +printf("#define dsMatchStart (%3u)(%%rdi)\n",(int)(((char*)&(s->match_start))-((char*)s))); +printf("#define dsLookahead (%3u)(%%rdi)\n",(int)(((char*)&(s->lookahead))-((char*)s))); +printf("#define dsPrevLen (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_length))-((char*)s))); +printf("#define dsMaxChainLen (%3u)(%%rdi)\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); +printf("#define dsGoodMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->good_match))-((char*)s))); +printf("#define dsNiceMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->nice_match))-((char*)s))); +} + +*/ + + +/* + to compile for XCode 3.2 on MacOSX x86_64 + - run "gcc -g -c -DXCODE_MAC_X64_STRUCTURE amd64-match.S" + */ + + +#ifndef CURRENT_LINX_XCODE_MAC_X64_STRUCTURE +#define dsWSize ( 68)(%rdi) +#define dsWMask ( 76)(%rdi) +#define dsWindow ( 80)(%rdi) +#define dsPrev ( 96)(%rdi) +#define dsMatchLen (144)(%rdi) +#define dsPrevMatch (148)(%rdi) +#define dsStrStart (156)(%rdi) +#define dsMatchStart (160)(%rdi) +#define dsLookahead (164)(%rdi) +#define dsPrevLen (168)(%rdi) +#define dsMaxChainLen (172)(%rdi) +#define dsGoodMatch (188)(%rdi) +#define dsNiceMatch (192)(%rdi) + +#else + +#ifndef STRUCT_OFFSET +# define STRUCT_OFFSET (0) +#endif + + +#define dsWSize ( 56 + STRUCT_OFFSET)(%rdi) +#define dsWMask ( 64 + STRUCT_OFFSET)(%rdi) +#define dsWindow ( 72 + STRUCT_OFFSET)(%rdi) +#define dsPrev ( 88 + STRUCT_OFFSET)(%rdi) +#define dsMatchLen (136 + STRUCT_OFFSET)(%rdi) +#define dsPrevMatch (140 + STRUCT_OFFSET)(%rdi) +#define dsStrStart (148 + STRUCT_OFFSET)(%rdi) +#define dsMatchStart (152 + STRUCT_OFFSET)(%rdi) +#define dsLookahead (156 + STRUCT_OFFSET)(%rdi) +#define dsPrevLen (160 + STRUCT_OFFSET)(%rdi) +#define dsMaxChainLen (164 + STRUCT_OFFSET)(%rdi) +#define dsGoodMatch (180 + STRUCT_OFFSET)(%rdi) +#define dsNiceMatch (184 + STRUCT_OFFSET)(%rdi) + +#endif + + + + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ + +longest_match: +/* + * Retrieve the function arguments. %curmatch will hold cur_match + * throughout the entire function (passed via rsi on amd64). + * rdi will hold the pointer to the deflate_state (first arg on amd64) + */ + mov %rsi, save_rsi + mov %rbx, save_rbx + mov %r12, save_r12 + mov %r13, save_r13 + mov %r14, save_r14 + mov %r15, save_r15 + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen, %eax + movl dsGoodMatch, %ebx + cmpl %ebx, %eax + movl dsWMask, %eax + movl dsMaxChainLen, %chainlenwmask + jl LastMatchGood + shrl $2, %chainlenwmask +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %chainlenwmask + shll $16, %chainlenwmask + orl %eax, %chainlenwmask + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch, %eax + movl dsLookahead, %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, %nicematch + +/* register Bytef *scan = s->window + s->strstart; */ + + mov dsWindow, %window + movl dsStrStart, %limitd + lea (%limit, %window), %scan + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + mov %scan, %scanalign + negl %scanalignd + andl $3, %scanalignd + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize, %eax + subl $MIN_LOOKAHEAD, %eax + xorl %ecx, %ecx + subl %eax, %limitd + cmovng %ecx, %limitd + +/* int best_len = s->prev_length; */ + + movl dsPrevLen, %bestlend + +/* Store the sum of s->window + best_len in %windowbestlen locally, and in memory. */ + + lea (%window, %bestlen), %windowbestlen + mov %windowbestlen, _windowbestlen + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%scan), %scanstart + movzwl -1(%scan, %bestlen), %scanend + mov dsPrev, %prev + +/* Jump into the main loop. */ + + movl %chainlenwmask, _chainlenwmask + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + */ +LookupLoop: + andl %chainlenwmask, %curmatchd + movzwl (%prev, %curmatch, 2), %curmatchd + cmpl %limitd, %curmatchd + jbe LeaveNow + subl $0x00010000, %chainlenwmask + js LeaveNow +LoopEntry: cmpw -1(%windowbestlen, %curmatch), %scanendw + jne LookupLoop + cmpw %scanstartw, (%window, %curmatch) + jne LookupLoop + +/* Store the current value of chainlen. */ + movl %chainlenwmask, _chainlenwmask + +/* %scan is the string under scrutiny, and %prev to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + mov $(-MAX_MATCH_8), %rdx + lea (%curmatch, %window), %windowbestlen + lea MAX_MATCH_8(%windowbestlen, %scanalign), %windowbestlen + lea MAX_MATCH_8(%scan, %scanalign), %prev + +/* the prefetching below makes very little difference... */ + prefetcht1 (%windowbestlen, %rdx) + prefetcht1 (%prev, %rdx) + +/* + * Test the strings for equality, 8 bytes at a time. At the end, + * adjust %rdx so that it is offset to the exact byte that mismatched. + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance -- unrolling it, for example, makes no difference. + */ + +#undef USE_SSE /* works, but is 6-7% slower, than non-SSE... */ + +LoopCmps: +#ifdef USE_SSE + /* Preload the SSE registers */ + movdqu (%windowbestlen, %rdx), %xmm1 + movdqu (%prev, %rdx), %xmm2 + pcmpeqb %xmm2, %xmm1 + movdqu 16(%windowbestlen, %rdx), %xmm3 + movdqu 16(%prev, %rdx), %xmm4 + pcmpeqb %xmm4, %xmm3 + movdqu 32(%windowbestlen, %rdx), %xmm5 + movdqu 32(%prev, %rdx), %xmm6 + pcmpeqb %xmm6, %xmm5 + movdqu 48(%windowbestlen, %rdx), %xmm7 + movdqu 48(%prev, %rdx), %xmm8 + pcmpeqb %xmm8, %xmm7 + + /* Check the comparisions' results */ + pmovmskb %xmm1, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + /* this is the only iteration of the loop with a possibility of having + incremented rdx by 0x108 (each loop iteration add 16*4 = 0x40 + and (0x40*4)+8=0x108 */ + add $8, %rdx + jz LenMaximum + add $8, %rdx + + + pmovmskb %xmm3, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + + add $16, %rdx + + + pmovmskb %xmm5, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + add $16, %rdx + + + pmovmskb %xmm7, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + add $16, %rdx + + jmp LoopCmps +LeaveLoopCmps: add %rax, %rdx +#else + mov (%windowbestlen, %rdx), %rax + xor (%prev, %rdx), %rax + jnz LeaveLoopCmps + + mov 8(%windowbestlen, %rdx), %rax + xor 8(%prev, %rdx), %rax + jnz LeaveLoopCmps8 + + mov 16(%windowbestlen, %rdx), %rax + xor 16(%prev, %rdx), %rax + jnz LeaveLoopCmps16 + + add $24, %rdx + jnz LoopCmps + jmp LenMaximum +# if 0 +/* + * This three-liner is tantalizingly simple, but bsf is a slow instruction, + * and the complicated alternative down below is quite a bit faster. Sad... + */ + +LeaveLoopCmps: bsf %rax, %rax /* find the first non-zero bit */ + shrl $3, %eax /* divide by 8 to get the byte */ + add %rax, %rdx +# else +LeaveLoopCmps16: + add $8, %rdx +LeaveLoopCmps8: + add $8, %rdx +LeaveLoopCmps: testl $0xFFFFFFFF, %eax /* Check the first 4 bytes */ + jnz Check16 + add $4, %rdx + shr $32, %rax +Check16: testw $0xFFFF, %ax + jnz LenLower + add $2, %rdx + shrl $16, %eax +LenLower: subb $1, %al + adc $0, %rdx +# endif +#endif + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%prev, %rdx), %rax + sub %scan, %rax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + cmpl %bestlend, %eax + jg LongerMatch + mov _windowbestlen, %windowbestlen + mov dsPrev, %prev + movl _chainlenwmask, %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: + movl %eax, %bestlend + movl %curmatchd, dsMatchStart + cmpl %nicematch, %eax + jge LeaveNow + + lea (%window, %bestlen), %windowbestlen + mov %windowbestlen, _windowbestlen + + movzwl -1(%scan, %rax), %scanend + mov dsPrev, %prev + movl _chainlenwmask, %chainlenwmask + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: + movl $MAX_MATCH, %bestlend + movl %curmatchd, dsMatchStart + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl dsLookahead, %eax + cmpl %eax, %bestlend + cmovngl %bestlend, %eax +LookaheadRet: + +/* Restore the registers and return from whence we came. */ + + mov save_rsi, %rsi + mov save_rbx, %rbx + mov save_r12, %r12 + mov save_r13, %r13 + mov save_r14, %r14 + mov save_r15, %r15 + + ret + +match_init: ret diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/asm686/README.686 b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/asm686/README.686 new file mode 100644 index 00000000..a0bf3bea --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/asm686/README.686 @@ -0,0 +1,51 @@ +This is a patched version of zlib, modified to use +Pentium-Pro-optimized assembly code in the deflation algorithm. The +files changed/added by this patch are: + +README.686 +match.S + +The speedup that this patch provides varies, depending on whether the +compiler used to build the original version of zlib falls afoul of the +PPro's speed traps. My own tests show a speedup of around 10-20% at +the default compression level, and 20-30% using -9, against a version +compiled using gcc 2.7.2.3. Your mileage may vary. + +Note that this code has been tailored for the PPro/PII in particular, +and will not perform particuarly well on a Pentium. + +If you are using an assembler other than GNU as, you will have to +translate match.S to use your assembler's syntax. (Have fun.) + +Brian Raiter +breadbox@muppetlabs.com +April, 1998 + + +Added for zlib 1.1.3: + +The patches come from +http://www.muppetlabs.com/~breadbox/software/assembly.html + +To compile zlib with this asm file, copy match.S to the zlib directory +then do: + +CFLAGS="-O3 -DASMV" ./configure +make OBJA=match.o + + +Update: + +I've been ignoring these assembly routines for years, believing that +gcc's generated code had caught up with it sometime around gcc 2.95 +and the major rearchitecting of the Pentium 4. However, I recently +learned that, despite what I believed, this code still has some life +in it. On the Pentium 4 and AMD64 chips, it continues to run about 8% +faster than the code produced by gcc 4.1. + +In acknowledgement of its continuing usefulness, I've altered the +license to match that of the rest of zlib. Share and Enjoy! + +Brian Raiter +breadbox@muppetlabs.com +April, 2007 diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/asm686/match.S b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/asm686/match.S new file mode 100644 index 00000000..06817e1d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/asm686/match.S @@ -0,0 +1,343 @@ +/* match.S -- x86 assembly version of the zlib longest_match() function. + * Optimized for the Intel 686 chips (PPro and later). + * + * Copyright (C) 1998, 2007 Brian Raiter + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the author be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef NO_UNDERLINE +#define match_init _match_init +#define longest_match _longest_match +#endif + +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ + +#define chainlenwmask 0 /* high word: current chain len */ + /* low word: s->wmask */ +#define window 4 /* local copy of s->window */ +#define windowbestlen 8 /* s->window + bestlen */ +#define scanstart 16 /* first two bytes of string */ +#define scanend 12 /* last two bytes of string */ +#define scanalign 20 /* dword-misalignment of string */ +#define nicematch 24 /* a good enough match size */ +#define bestlen 28 /* size of best match so far */ +#define scan 32 /* ptr to string wanting match */ + +#define LocalVarsSize (36) +/* saved ebx 36 */ +/* saved edi 40 */ +/* saved esi 44 */ +/* saved ebp 48 */ +/* return address 52 */ +#define deflatestate 56 /* the function arguments */ +#define curmatch 60 + +/* All the +zlib1222add offsets are due to the addition of fields + * in zlib in the deflate_state structure since the asm code was first written + * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). + * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). + * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + */ + +#define zlib1222add (8) + +#define dsWSize (36+zlib1222add) +#define dsWMask (44+zlib1222add) +#define dsWindow (48+zlib1222add) +#define dsPrev (56+zlib1222add) +#define dsMatchLen (88+zlib1222add) +#define dsPrevMatch (92+zlib1222add) +#define dsStrStart (100+zlib1222add) +#define dsMatchStart (104+zlib1222add) +#define dsLookahead (108+zlib1222add) +#define dsPrevLen (112+zlib1222add) +#define dsMaxChainLen (116+zlib1222add) +#define dsGoodMatch (132+zlib1222add) +#define dsNiceMatch (136+zlib1222add) + + +.file "match.S" + +.globl match_init, longest_match + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ + +longest_match: + +/* Save registers that the compiler may be using, and adjust %esp to */ +/* make room for our stack frame. */ + + pushl %ebp + pushl %edi + pushl %esi + pushl %ebx + subl $LocalVarsSize, %esp + +/* Retrieve the function arguments. %ecx will hold cur_match */ +/* throughout the entire function. %edx will hold the pointer to the */ +/* deflate_state structure during the function's setup (before */ +/* entering the main loop). */ + + movl deflatestate(%esp), %edx + movl curmatch(%esp), %ecx + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen(%edx), %eax + movl dsGoodMatch(%edx), %ebx + cmpl %ebx, %eax + movl dsWMask(%edx), %eax + movl dsMaxChainLen(%edx), %ebx + jl LastMatchGood + shrl $2, %ebx +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %ebx + shll $16, %ebx + orl %eax, %ebx + movl %ebx, chainlenwmask(%esp) + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch(%edx), %eax + movl dsLookahead(%edx), %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, nicematch(%esp) + +/* register Bytef *scan = s->window + s->strstart; */ + + movl dsWindow(%edx), %esi + movl %esi, window(%esp) + movl dsStrStart(%edx), %ebp + lea (%esi,%ebp), %edi + movl %edi, scan(%esp) + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + movl %edi, %eax + negl %eax + andl $3, %eax + movl %eax, scanalign(%esp) + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize(%edx), %eax + subl $MIN_LOOKAHEAD, %eax + subl %eax, %ebp + jg LimitPositive + xorl %ebp, %ebp +LimitPositive: + +/* int best_len = s->prev_length; */ + + movl dsPrevLen(%edx), %eax + movl %eax, bestlen(%esp) + +/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ + + addl %eax, %esi + movl %esi, windowbestlen(%esp) + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%edi), %ebx + movl %ebx, scanstart(%esp) + movzwl -1(%edi,%eax), %ebx + movl %ebx, scanend(%esp) + movl dsPrev(%edx), %edi + +/* Jump into the main loop. */ + + movl chainlenwmask(%esp), %edx + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + * + * Within this loop: + * %ebx = scanend + * %ecx = curmatch + * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) + * %esi = windowbestlen - i.e., (window + bestlen) + * %edi = prev + * %ebp = limit + */ +LookupLoop: + andl %edx, %ecx + movzwl (%edi,%ecx,2), %ecx + cmpl %ebp, %ecx + jbe LeaveNow + subl $0x00010000, %edx + js LeaveNow +LoopEntry: movzwl -1(%esi,%ecx), %eax + cmpl %ebx, %eax + jnz LookupLoop + movl window(%esp), %eax + movzwl (%eax,%ecx), %eax + cmpl scanstart(%esp), %eax + jnz LookupLoop + +/* Store the current value of chainlen. */ + + movl %edx, chainlenwmask(%esp) + +/* Point %edi to the string under scrutiny, and %esi to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + movl window(%esp), %esi + movl scan(%esp), %edi + addl %ecx, %esi + movl scanalign(%esp), %eax + movl $(-MAX_MATCH_8), %edx + lea MAX_MATCH_8(%edi,%eax), %edi + lea MAX_MATCH_8(%esi,%eax), %esi + +/* Test the strings for equality, 8 bytes at a time. At the end, + * adjust %edx so that it is offset to the exact byte that mismatched. + * + * We already know at this point that the first three bytes of the + * strings match each other, and they can be safely passed over before + * starting the compare loop. So what this code does is skip over 0-3 + * bytes, as much as necessary in order to dword-align the %edi + * pointer. (%esi will still be misaligned three times out of four.) + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance. + */ +LoopCmps: + movl (%esi,%edx), %eax + xorl (%edi,%edx), %eax + jnz LeaveLoopCmps + movl 4(%esi,%edx), %eax + xorl 4(%edi,%edx), %eax + jnz LeaveLoopCmps4 + addl $8, %edx + jnz LoopCmps + jmp LenMaximum +LeaveLoopCmps4: addl $4, %edx +LeaveLoopCmps: testl $0x0000FFFF, %eax + jnz LenLower + addl $2, %edx + shrl $16, %eax +LenLower: subb $1, %al + adcl $0, %edx + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%edi,%edx), %eax + movl scan(%esp), %edi + subl %edi, %eax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + cmpl %ebx, %eax + jg LongerMatch + movl windowbestlen(%esp), %esi + movl dsPrev(%edx), %edi + movl scanend(%esp), %ebx + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: movl nicematch(%esp), %ebx + movl %eax, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + cmpl %ebx, %eax + jge LeaveNow + movl window(%esp), %esi + addl %eax, %esi + movl %esi, windowbestlen(%esp) + movzwl -1(%edi,%eax), %ebx + movl dsPrev(%edx), %edi + movl %ebx, scanend(%esp) + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: movl deflatestate(%esp), %edx + movl $MAX_MATCH, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + movl dsLookahead(%edx), %eax + cmpl %eax, %ebx + jg LookaheadRet + movl %ebx, %eax +LookaheadRet: + +/* Restore the stack and return from whence we came. */ + + addl $LocalVarsSize, %esp + popl %ebx + popl %esi + popl %edi + popl %ebp +match_init: ret diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/Makefile b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/Makefile new file mode 100644 index 00000000..9be80baf --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/Makefile @@ -0,0 +1,8 @@ +blast: blast.c blast.h + cc -DTEST -o blast blast.c + +test: blast + blast < test.pk | cmp - test.txt + +clean: + rm -f blast blast.o diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/README new file mode 100644 index 00000000..e3a60b3f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/README @@ -0,0 +1,4 @@ +Read blast.h for purpose and usage. + +Mark Adler +madler@alumni.caltech.edu diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/blast.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/blast.c new file mode 100644 index 00000000..4ce697a4 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/blast.c @@ -0,0 +1,444 @@ +/* blast.c + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in blast.h + * version 1.1, 16 Feb 2003 + * + * blast.c decompresses data compressed by the PKWare Compression Library. + * This function provides functionality similar to the explode() function of + * the PKWare library, hence the name "blast". + * + * This decompressor is based on the excellent format description provided by + * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the + * example Ben provided in the post is incorrect. The distance 110001 should + * instead be 111000. When corrected, the example byte stream becomes: + * + * 00 04 82 24 25 8f 80 7f + * + * which decompresses to "AIAIAIAIAIAIA" (without the quotes). + */ + +/* + * Change history: + * + * 1.0 12 Feb 2003 - First version + * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "blast.h" /* prototype for blast() */ + +#define local static /* for local function definitions */ +#define MAXBITS 13 /* maximum code length */ +#define MAXWIN 4096 /* maximum window size */ + +/* input and output state */ +struct state { + /* input state */ + blast_in infun; /* input function provided by user */ + void *inhow; /* opaque information passed to infun() */ + unsigned char *in; /* next input location */ + unsigned left; /* available input at in */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; + + /* output state */ + blast_out outfun; /* output function provided by user */ + void *outhow; /* opaque information passed to outfun() */ + unsigned next; /* index of next write location in out[] */ + int first; /* true to check distances (for first 4K) */ + unsigned char out[MAXWIN]; /* output buffer and sliding window */ +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + int val; /* bit accumulator */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ + s->left--; + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = val >> need; + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return val & ((1 << need) - 1); +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. + * + * - The first code for the shortest length is all ones. Subsequent codes of + * the same length are simply integer decrements of the previous code. When + * moving up a length, a one bit is appended to the code. For a complete + * code, the last code of the longest length will be all zeros. To support + * this ordering, the bits pulled during decoding are inverted to apply the + * more "natural" ordering starting with all zeros and incrementing. + */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= (bitbuf & 1) ^ 1; /* invert code */ + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + bitbuf = *(s->in)++; + s->left--; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} + +/* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + */ +local int construct(struct huffman *h, const unsigned char *rep, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short length[256]; /* code lengths */ + + /* convert compact repeat counts into symbol bit length list */ + symbol = 0; + do { + len = *rep++; + left = (len >> 4) + 1; + len &= 15; + do { + length[symbol++] = len; + } while (--left); + } while (--n); + n = symbol; + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode PKWare Compression Library stream. + * + * Format notes: + * + * - First byte is 0 if literals are uncoded or 1 if they are coded. Second + * byte is 4, 5, or 6 for the number of extra bits in the distance code. + * This is the base-2 logarithm of the dictionary size minus six. + * + * - Compressed data is a combination of literals and length/distance pairs + * terminated by an end code. Literals are either Huffman coded or + * uncoded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - A bit preceding a literal or length/distance pair indicates which comes + * next, 0 for literals, 1 for length/distance. + * + * - If literals are uncoded, then the next eight bits are the literal, in the + * normal bit order in th stream, i.e. no bit-reversal is needed. Similarly, + * no bit reversal is needed for either the length extra bits or the distance + * extra bits. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 518 + * simply copies the last byte 518 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. + */ +local int decomp(struct state *s) +{ + int lit; /* true if literals are coded */ + int dict; /* log2(dictionary size) - 6 */ + int symbol; /* decoded symbol, extra bits for distance */ + int len; /* length for copy */ + int dist; /* distance for copy */ + int copy; /* copy counter */ + unsigned char *from, *to; /* copy pointers */ + static int virgin = 1; /* build tables once */ + static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ + static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ + static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ + static struct huffman litcode = {litcnt, litsym}; /* length code */ + static struct huffman lencode = {lencnt, lensym}; /* length code */ + static struct huffman distcode = {distcnt, distsym};/* distance code */ + /* bit lengths of literal codes */ + static const unsigned char litlen[] = { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, + 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, + 44, 173}; + /* bit lengths of length codes 0..15 */ + static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; + /* bit lengths of distance codes 0..63 */ + static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; + static const short base[16] = { /* base for length codes */ + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; + static const char extra[16] = { /* extra bits for length codes */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; + + /* set up decoding tables (once--might not be thread-safe) */ + if (virgin) { + construct(&litcode, litlen, sizeof(litlen)); + construct(&lencode, lenlen, sizeof(lenlen)); + construct(&distcode, distlen, sizeof(distlen)); + virgin = 0; + } + + /* read header */ + lit = bits(s, 8); + if (lit > 1) return -1; + dict = bits(s, 8); + if (dict < 4 || dict > 6) return -2; + + /* decode literals and length/distance pairs */ + do { + if (bits(s, 1)) { + /* get length */ + symbol = decode(s, &lencode); + len = base[symbol] + bits(s, extra[symbol]); + if (len == 519) break; /* end code */ + + /* get distance */ + symbol = len == 2 ? 2 : dict; + dist = decode(s, &distcode) << symbol; + dist += bits(s, symbol); + dist++; + if (s->first && dist > s->next) + return -3; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + do { + to = s->out + s->next; + from = to - dist; + copy = MAXWIN; + if (s->next < dist) { + from += copy; + copy = dist; + } + copy -= s->next; + if (copy > len) copy = len; + len -= copy; + s->next += copy; + do { + *to++ = *from++; + } while (--copy); + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } while (len != 0); + } + else { + /* get literal and write it */ + symbol = lit ? decode(s, &litcode) : bits(s, 8); + s->out[s->next++] = symbol; + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } + } while (1); + return 0; +} + +/* See comments in blast.h */ +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow) +{ + struct state s; /* input/output state */ + int err; /* return value */ + + /* initialize input state */ + s.infun = infun; + s.inhow = inhow; + s.left = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* initialize output state */ + s.outfun = outfun; + s.outhow = outhow; + s.next = 0; + s.first = 1; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ + err = 2; /* then skip decomp(), return error */ + else + err = decomp(&s); /* decompress */ + + /* write any leftover output and update the error code if needed */ + if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) + err = 1; + return err; +} + +#ifdef TEST +/* Example of how to use blast() */ +#include +#include + +#define CHUNK 16384 + +local unsigned inf(void *how, unsigned char **buf) +{ + static unsigned char hold[CHUNK]; + + *buf = hold; + return fread(hold, 1, CHUNK, (FILE *)how); +} + +local int outf(void *how, unsigned char *buf, unsigned len) +{ + return fwrite(buf, 1, len, (FILE *)how) != len; +} + +/* Decompress a PKWare Compression Library stream from stdin to stdout */ +int main(void) +{ + int ret, n; + + /* decompress to stdout */ + ret = blast(inf, stdin, outf, stdout); + if (ret != 0) fprintf(stderr, "blast error: %d\n", ret); + + /* see if there are any leftover bytes */ + n = 0; + while (getchar() != EOF) n++; + if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n); + + /* return blast() error code */ + return ret; +} +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/blast.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/blast.h new file mode 100644 index 00000000..ce9e5410 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/blast.h @@ -0,0 +1,71 @@ +/* blast.h -- interface for blast.c + Copyright (C) 2003 Mark Adler + version 1.1, 16 Feb 2003 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * blast() decompresses the PKWare Data Compression Library (DCL) compressed + * format. It provides the same functionality as the explode() function in + * that library. (Note: PKWare overused the "implode" verb, and the format + * used by their library implode() function is completely different and + * incompatible with the implode compression method supported by PKZIP.) + */ + + +typedef unsigned (*blast_in)(void *how, unsigned char **buf); +typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); +/* Definitions for input/output functions passed to blast(). See below for + * what the provided functions need to do. + */ + + +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow); +/* Decompress input to output using the provided infun() and outfun() calls. + * On success, the return value of blast() is zero. If there is an error in + * the source data, i.e. it is not in the proper format, then a negative value + * is returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. + * + * The input function is invoked: len = infun(how, &buf), where buf is set by + * infun() to point to the input buffer, and infun() returns the number of + * available bytes there. If infun() returns zero, then blast() returns with + * an input error. (blast() only asks for input if it needs it.) inhow is for + * use by the application to pass an input descriptor to infun(), if desired. + * + * The output function is invoked: err = outfun(how, buf, len), where the bytes + * to be written are buf[0..len-1]. If err is not zero, then blast() returns + * with an output error. outfun() is always called with len <= 4096. outhow + * is for use by the application to pass an output descriptor to outfun(), if + * desired. + * + * The return codes are: + * + * 2: ran out of input before completing decompression + * 1: output error before completing decompression + * 0: successful decompression + * -1: literal flag not zero or one + * -2: dictionary size not in 4..6 + * -3: distance is too far back + * + * At the bottom of blast.c is an example program that uses blast() that can be + * compiled to produce a command-line decompression filter by defining TEST. + */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/test.pk b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/test.pk new file mode 100644 index 00000000..be10b2bb Binary files /dev/null and b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/test.pk differ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/test.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/test.txt new file mode 100644 index 00000000..bfdf1c5d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/blast/test.txt @@ -0,0 +1 @@ +AIAIAIAIAIAIA \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/ZLib.pas b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/ZLib.pas new file mode 100644 index 00000000..0d86fb52 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/ZLib.pas @@ -0,0 +1,557 @@ +{*******************************************************} +{ } +{ Borland Delphi Supplemental Components } +{ ZLIB Data Compression Interface Unit } +{ } +{ Copyright (c) 1997,99 Borland Corporation } +{ } +{*******************************************************} + +{ Updated for zlib 1.2.x by Cosmin Truta } + +unit ZLib; + +interface + +uses SysUtils, Classes; + +type + TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl; + TFree = procedure (AppData, Block: Pointer); cdecl; + + // Internal structure. Ignore. + TZStreamRec = packed record + next_in: PChar; // next input byte + avail_in: Integer; // number of bytes available at next_in + total_in: Longint; // total nb of input bytes read so far + + next_out: PChar; // next output byte should be put here + avail_out: Integer; // remaining free space at next_out + total_out: Longint; // total nb of bytes output so far + + msg: PChar; // last error message, NULL if no error + internal: Pointer; // not visible by applications + + zalloc: TAlloc; // used to allocate the internal state + zfree: TFree; // used to free the internal state + AppData: Pointer; // private data object passed to zalloc and zfree + + data_type: Integer; // best guess about the data type: ascii or binary + adler: Longint; // adler32 value of the uncompressed data + reserved: Longint; // reserved for future use + end; + + // Abstract ancestor class + TCustomZlibStream = class(TStream) + private + FStrm: TStream; + FStrmPos: Integer; + FOnProgress: TNotifyEvent; + FZRec: TZStreamRec; + FBuffer: array [Word] of Char; + protected + procedure Progress(Sender: TObject); dynamic; + property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; + constructor Create(Strm: TStream); + end; + +{ TCompressionStream compresses data on the fly as data is written to it, and + stores the compressed data to another stream. + + TCompressionStream is write-only and strictly sequential. Reading from the + stream will raise an exception. Using Seek to move the stream pointer + will raise an exception. + + Output data is cached internally, written to the output stream only when + the internal output buffer is full. All pending output data is flushed + when the stream is destroyed. + + The Position property returns the number of uncompressed bytes of + data that have been written to the stream so far. + + CompressionRate returns the on-the-fly percentage by which the original + data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 + If raw data size = 100 and compressed data size = 25, the CompressionRate + is 75% + + The OnProgress event is called each time the output buffer is filled and + written to the output stream. This is useful for updating a progress + indicator when you are writing a large chunk of data to the compression + stream in a single call.} + + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + TCompressionStream = class(TCustomZlibStream) + private + function GetCompressionRate: Single; + public + constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property CompressionRate: Single read GetCompressionRate; + property OnProgress; + end; + +{ TDecompressionStream decompresses data on the fly as data is read from it. + + Compressed data comes from a separate source stream. TDecompressionStream + is read-only and unidirectional; you can seek forward in the stream, but not + backwards. The special case of setting the stream position to zero is + allowed. Seeking forward decompresses data until the requested position in + the uncompressed data has been reached. Seeking backwards, seeking relative + to the end of the stream, requesting the size of the stream, and writing to + the stream will raise an exception. + + The Position property returns the number of bytes of uncompressed data that + have been read from the stream so far. + + The OnProgress event is called each time the internal input buffer of + compressed data is exhausted and the next block is read from the input stream. + This is useful for updating a progress indicator when you are reading a + large chunk of data from the decompression stream in a single call.} + + TDecompressionStream = class(TCustomZlibStream) + public + constructor Create(Source: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress; + end; + + + +{ CompressBuf compresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); + + +{ DecompressBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + OutEstimate = zero, or est. size of the decompressed data + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); + +{ DecompressToUserBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to user-allocated buffer to contain decompressed data + BufSize = number of bytes in OutBuf } +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); + +const + zlib_version = '1.2.5'; + +type + EZlibError = class(Exception); + ECompressionError = class(EZlibError); + EDecompressionError = class(EZlibError); + +implementation + +uses ZLibConst; + +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = (-1); + Z_STREAM_ERROR = (-2); + Z_DATA_ERROR = (-3); + Z_MEM_ERROR = (-4); + Z_BUF_ERROR = (-5); + Z_VERSION_ERROR = (-6); + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = (-1); + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +procedure adler32; external; +procedure compressBound; external; +procedure crc32; external; +procedure deflateInit2_; external; +procedure deflateParams; external; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + Result := AllocMem(Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + + + +// deflate compresses data +function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar; + recsize: Integer): Integer; external; +function deflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function deflateEnd(var strm: TZStreamRec): Integer; external; + +// inflate decompresses data +function inflateInit_(var strm: TZStreamRec; version: PChar; + recsize: Integer): Integer; external; +function inflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function inflateEnd(var strm: TZStreamRec): Integer; external; +function inflateReset(var strm: TZStreamRec): Integer; external; + + +function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; +begin +// GetMem(Result, Items*Size); + Result := AllocMem(Items * Size); +end; + +procedure zlibFreeMem(AppData, Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +{function zlibCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EZlibError.Create('error'); //!! +end;} + +function CCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise ECompressionError.Create('error'); //!! +end; + +function DCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EDecompressionError.Create('error'); //!! +end; + +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm))); + try + while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, 256); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := 256; + end; + finally + CCheck(deflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + + +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; + BufInc: Integer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + BufInc := (InBytes + 255) and not 255; + if OutEstimate = 0 then + OutBytes := BufInc + else + OutBytes := OutEstimate; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, BufInc); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := BufInc; + end; + finally + DCheck(inflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); +var + strm: TZStreamRec; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := BufSize; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then + raise EZlibError.CreateRes(@sTargetBufferTooSmall); + finally + DCheck(inflateEnd(strm)); + end; +end; + +// TCustomZlibStream + +constructor TCustomZLibStream.Create(Strm: TStream); +begin + inherited Create; + FStrm := Strm; + FStrmPos := Strm.Position; + FZRec.zalloc := zlibAllocMem; + FZRec.zfree := zlibFreeMem; +end; + +procedure TCustomZLibStream.Progress(Sender: TObject); +begin + if Assigned(FOnProgress) then FOnProgress(Sender); +end; + + +// TCompressionStream + +constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel; + Dest: TStream); +const + Levels: array [TCompressionLevel] of ShortInt = + (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); +begin + inherited Create(Dest); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec))); +end; + +destructor TCompressionStream.Destroy; +begin + FZRec.next_in := nil; + FZRec.avail_in := 0; + try + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END) + and (FZRec.avail_out = 0) do + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + end; + if FZRec.avail_out < sizeof(FBuffer) then + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out); + finally + deflateEnd(FZRec); + end; + inherited Destroy; +end; + +function TCompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + FZRec.next_in := @Buffer; + FZRec.avail_in := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_in > 0) do + begin + CCheck(deflate(FZRec, 0)); + if FZRec.avail_out = 0 then + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + FStrmPos := FStrm.Position; + Progress(Self); + end; + end; + Result := Count; +end; + +function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := FZRec.total_in + else + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.GetCompressionRate: Single; +begin + if FZRec.total_in = 0 then + Result := 0 + else + Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0; +end; + + +// TDecompressionStream + +constructor TDecompressionStream.Create(Source: TStream); +begin + inherited Create(Source); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec))); +end; + +destructor TDecompressionStream.Destroy; +begin + FStrm.Seek(-FZRec.avail_in, 1); + inflateEnd(FZRec); + inherited Destroy; +end; + +function TDecompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + FZRec.next_out := @Buffer; + FZRec.avail_out := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_out > 0) do + begin + if FZRec.avail_in = 0 then + begin + FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); + if FZRec.avail_in = 0 then + begin + Result := Count - FZRec.avail_out; + Exit; + end; + FZRec.next_in := FBuffer; + FStrmPos := FStrm.Position; + Progress(Self); + end; + CCheck(inflate(FZRec, 0)); + end; + Result := Count; +end; + +function TDecompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + raise EDecompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +var + I: Integer; + Buf: array [0..4095] of Char; +begin + if (Offset = 0) and (Origin = soFromBeginning) then + begin + DCheck(inflateReset(FZRec)); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + FStrm.Position := 0; + FStrmPos := 0; + end + else if ( (Offset >= 0) and (Origin = soFromCurrent)) or + ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then + begin + if Origin = soFromBeginning then Dec(Offset, FZRec.total_out); + if Offset > 0 then + begin + for I := 1 to Offset div sizeof(Buf) do + ReadBuffer(Buf, sizeof(Buf)); + ReadBuffer(Buf, Offset mod sizeof(Buf)); + end; + end + else + raise EDecompressionError.CreateRes(@sInvalidStreamOp); + Result := FZRec.total_out; +end; + + +end. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/ZLibConst.pas b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/ZLibConst.pas new file mode 100644 index 00000000..cdfe1367 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/ZLibConst.pas @@ -0,0 +1,11 @@ +unit ZLibConst; + +interface + +resourcestring + sTargetBufferTooSmall = 'ZLib error: target buffer may be too small'; + sInvalidStreamOp = 'Invalid stream operation'; + +implementation + +end. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/readme.txt new file mode 100644 index 00000000..2dc9a8bb --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/readme.txt @@ -0,0 +1,76 @@ + +Overview +======== + +This directory contains an update to the ZLib interface unit, +distributed by Borland as a Delphi supplemental component. + +The original ZLib unit is Copyright (c) 1997,99 Borland Corp., +and is based on zlib version 1.0.4. There are a series of bugs +and security problems associated with that old zlib version, and +we recommend the users to update their ZLib unit. + + +Summary of modifications +======================== + +- Improved makefile, adapted to zlib version 1.2.1. + +- Some field types from TZStreamRec are changed from Integer to + Longint, for consistency with the zlib.h header, and for 64-bit + readiness. + +- The zlib_version constant is updated. + +- The new Z_RLE strategy has its corresponding symbolic constant. + +- The allocation and deallocation functions and function types + (TAlloc, TFree, zlibAllocMem and zlibFreeMem) are now cdecl, + and _malloc and _free are added as C RTL stubs. As a result, + the original C sources of zlib can be compiled out of the box, + and linked to the ZLib unit. + + +Suggestions for improvements +============================ + +Currently, the ZLib unit provides only a limited wrapper around +the zlib library, and much of the original zlib functionality is +missing. Handling compressed file formats like ZIP/GZIP or PNG +cannot be implemented without having this functionality. +Applications that handle these formats are either using their own, +duplicated code, or not using the ZLib unit at all. + +Here are a few suggestions: + +- Checksum class wrappers around adler32() and crc32(), similar + to the Java classes that implement the java.util.zip.Checksum + interface. + +- The ability to read and write raw deflate streams, without the + zlib stream header and trailer. Raw deflate streams are used + in the ZIP file format. + +- The ability to read and write gzip streams, used in the GZIP + file format, and normally produced by the gzip program. + +- The ability to select a different compression strategy, useful + to PNG and MNG image compression, and to multimedia compression + in general. Besides the compression level + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + which, in fact, could have used the 'z' prefix and avoided + TColor-like symbols + + TCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax); + + there could be a compression strategy + + TCompressionStrategy = (zsDefault, zsFiltered, zsHuffmanOnly, zsRle); + +- ZIP and GZIP stream handling via TStreams. + + +-- +Cosmin Truta diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/zlibd32.mak b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/zlibd32.mak new file mode 100644 index 00000000..0d0699a6 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/delphi/zlibd32.mak @@ -0,0 +1,99 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.build b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.build new file mode 100644 index 00000000..e69630ce --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.build @@ -0,0 +1,33 @@ + + + A .Net wrapper library around ZLib1.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.chm b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.chm new file mode 100644 index 00000000..f214a444 Binary files /dev/null and b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.chm differ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.sln b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.sln new file mode 100644 index 00000000..5d533d6b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotZLib", "DotZLib\DotZLib.csproj", "{BB1EE0B1-1808-46CB-B786-949D91117FC5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Debug.ActiveCfg = Debug|.NET + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Debug.Build.0 = Debug|.NET + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Release.ActiveCfg = Release|.NET + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs new file mode 100644 index 00000000..724c5347 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("DotZLib")] +[assembly: AssemblyDescription(".Net bindings for ZLib compression dll 1.2.x")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Henrik Ravn")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("(c) 2004 by Henrik Ravn")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs new file mode 100644 index 00000000..b110dae6 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs @@ -0,0 +1,202 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Runtime.InteropServices; +using System.Text; + + +namespace DotZLib +{ + #region ChecksumGeneratorBase + /// + /// Implements the common functionality needed for all s + /// + /// + public abstract class ChecksumGeneratorBase : ChecksumGenerator + { + /// + /// The value of the current checksum + /// + protected uint _current; + + /// + /// Initializes a new instance of the checksum generator base - the current checksum is + /// set to zero + /// + public ChecksumGeneratorBase() + { + _current = 0; + } + + /// + /// Initializes a new instance of the checksum generator basewith a specified value + /// + /// The value to set the current checksum to + public ChecksumGeneratorBase(uint initialValue) + { + _current = initialValue; + } + + /// + /// Resets the current checksum to zero + /// + public void Reset() { _current = 0; } + + /// + /// Gets the current checksum value + /// + public uint Value { get { return _current; } } + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + /// All the other Update methods are implmeneted in terms of this one. + /// This is therefore the only method a derived class has to implement + public abstract void Update(byte[] data, int offset, int count); + + /// + /// Updates the current checksum with an array of bytes. + /// + /// The data to update the checksum with + public void Update(byte[] data) + { + Update(data, 0, data.Length); + } + + /// + /// Updates the current checksum with the data from a string + /// + /// The string to update the checksum with + /// The characters in the string are converted by the UTF-8 encoding + public void Update(string data) + { + Update(Encoding.UTF8.GetBytes(data)); + } + + /// + /// Updates the current checksum with the data from a string, using a specific encoding + /// + /// The string to update the checksum with + /// The encoding to use + public void Update(string data, Encoding encoding) + { + Update(encoding.GetBytes(data)); + } + + } + #endregion + + #region CRC32 + /// + /// Implements a CRC32 checksum generator + /// + public sealed class CRC32Checksum : ChecksumGeneratorBase + { + #region DLL imports + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint crc32(uint crc, int data, uint length); + + #endregion + + /// + /// Initializes a new instance of the CRC32 checksum generator + /// + public CRC32Checksum() : base() {} + + /// + /// Initializes a new instance of the CRC32 checksum generator with a specified value + /// + /// The value to set the current checksum to + public CRC32Checksum(uint initialValue) : base(initialValue) {} + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + public override void Update(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + _current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); + } + finally + { + hData.Free(); + } + } + + } + #endregion + + #region Adler + /// + /// Implements a checksum generator that computes the Adler checksum on data + /// + public sealed class AdlerChecksum : ChecksumGeneratorBase + { + #region DLL imports + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint adler32(uint adler, int data, uint length); + + #endregion + + /// + /// Initializes a new instance of the Adler checksum generator + /// + public AdlerChecksum() : base() {} + + /// + /// Initializes a new instance of the Adler checksum generator with a specified value + /// + /// The value to set the current checksum to + public AdlerChecksum(uint initialValue) : base(initialValue) {} + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + public override void Update(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + _current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); + } + finally + { + hData.Free(); + } + } + + } + #endregion + +} \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs new file mode 100644 index 00000000..9c8d6019 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs @@ -0,0 +1,83 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; + +namespace DotZLib +{ + + /// + /// This class implements a circular buffer + /// + internal class CircularBuffer + { + #region Private data + private int _capacity; + private int _head; + private int _tail; + private int _size; + private byte[] _buffer; + #endregion + + public CircularBuffer(int capacity) + { + Debug.Assert( capacity > 0 ); + _buffer = new byte[capacity]; + _capacity = capacity; + _head = 0; + _tail = 0; + _size = 0; + } + + public int Size { get { return _size; } } + + public int Put(byte[] source, int offset, int count) + { + Debug.Assert( count > 0 ); + int trueCount = Math.Min(count, _capacity - Size); + for (int i = 0; i < trueCount; ++i) + _buffer[(_tail+i) % _capacity] = source[offset+i]; + _tail += trueCount; + _tail %= _capacity; + _size += trueCount; + return trueCount; + } + + public bool Put(byte b) + { + if (Size == _capacity) // no room + return false; + _buffer[_tail++] = b; + _tail %= _capacity; + ++_size; + return true; + } + + public int Get(byte[] destination, int offset, int count) + { + int trueCount = Math.Min(count,Size); + for (int i = 0; i < trueCount; ++i) + destination[offset + i] = _buffer[(_head+i) % _capacity]; + _head += trueCount; + _head %= _capacity; + _size -= trueCount; + return trueCount; + } + + public int Get() + { + if (Size == 0) + return -1; + + int result = (int)_buffer[_head++ % _capacity]; + --_size; + return result; + } + + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/CodecBase.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/CodecBase.cs new file mode 100644 index 00000000..b0eb78a0 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/CodecBase.cs @@ -0,0 +1,198 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + /// + /// Implements the common functionality needed for all s + /// + public abstract class CodecBase : Codec, IDisposable + { + + #region Data members + + /// + /// Instance of the internal zlib buffer structure that is + /// passed to all functions in the zlib dll + /// + internal ZStream _ztream = new ZStream(); + + /// + /// True if the object instance has been disposed, false otherwise + /// + protected bool _isDisposed = false; + + /// + /// The size of the internal buffers + /// + protected const int kBufferSize = 16384; + + private byte[] _outBuffer = new byte[kBufferSize]; + private byte[] _inBuffer = new byte[kBufferSize]; + + private GCHandle _hInput; + private GCHandle _hOutput; + + private uint _checksum = 0; + + #endregion + + /// + /// Initializes a new instance of the CodeBase class. + /// + public CodecBase() + { + try + { + _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned); + _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned); + } + catch (Exception) + { + CleanUp(false); + throw; + } + } + + + #region Codec Members + + /// + /// Occurs when more processed data are available. + /// + public event DataAvailableHandler DataAvailable; + + /// + /// Fires the event + /// + protected void OnDataAvailable() + { + if (_ztream.total_out > 0) + { + if (DataAvailable != null) + DataAvailable( _outBuffer, 0, (int)_ztream.total_out); + resetOutput(); + } + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// Adding data may, or may not, raise the DataAvailable event + public void Add(byte[] data) + { + Add(data,0,data.Length); + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + /// This must be implemented by a derived class + public abstract void Add(byte[] data, int offset, int count); + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + /// This must be implemented by a derived class + public abstract void Finish(); + + /// + /// Gets the checksum of the data that has been added so far + /// + public uint Checksum { get { return _checksum; } } + + #endregion + + #region Destructor & IDisposable stuff + + /// + /// Destroys this instance + /// + ~CodecBase() + { + CleanUp(false); + } + + /// + /// Releases any unmanaged resources and calls the method of the derived class + /// + public void Dispose() + { + CleanUp(true); + } + + /// + /// Performs any codec specific cleanup + /// + /// This must be implemented by a derived class + protected abstract void CleanUp(); + + // performs the release of the handles and calls the dereived CleanUp() + private void CleanUp(bool isDisposing) + { + if (!_isDisposed) + { + CleanUp(); + if (_hInput.IsAllocated) + _hInput.Free(); + if (_hOutput.IsAllocated) + _hOutput.Free(); + + _isDisposed = true; + } + } + + + #endregion + + #region Helper methods + + /// + /// Copies a number of bytes to the internal codec buffer - ready for proccesing + /// + /// The byte array that contains the data to copy + /// The index of the first byte to copy + /// The number of bytes to copy from data + protected void copyInput(byte[] data, int startIndex, int count) + { + Array.Copy(data, startIndex, _inBuffer,0, count); + _ztream.next_in = _hInput.AddrOfPinnedObject(); + _ztream.total_in = 0; + _ztream.avail_in = (uint)count; + + } + + /// + /// Resets the internal output buffers to a known state - ready for processing + /// + protected void resetOutput() + { + _ztream.total_out = 0; + _ztream.avail_out = kBufferSize; + _ztream.next_out = _hOutput.AddrOfPinnedObject(); + } + + /// + /// Updates the running checksum property + /// + /// The new checksum value + protected void setChecksum(uint newSum) + { + _checksum = newSum; + } + #endregion + + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/Deflater.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/Deflater.cs new file mode 100644 index 00000000..9039f41f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/Deflater.cs @@ -0,0 +1,106 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + + /// + /// Implements a data compressor, using the deflate algorithm in the ZLib dll + /// + public sealed class Deflater : CodecBase + { + #region Dll imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflate(ref ZStream sz, int flush); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflateReset(ref ZStream sz); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflateEnd(ref ZStream sz); + #endregion + + /// + /// Constructs an new instance of the Deflater + /// + /// The compression level to use for this Deflater + public Deflater(CompressLevel level) : base() + { + int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream)); + if (retval != 0) + throw new ZLibException(retval, "Could not initialize deflater"); + + resetOutput(); + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + public override void Add(byte[] data, int offset, int count) + { + if (data == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + + int total = count; + int inputIndex = offset; + int err = 0; + + while (err >= 0 && inputIndex < total) + { + copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); + while (err >= 0 && _ztream.avail_in > 0) + { + err = deflate(ref _ztream, (int)FlushTypes.None); + if (err == 0) + while (_ztream.avail_out == 0) + { + OnDataAvailable(); + err = deflate(ref _ztream, (int)FlushTypes.None); + } + inputIndex += (int)_ztream.total_in; + } + } + setChecksum( _ztream.adler ); + } + + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + public override void Finish() + { + int err; + do + { + err = deflate(ref _ztream, (int)FlushTypes.Finish); + OnDataAvailable(); + } + while (err == 0); + setChecksum( _ztream.adler ); + deflateReset(ref _ztream); + resetOutput(); + } + + /// + /// Closes the internal zlib deflate stream + /// + protected override void CleanUp() { deflateEnd(ref _ztream); } + + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/DotZLib.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/DotZLib.cs new file mode 100644 index 00000000..90c7c3b3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/DotZLib.cs @@ -0,0 +1,288 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + + +namespace DotZLib +{ + + #region Internal types + + /// + /// Defines constants for the various flush types used with zlib + /// + internal enum FlushTypes + { + None, Partial, Sync, Full, Finish, Block + } + + #region ZStream structure + // internal mapping of the zlib zstream structure for marshalling + [StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)] + internal struct ZStream + { + public IntPtr next_in; + public uint avail_in; + public uint total_in; + + public IntPtr next_out; + public uint avail_out; + public uint total_out; + + [MarshalAs(UnmanagedType.LPStr)] + string msg; + uint state; + + uint zalloc; + uint zfree; + uint opaque; + + int data_type; + public uint adler; + uint reserved; + } + + #endregion + + #endregion + + #region Public enums + /// + /// Defines constants for the available compression levels in zlib + /// + public enum CompressLevel : int + { + /// + /// The default compression level with a reasonable compromise between compression and speed + /// + Default = -1, + /// + /// No compression at all. The data are passed straight through. + /// + None = 0, + /// + /// The maximum compression rate available. + /// + Best = 9, + /// + /// The fastest available compression level. + /// + Fastest = 1 + } + #endregion + + #region Exception classes + /// + /// The exception that is thrown when an error occurs on the zlib dll + /// + public class ZLibException : ApplicationException + { + /// + /// Initializes a new instance of the class with a specified + /// error message and error code + /// + /// The zlib error code that caused the exception + /// A message that (hopefully) describes the error + public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg)) + { + } + + /// + /// Initializes a new instance of the class with a specified + /// error code + /// + /// The zlib error code that caused the exception + public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode)) + { + } + } + #endregion + + #region Interfaces + + /// + /// Declares methods and properties that enables a running checksum to be calculated + /// + public interface ChecksumGenerator + { + /// + /// Gets the current value of the checksum + /// + uint Value { get; } + + /// + /// Clears the current checksum to 0 + /// + void Reset(); + + /// + /// Updates the current checksum with an array of bytes + /// + /// The data to update the checksum with + void Update(byte[] data); + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + void Update(byte[] data, int offset, int count); + + /// + /// Updates the current checksum with the data from a string + /// + /// The string to update the checksum with + /// The characters in the string are converted by the UTF-8 encoding + void Update(string data); + + /// + /// Updates the current checksum with the data from a string, using a specific encoding + /// + /// The string to update the checksum with + /// The encoding to use + void Update(string data, Encoding encoding); + } + + + /// + /// Represents the method that will be called from a codec when new data + /// are available. + /// + /// The byte array containing the processed data + /// The index of the first processed byte in data + /// The number of processed bytes available + /// On return from this method, the data may be overwritten, so grab it while you can. + /// You cannot assume that startIndex will be zero. + /// + public delegate void DataAvailableHandler(byte[] data, int startIndex, int count); + + /// + /// Declares methods and events for implementing compressors/decompressors + /// + public interface Codec + { + /// + /// Occurs when more processed data are available. + /// + event DataAvailableHandler DataAvailable; + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// Adding data may, or may not, raise the DataAvailable event + void Add(byte[] data); + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + void Add(byte[] data, int offset, int count); + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + void Finish(); + + /// + /// Gets the checksum of the data that has been added so far + /// + uint Checksum { get; } + + + } + + #endregion + + #region Classes + /// + /// Encapsulates general information about the ZLib library + /// + public class Info + { + #region DLL imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint zlibCompileFlags(); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern string zlibVersion(); + #endregion + + #region Private stuff + private uint _flags; + + // helper function that unpacks a bitsize mask + private static int bitSize(uint bits) + { + switch (bits) + { + case 0: return 16; + case 1: return 32; + case 2: return 64; + } + return -1; + } + #endregion + + /// + /// Constructs an instance of the Info class. + /// + public Info() + { + _flags = zlibCompileFlags(); + } + + /// + /// True if the library is compiled with debug info + /// + public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } } + + /// + /// True if the library is compiled with assembly optimizations + /// + public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } } + + /// + /// Gets the size of the unsigned int that was compiled into Zlib + /// + public int SizeOfUInt { get { return bitSize(_flags & 3); } } + + /// + /// Gets the size of the unsigned long that was compiled into Zlib + /// + public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } } + + /// + /// Gets the size of the pointers that were compiled into Zlib + /// + public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } } + + /// + /// Gets the size of the z_off_t type that was compiled into Zlib + /// + public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } } + + /// + /// Gets the version of ZLib as a string, e.g. "1.2.1" + /// + public static string Version { get { return zlibVersion(); } } + } + + #endregion + +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj new file mode 100644 index 00000000..dea7fb16 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/GZipStream.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/GZipStream.cs new file mode 100644 index 00000000..f0eada1d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/GZipStream.cs @@ -0,0 +1,301 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + /// + /// Implements a compressed , in GZip (.gz) format. + /// + public class GZipStream : Stream, IDisposable + { + #region Dll Imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern IntPtr gzopen(string name, string mode); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzclose(IntPtr gzFile); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzwrite(IntPtr gzFile, int data, int length); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzread(IntPtr gzFile, int data, int length); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzgetc(IntPtr gzFile); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzputc(IntPtr gzFile, int c); + + #endregion + + #region Private data + private IntPtr _gzFile; + private bool _isDisposed = false; + private bool _isWriting; + #endregion + + #region Constructors + /// + /// Creates a new file as a writeable GZipStream + /// + /// The name of the compressed file to create + /// The compression level to use when adding data + /// If an error occurred in the internal zlib function + public GZipStream(string fileName, CompressLevel level) + { + _isWriting = true; + _gzFile = gzopen(fileName, String.Format("wb{0}", (int)level)); + if (_gzFile == IntPtr.Zero) + throw new ZLibException(-1, "Could not open " + fileName); + } + + /// + /// Opens an existing file as a readable GZipStream + /// + /// The name of the file to open + /// If an error occurred in the internal zlib function + public GZipStream(string fileName) + { + _isWriting = false; + _gzFile = gzopen(fileName, "rb"); + if (_gzFile == IntPtr.Zero) + throw new ZLibException(-1, "Could not open " + fileName); + + } + #endregion + + #region Access properties + /// + /// Returns true of this stream can be read from, false otherwise + /// + public override bool CanRead + { + get + { + return !_isWriting; + } + } + + + /// + /// Returns false. + /// + public override bool CanSeek + { + get + { + return false; + } + } + + /// + /// Returns true if this tsream is writeable, false otherwise + /// + public override bool CanWrite + { + get + { + return _isWriting; + } + } + #endregion + + #region Destructor & IDispose stuff + + /// + /// Destroys this instance + /// + ~GZipStream() + { + cleanUp(false); + } + + /// + /// Closes the external file handle + /// + public void Dispose() + { + cleanUp(true); + } + + // Does the actual closing of the file handle. + private void cleanUp(bool isDisposing) + { + if (!_isDisposed) + { + gzclose(_gzFile); + _isDisposed = true; + } + } + #endregion + + #region Basic reading and writing + /// + /// Attempts to read a number of bytes from the stream. + /// + /// The destination data buffer + /// The index of the first destination byte in buffer + /// The number of bytes requested + /// The number of bytes read + /// If buffer is null + /// If count or offset are negative + /// If offset + count is > buffer.Length + /// If this stream is not readable. + /// If this stream has been disposed. + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) throw new NotSupportedException(); + if (buffer == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > buffer.Length) throw new ArgumentException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); + int result; + try + { + result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); + if (result < 0) + throw new IOException(); + } + finally + { + h.Free(); + } + return result; + } + + /// + /// Attempts to read a single byte from the stream. + /// + /// The byte that was read, or -1 in case of error or End-Of-File + public override int ReadByte() + { + if (!CanRead) throw new NotSupportedException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + return gzgetc(_gzFile); + } + + /// + /// Writes a number of bytes to the stream + /// + /// + /// + /// + /// If buffer is null + /// If count or offset are negative + /// If offset + count is > buffer.Length + /// If this stream is not writeable. + /// If this stream has been disposed. + public override void Write(byte[] buffer, int offset, int count) + { + if (!CanWrite) throw new NotSupportedException(); + if (buffer == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > buffer.Length) throw new ArgumentException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); + if (result < 0) + throw new IOException(); + } + finally + { + h.Free(); + } + } + + /// + /// Writes a single byte to the stream + /// + /// The byte to add to the stream. + /// If this stream is not writeable. + /// If this stream has been disposed. + public override void WriteByte(byte value) + { + if (!CanWrite) throw new NotSupportedException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + int result = gzputc(_gzFile, (int)value); + if (result < 0) + throw new IOException(); + } + #endregion + + #region Position & length stuff + /// + /// Not supported. + /// + /// + /// Always thrown + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Not suppported. + /// + /// + /// + /// + /// Always thrown + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Flushes the GZipStream. + /// + /// In this implementation, this method does nothing. This is because excessive + /// flushing may degrade the achievable compression rates. + public override void Flush() + { + // left empty on purpose + } + + /// + /// Gets/sets the current position in the GZipStream. Not suppported. + /// + /// In this implementation this property is not supported + /// Always thrown + public override long Position + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + + /// + /// Gets the size of the stream. Not suppported. + /// + /// In this implementation this property is not supported + /// Always thrown + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + #endregion + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/Inflater.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/Inflater.cs new file mode 100644 index 00000000..d295f268 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/Inflater.cs @@ -0,0 +1,105 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + + /// + /// Implements a data decompressor, using the inflate algorithm in the ZLib dll + /// + public class Inflater : CodecBase + { + #region Dll imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern int inflateInit_(ref ZStream sz, string vs, int size); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflate(ref ZStream sz, int flush); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflateReset(ref ZStream sz); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflateEnd(ref ZStream sz); + #endregion + + /// + /// Constructs an new instance of the Inflater + /// + public Inflater() : base() + { + int retval = inflateInit_(ref _ztream, Info.Version, Marshal.SizeOf(_ztream)); + if (retval != 0) + throw new ZLibException(retval, "Could not initialize inflater"); + + resetOutput(); + } + + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + public override void Add(byte[] data, int offset, int count) + { + if (data == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + + int total = count; + int inputIndex = offset; + int err = 0; + + while (err >= 0 && inputIndex < total) + { + copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); + err = inflate(ref _ztream, (int)FlushTypes.None); + if (err == 0) + while (_ztream.avail_out == 0) + { + OnDataAvailable(); + err = inflate(ref _ztream, (int)FlushTypes.None); + } + + inputIndex += (int)_ztream.total_in; + } + setChecksum( _ztream.adler ); + } + + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + public override void Finish() + { + int err; + do + { + err = inflate(ref _ztream, (int)FlushTypes.Finish); + OnDataAvailable(); + } + while (err == 0); + setChecksum( _ztream.adler ); + inflateReset(ref _ztream); + resetOutput(); + } + + /// + /// Closes the internal zlib inflate stream + /// + protected override void CleanUp() { inflateEnd(ref _ztream); } + + + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/UnitTests.cs b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/UnitTests.cs new file mode 100644 index 00000000..528a0398 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/DotZLib/UnitTests.cs @@ -0,0 +1,274 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Collections; +using System.IO; + +// uncomment the define below to include unit tests +//#define nunit +#if nunit +using NUnit.Framework; + +// Unit tests for the DotZLib class library +// ---------------------------------------- +// +// Use this with NUnit 2 from http://www.nunit.org +// + +namespace DotZLibTests +{ + using DotZLib; + + // helper methods + internal class Utils + { + public static bool byteArrEqual( byte[] lhs, byte[] rhs ) + { + if (lhs.Length != rhs.Length) + return false; + for (int i = lhs.Length-1; i >= 0; --i) + if (lhs[i] != rhs[i]) + return false; + return true; + } + + } + + + [TestFixture] + public class CircBufferTests + { + #region Circular buffer tests + [Test] + public void SinglePutGet() + { + CircularBuffer buf = new CircularBuffer(10); + Assert.AreEqual( 0, buf.Size ); + Assert.AreEqual( -1, buf.Get() ); + + Assert.IsTrue(buf.Put( 1 )); + Assert.AreEqual( 1, buf.Size ); + Assert.AreEqual( 1, buf.Get() ); + Assert.AreEqual( 0, buf.Size ); + Assert.AreEqual( -1, buf.Get() ); + } + + [Test] + public void BlockPutGet() + { + CircularBuffer buf = new CircularBuffer(10); + byte[] arr = {1,2,3,4,5,6,7,8,9,10}; + Assert.AreEqual( 10, buf.Put(arr,0,10) ); + Assert.AreEqual( 10, buf.Size ); + Assert.IsFalse( buf.Put(11) ); + Assert.AreEqual( 1, buf.Get() ); + Assert.IsTrue( buf.Put(11) ); + + byte[] arr2 = (byte[])arr.Clone(); + Assert.AreEqual( 9, buf.Get(arr2,1,9) ); + Assert.IsTrue( Utils.byteArrEqual(arr,arr2) ); + } + + #endregion + } + + [TestFixture] + public class ChecksumTests + { + #region CRC32 Tests + [Test] + public void CRC32_Null() + { + CRC32Checksum crc32 = new CRC32Checksum(); + Assert.AreEqual( 0, crc32.Value ); + + crc32 = new CRC32Checksum(1); + Assert.AreEqual( 1, crc32.Value ); + + crc32 = new CRC32Checksum(556); + Assert.AreEqual( 556, crc32.Value ); + } + + [Test] + public void CRC32_Data() + { + CRC32Checksum crc32 = new CRC32Checksum(); + byte[] data = { 1,2,3,4,5,6,7 }; + crc32.Update(data); + Assert.AreEqual( 0x70e46888, crc32.Value ); + + crc32 = new CRC32Checksum(); + crc32.Update("penguin"); + Assert.AreEqual( 0x0e5c1a120, crc32.Value ); + + crc32 = new CRC32Checksum(1); + crc32.Update("penguin"); + Assert.AreEqual(0x43b6aa94, crc32.Value); + + } + #endregion + + #region Adler tests + + [Test] + public void Adler_Null() + { + AdlerChecksum adler = new AdlerChecksum(); + Assert.AreEqual(0, adler.Value); + + adler = new AdlerChecksum(1); + Assert.AreEqual( 1, adler.Value ); + + adler = new AdlerChecksum(556); + Assert.AreEqual( 556, adler.Value ); + } + + [Test] + public void Adler_Data() + { + AdlerChecksum adler = new AdlerChecksum(1); + byte[] data = { 1,2,3,4,5,6,7 }; + adler.Update(data); + Assert.AreEqual( 0x5b001d, adler.Value ); + + adler = new AdlerChecksum(); + adler.Update("penguin"); + Assert.AreEqual(0x0bcf02f6, adler.Value ); + + adler = new AdlerChecksum(1); + adler.Update("penguin"); + Assert.AreEqual(0x0bd602f7, adler.Value); + + } + #endregion + } + + [TestFixture] + public class InfoTests + { + #region Info tests + [Test] + public void Info_Version() + { + Info info = new Info(); + Assert.AreEqual("1.2.5", Info.Version); + Assert.AreEqual(32, info.SizeOfUInt); + Assert.AreEqual(32, info.SizeOfULong); + Assert.AreEqual(32, info.SizeOfPointer); + Assert.AreEqual(32, info.SizeOfOffset); + } + #endregion + } + + [TestFixture] + public class DeflateInflateTests + { + #region Deflate tests + [Test] + public void Deflate_Init() + { + using (Deflater def = new Deflater(CompressLevel.Default)) + { + } + } + + private ArrayList compressedData = new ArrayList(); + private uint adler1; + + private ArrayList uncompressedData = new ArrayList(); + private uint adler2; + + public void CDataAvail(byte[] data, int startIndex, int count) + { + for (int i = 0; i < count; ++i) + compressedData.Add(data[i+startIndex]); + } + + [Test] + public void Deflate_Compress() + { + compressedData.Clear(); + + byte[] testData = new byte[35000]; + for (int i = 0; i < testData.Length; ++i) + testData[i] = 5; + + using (Deflater def = new Deflater((CompressLevel)5)) + { + def.DataAvailable += new DataAvailableHandler(CDataAvail); + def.Add(testData); + def.Finish(); + adler1 = def.Checksum; + } + } + #endregion + + #region Inflate tests + [Test] + public void Inflate_Init() + { + using (Inflater inf = new Inflater()) + { + } + } + + private void DDataAvail(byte[] data, int startIndex, int count) + { + for (int i = 0; i < count; ++i) + uncompressedData.Add(data[i+startIndex]); + } + + [Test] + public void Inflate_Expand() + { + uncompressedData.Clear(); + + using (Inflater inf = new Inflater()) + { + inf.DataAvailable += new DataAvailableHandler(DDataAvail); + inf.Add((byte[])compressedData.ToArray(typeof(byte))); + inf.Finish(); + adler2 = inf.Checksum; + } + Assert.AreEqual( adler1, adler2 ); + } + #endregion + } + + [TestFixture] + public class GZipStreamTests + { + #region GZipStream test + [Test] + public void GZipStream_WriteRead() + { + using (GZipStream gzOut = new GZipStream("gzstream.gz", CompressLevel.Best)) + { + BinaryWriter writer = new BinaryWriter(gzOut); + writer.Write("hi there"); + writer.Write(Math.PI); + writer.Write(42); + } + + using (GZipStream gzIn = new GZipStream("gzstream.gz")) + { + BinaryReader reader = new BinaryReader(gzIn); + string s = reader.ReadString(); + Assert.AreEqual("hi there",s); + double d = reader.ReadDouble(); + Assert.AreEqual(Math.PI, d); + int i = reader.ReadInt32(); + Assert.AreEqual(42,i); + } + + } + #endregion + } +} + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/LICENSE_1_0.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/LICENSE_1_0.txt new file mode 100644 index 00000000..127a5bc3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/readme.txt new file mode 100644 index 00000000..4d8c2dd9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/dotzlib/readme.txt @@ -0,0 +1,58 @@ +This directory contains a .Net wrapper class library for the ZLib1.dll + +The wrapper includes support for inflating/deflating memory buffers, +.Net streaming wrappers for the gz streams part of zlib, and wrappers +for the checksum parts of zlib. See DotZLib/UnitTests.cs for examples. + +Directory structure: +-------------------- + +LICENSE_1_0.txt - License file. +readme.txt - This file. +DotZLib.chm - Class library documentation +DotZLib.build - NAnt build file +DotZLib.sln - Microsoft Visual Studio 2003 solution file + +DotZLib\*.cs - Source files for the class library + +Unit tests: +----------- +The file DotZLib/UnitTests.cs contains unit tests for use with NUnit 2.1 or higher. +To include unit tests in the build, define nunit before building. + + +Build instructions: +------------------- + +1. Using Visual Studio.Net 2003: + Open DotZLib.sln in VS.Net and build from there. Output file (DotZLib.dll) + will be found ./DotZLib/bin/release or ./DotZLib/bin/debug, depending on + you are building the release or debug version of the library. Check + DotZLib/UnitTests.cs for instructions on how to include unit tests in the + build. + +2. Using NAnt: + Open a command prompt with access to the build environment and run nant + in the same directory as the DotZLib.build file. + You can define 2 properties on the nant command-line to control the build: + debug={true|false} to toggle between release/debug builds (default=true). + nunit={true|false} to include or esclude unit tests (default=true). + Also the target clean will remove binaries. + Output file (DotZLib.dll) will be found in either ./DotZLib/bin/release + or ./DotZLib/bin/debug, depending on whether you are building the release + or debug version of the library. + + Examples: + nant -D:debug=false -D:nunit=false + will build a release mode version of the library without unit tests. + nant + will build a debug version of the library with unit tests + nant clean + will remove all previously built files. + + +--------------------------------- +Copyright (c) Henrik Ravn 2004 + +Use, modification and distribution are subject to the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/gcc_gvmat64/gvmat64.S b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/gcc_gvmat64/gvmat64.S new file mode 100644 index 00000000..dd858ddb --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/gcc_gvmat64/gvmat64.S @@ -0,0 +1,574 @@ +/* +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); // current match + +; gvmat64.S -- Asm portion of the optimized longest_match for 32 bits x86_64 +; (AMD64 on Athlon 64, Opteron, Phenom +; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) +; this file is translation from gvmat64.asm to GCC 4.x (for Linux, Mac XCode) +; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software +; 3. This notice may not be removed or altered from any source distribution. +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for zLib, I use option: +; gcc -c -arch x86_64 gvmat64.S + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; // current match / +; +; with XCode for Mac, I had strange error with some jump on intel syntax +; this is why BEFORE_JMP and AFTER_JMP are used + */ + + +#define BEFORE_JMP .att_syntax +#define AFTER_JMP .intel_syntax noprefix + +#ifndef NO_UNDERLINE +# define match_init _match_init +# define longest_match _longest_match +#endif + +.intel_syntax noprefix + +.globl match_init, longest_match +.text +longest_match: + + + +#define LocalVarsSize 96 +/* +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp +*/ + +#define chainlenwmask (rsp + 8 - LocalVarsSize) +#define nicematch (rsp + 16 - LocalVarsSize) + +#define save_rdi (rsp + 24 - LocalVarsSize) +#define save_rsi (rsp + 32 - LocalVarsSize) +#define save_rbx (rsp + 40 - LocalVarsSize) +#define save_rbp (rsp + 48 - LocalVarsSize) +#define save_r12 (rsp + 56 - LocalVarsSize) +#define save_r13 (rsp + 64 - LocalVarsSize) +#define save_r14 (rsp + 72 - LocalVarsSize) +#define save_r15 (rsp + 80 - LocalVarsSize) + + +/* +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure +*/ + +#define MAX_MATCH 258 +#define MIN_MATCH 3 +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) + +/* +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). +*/ + + + +/* you can check the structure offset by running + +#include +#include +#include "deflate.h" + +void print_depl() +{ +deflate_state ds; +deflate_state *s=&ds; +printf("size pointer=%u\n",(int)sizeof(void*)); + +printf("#define dsWSize %u\n",(int)(((char*)&(s->w_size))-((char*)s))); +printf("#define dsWMask %u\n",(int)(((char*)&(s->w_mask))-((char*)s))); +printf("#define dsWindow %u\n",(int)(((char*)&(s->window))-((char*)s))); +printf("#define dsPrev %u\n",(int)(((char*)&(s->prev))-((char*)s))); +printf("#define dsMatchLen %u\n",(int)(((char*)&(s->match_length))-((char*)s))); +printf("#define dsPrevMatch %u\n",(int)(((char*)&(s->prev_match))-((char*)s))); +printf("#define dsStrStart %u\n",(int)(((char*)&(s->strstart))-((char*)s))); +printf("#define dsMatchStart %u\n",(int)(((char*)&(s->match_start))-((char*)s))); +printf("#define dsLookahead %u\n",(int)(((char*)&(s->lookahead))-((char*)s))); +printf("#define dsPrevLen %u\n",(int)(((char*)&(s->prev_length))-((char*)s))); +printf("#define dsMaxChainLen %u\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); +printf("#define dsGoodMatch %u\n",(int)(((char*)&(s->good_match))-((char*)s))); +printf("#define dsNiceMatch %u\n",(int)(((char*)&(s->nice_match))-((char*)s))); +} +*/ + +#define dsWSize 68 +#define dsWMask 76 +#define dsWindow 80 +#define dsPrev 96 +#define dsMatchLen 144 +#define dsPrevMatch 148 +#define dsStrStart 156 +#define dsMatchStart 160 +#define dsLookahead 164 +#define dsPrevLen 168 +#define dsMaxChainLen 172 +#define dsGoodMatch 188 +#define dsNiceMatch 192 + +#define window_size [ rcx + dsWSize] +#define WMask [ rcx + dsWMask] +#define window_ad [ rcx + dsWindow] +#define prev_ad [ rcx + dsPrev] +#define strstart [ rcx + dsStrStart] +#define match_start [ rcx + dsMatchStart] +#define Lookahead [ rcx + dsLookahead] //; 0ffffffffh on infozip +#define prev_length [ rcx + dsPrevLen] +#define max_chain_length [ rcx + dsMaxChainLen] +#define good_match [ rcx + dsGoodMatch] +#define nice_match [ rcx + dsNiceMatch] + +/* +; windows: +; parameter 1 in rcx(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + +; +; gcc on macosx-linux: +; see http://www.x86-64.org/documentation/abi-0.99.pdf +; param 1 in rdi, param 2 in rsi +; rbx, rsp, rbp, r12 to r15 must be preserved + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; ms: parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) +; mac: param 1 in rdi, param 2 rsi +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx +*/ + mov [save_rbx],rbx + mov [save_rbp],rbp + + + mov rcx,rdi + + mov r8d,esi + + + mov [save_r12],r12 + mov [save_r13],r13 + mov [save_r14],r14 + mov [save_r15],r15 + + +//;;; uInt wmask = s->w_mask; +//;;; unsigned chain_length = s->max_chain_length; +//;;; if (s->prev_length >= s->good_match) { +//;;; chain_length >>= 2; +//;;; } + + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +//;;; chainlen is decremented once beforehand so that the function can +//;;; use the sign flag instead of the zero flag for the exit test. +//;;; It is then shifted into the high word, to make room for the wmask +//;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +//;;; on zlib only +//;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + + + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d + + + +//;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +//;;; Determine how many bytes the scan ptr is off from being +//;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +//;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +//;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + + mov eax, window_size + sub eax, MIN_LOOKAHEAD + + + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +//;;; int best_len = s->prev_length; + + +//;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +//;;; register ush scan_start = *(ushf*)scan; +//;;; register ush scan_end = *(ushf*)(scan+best_len-1); +//;;; Posf *prev = s->prev; + + movzx r12d,word ptr [r9] + movzx ebx, word ptr [r9 + r11 - 1] + + mov rdi, prev_ad + +//;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + + + +LookupLoop1: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + + + + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry1: + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jz LookupLoopIsZero + AFTER_JMP + +LookupLoop2: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry2: + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jz LookupLoopIsZero + AFTER_JMP + +LookupLoop4: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry4: + + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jnz LookupLoop1 + jmp LookupLoopIsZero + AFTER_JMP +/* +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit +*/ +.balign 16 +LookupLoop: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry: + + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jnz LookupLoop1 + AFTER_JMP +LookupLoopIsZero: + cmp r12w, word ptr [r10 + r8] + BEFORE_JMP + jnz LookupLoop1 + AFTER_JMP + + +//;;; Store the current value of chainlen. + mov [chainlenwmask], edx +/* +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). +*/ + lea rsi,[r8+r10] + mov rdx, 0xfffffffffffffef8 //; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0x0108] //;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0x0108] //;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + +/* +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. +*/ + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + BEFORE_JMP + jnz LoopCmps + jmp LenMaximum + AFTER_JMP + +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0x0000FFFF + jnz LenLower + + test eax,0xffffffff + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + BEFORE_JMP + jnz LenLower + AFTER_JMP + +LenLower32: + shr eax,16 + add rdx,2 + +LenLower: + sub al, 1 + adc rdx, 0 +//;;; Calculate the length of the match. If it is longer than MAX_MATCH, +//;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + BEFORE_JMP + jge LenMaximum + AFTER_JMP +/* +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// +*/ + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + BEFORE_JMP + jmp LookupLoop + AFTER_JMP +/* +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); +*/ +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + BEFORE_JMP + jge LeaveNow + AFTER_JMP + + lea rsi,[r10+rax] + + movzx ebx, word ptr [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + BEFORE_JMP + jmp LookupLoop + AFTER_JMP + +//;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d + +//;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +//;;; return s->lookahead; + +LeaveNow: + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d + + + +//;;; Restore the stack and return from whence we came. + + +// mov rsi,[save_rsi] +// mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] + mov r14,[save_r14] + mov r15,[save_r15] + + + ret 0 +//; please don't remove this string ! +//; Your can freely use gvmat64 in any free or commercial app +//; but it is far better don't remove the string in the binary! + // db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 + + +match_init: + ret 0 + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/README new file mode 100644 index 00000000..e75ed132 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/README @@ -0,0 +1 @@ +See infback9.h for what this is and how to use it. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/infback9.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/infback9.c new file mode 100644 index 00000000..7bbe90ce --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/infback9.c @@ -0,0 +1,617 @@ +/* infback9.c -- inflate deflate64 data using a call-back interface + * Copyright (C) 1995-2008 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infback9.h" +#include "inftree9.h" +#include "inflate9.h" + +#define WSIZE 65536UL + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + window is a user-supplied window and output buffer that is 64K bytes. + */ +int ZEXPORT inflateBack9Init_(strm, window, version, stream_size) +z_stream FAR *strm; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->window = window; + return Z_OK; +} + +/* + Build and output length and distance decoding tables for fixed code + decoding. + */ +#ifdef MAKEFIXED +#include + +void makefixed9(void) +{ + unsigned sym, bits, low, size; + code *next, *lenfix, *distfix; + struct inflate_state state; + code fixed[544]; + + /* literal/length table */ + sym = 0; + while (sym < 144) state.lens[sym++] = 8; + while (sym < 256) state.lens[sym++] = 9; + while (sym < 280) state.lens[sym++] = 7; + while (sym < 288) state.lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table9(LENS, state.lens, 288, &(next), &(bits), state.work); + + /* distance table */ + sym = 0; + while (sym < 32) state.lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table9(DISTS, state.lens, 32, &(next), &(bits), state.work); + + /* write tables */ + puts(" /* inffix9.h -- table for decoding deflate64 fixed codes"); + puts(" * Generated automatically by makefixed9()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", lenfix[low].op, lenfix[low].bits, + lenfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 5) == 0) printf("\n "); + printf("{%u,%u,%d}", distfix[low].op, distfix[low].bits, + distfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* Macros for inflateBack(): */ + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n <= 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = window; \ + left = WSIZE; \ + wrap = 1; \ + if (out(out_desc, put, (unsigned)left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have; /* available input */ + unsigned long left; /* available output */ + inflate_mode mode; /* current inflate mode */ + int lastblock; /* true if processing last block */ + int wrap; /* true if the window has wrapped */ + unsigned long write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned extra; /* extra bits needed */ + unsigned long length; /* literal or length of data to copy */ + unsigned long offset; /* distance back to copy string from */ + unsigned long copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +#include "inffix9.h" + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + mode = TYPE; + lastblock = 0; + write = 0; + wrap = 0; + window = state->window; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = window; + left = WSIZE; + lencode = Z_NULL; + distcode = Z_NULL; + + /* Inflate until end of block marked as last */ + for (;;) + switch (mode) { + case TYPE: + /* determine and dispatch block type */ + if (lastblock) { + BYTEBITS(); + mode = DONE; + break; + } + NEEDBITS(3); + lastblock = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + lastblock ? " (last)" : "")); + mode = STORED; + break; + case 1: /* fixed block */ + lencode = lenfix; + lenbits = 9; + distcode = distfix; + distbits = 5; + Tracev((stderr, "inflate: fixed codes block%s\n", + lastblock ? " (last)" : "")); + mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + lastblock ? " (last)" : "")); + mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + mode = BAD; + break; + } + length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %lu\n", + length)); + INITBITS(); + + /* copy stored block from input to output */ + while (length != 0) { + copy = length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); + if (state->nlen > 286) { + strm->msg = (char *)"too many length symbols"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 7; + ret = inflate_table9(CODES, state->lens, 19, &(state->next), + &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = lencode[BITS(lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftree9.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 9; + ret = inflate_table9(LENS, state->lens, state->nlen, + &(state->next), &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + mode = BAD; + break; + } + distcode = (code const FAR *)(state->next); + distbits = 6; + ret = inflate_table9(DISTS, state->lens + state->nlen, + state->ndist, &(state->next), &(distbits), + state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + mode = LEN; + + case LEN: + /* get a literal, length, or end-of-block code */ + for (;;) { + here = lencode[BITS(lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(length); + left--; + mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + extra = (unsigned)(here.op) & 31; + if (extra != 0) { + NEEDBITS(extra); + length += BITS(extra); + DROPBITS(extra); + } + Tracevv((stderr, "inflate: length %lu\n", length)); + + /* get distance code */ + for (;;) { + here = distcode[BITS(distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + mode = BAD; + break; + } + offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + extra = (unsigned)(here.op) & 15; + if (extra != 0) { + NEEDBITS(extra); + offset += BITS(extra); + DROPBITS(extra); + } + if (offset > WSIZE - (wrap ? 0: left)) { + strm->msg = (char *)"invalid distance too far back"; + mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %lu\n", offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = WSIZE - offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - offset; + copy = left; + } + if (copy > length) copy = length; + length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < WSIZE) { + if (out(out_desc, window, (unsigned)(WSIZE - left))) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBack9End(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/infback9.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/infback9.h new file mode 100644 index 00000000..1073c0a3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/infback9.h @@ -0,0 +1,37 @@ +/* infback9.h -- header for using inflateBack9 functions + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * This header file and associated patches provide a decoder for PKWare's + * undocumented deflate64 compression method (method 9). Use with infback9.c, + * inftree9.h, inftree9.c, and inffix9.h. These patches are not supported. + * This should be compiled with zlib, since it uses zutil.h and zutil.o. + * This code has not yet been tested on 16-bit architectures. See the + * comments in zlib.h for inflateBack() usage. These functions are used + * identically, except that there is no windowBits parameter, and a 64K + * window must be provided. Also if int's are 16 bits, then a zero for + * the third parameter of the "out" function actually means 65536UL. + * zlib.h must be included before this header file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm)); +ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define inflateBack9Init(strm, window) \ + inflateBack9Init_((strm), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +#ifdef __cplusplus +} +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inffix9.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inffix9.h new file mode 100644 index 00000000..ee5671d2 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inffix9.h @@ -0,0 +1,107 @@ + /* inffix9.h -- table for decoding deflate64 fixed codes + * Generated automatically by makefixed9(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{132,8,115},{130,7,31},{0,8,112}, + {0,8,48},{0,9,192},{128,7,10},{0,8,96},{0,8,32},{0,9,160}, + {0,8,0},{0,8,128},{0,8,64},{0,9,224},{128,7,6},{0,8,88}, + {0,8,24},{0,9,144},{131,7,59},{0,8,120},{0,8,56},{0,9,208}, + {129,7,17},{0,8,104},{0,8,40},{0,9,176},{0,8,8},{0,8,136}, + {0,8,72},{0,9,240},{128,7,4},{0,8,84},{0,8,20},{133,8,227}, + {131,7,43},{0,8,116},{0,8,52},{0,9,200},{129,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232}, + {128,7,8},{0,8,92},{0,8,28},{0,9,152},{132,7,83},{0,8,124}, + {0,8,60},{0,9,216},{130,7,23},{0,8,108},{0,8,44},{0,9,184}, + {0,8,12},{0,8,140},{0,8,76},{0,9,248},{128,7,3},{0,8,82}, + {0,8,18},{133,8,163},{131,7,35},{0,8,114},{0,8,50},{0,9,196}, + {129,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},{0,8,130}, + {0,8,66},{0,9,228},{128,7,7},{0,8,90},{0,8,26},{0,9,148}, + {132,7,67},{0,8,122},{0,8,58},{0,9,212},{130,7,19},{0,8,106}, + {0,8,42},{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244}, + {128,7,5},{0,8,86},{0,8,22},{65,8,0},{131,7,51},{0,8,118}, + {0,8,54},{0,9,204},{129,7,15},{0,8,102},{0,8,38},{0,9,172}, + {0,8,6},{0,8,134},{0,8,70},{0,9,236},{128,7,9},{0,8,94}, + {0,8,30},{0,9,156},{132,7,99},{0,8,126},{0,8,62},{0,9,220}, + {130,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{133,8,131}, + {130,7,31},{0,8,113},{0,8,49},{0,9,194},{128,7,10},{0,8,97}, + {0,8,33},{0,9,162},{0,8,1},{0,8,129},{0,8,65},{0,9,226}, + {128,7,6},{0,8,89},{0,8,25},{0,9,146},{131,7,59},{0,8,121}, + {0,8,57},{0,9,210},{129,7,17},{0,8,105},{0,8,41},{0,9,178}, + {0,8,9},{0,8,137},{0,8,73},{0,9,242},{128,7,4},{0,8,85}, + {0,8,21},{144,8,3},{131,7,43},{0,8,117},{0,8,53},{0,9,202}, + {129,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133}, + {0,8,69},{0,9,234},{128,7,8},{0,8,93},{0,8,29},{0,9,154}, + {132,7,83},{0,8,125},{0,8,61},{0,9,218},{130,7,23},{0,8,109}, + {0,8,45},{0,9,186},{0,8,13},{0,8,141},{0,8,77},{0,9,250}, + {128,7,3},{0,8,83},{0,8,19},{133,8,195},{131,7,35},{0,8,115}, + {0,8,51},{0,9,198},{129,7,11},{0,8,99},{0,8,35},{0,9,166}, + {0,8,3},{0,8,131},{0,8,67},{0,9,230},{128,7,7},{0,8,91}, + {0,8,27},{0,9,150},{132,7,67},{0,8,123},{0,8,59},{0,9,214}, + {130,7,19},{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139}, + {0,8,75},{0,9,246},{128,7,5},{0,8,87},{0,8,23},{77,8,0}, + {131,7,51},{0,8,119},{0,8,55},{0,9,206},{129,7,15},{0,8,103}, + {0,8,39},{0,9,174},{0,8,7},{0,8,135},{0,8,71},{0,9,238}, + {128,7,9},{0,8,95},{0,8,31},{0,9,158},{132,7,99},{0,8,127}, + {0,8,63},{0,9,222},{130,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80}, + {0,8,16},{132,8,115},{130,7,31},{0,8,112},{0,8,48},{0,9,193}, + {128,7,10},{0,8,96},{0,8,32},{0,9,161},{0,8,0},{0,8,128}, + {0,8,64},{0,9,225},{128,7,6},{0,8,88},{0,8,24},{0,9,145}, + {131,7,59},{0,8,120},{0,8,56},{0,9,209},{129,7,17},{0,8,104}, + {0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},{0,9,241}, + {128,7,4},{0,8,84},{0,8,20},{133,8,227},{131,7,43},{0,8,116}, + {0,8,52},{0,9,201},{129,7,13},{0,8,100},{0,8,36},{0,9,169}, + {0,8,4},{0,8,132},{0,8,68},{0,9,233},{128,7,8},{0,8,92}, + {0,8,28},{0,9,153},{132,7,83},{0,8,124},{0,8,60},{0,9,217}, + {130,7,23},{0,8,108},{0,8,44},{0,9,185},{0,8,12},{0,8,140}, + {0,8,76},{0,9,249},{128,7,3},{0,8,82},{0,8,18},{133,8,163}, + {131,7,35},{0,8,114},{0,8,50},{0,9,197},{129,7,11},{0,8,98}, + {0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {128,7,7},{0,8,90},{0,8,26},{0,9,149},{132,7,67},{0,8,122}, + {0,8,58},{0,9,213},{130,7,19},{0,8,106},{0,8,42},{0,9,181}, + {0,8,10},{0,8,138},{0,8,74},{0,9,245},{128,7,5},{0,8,86}, + {0,8,22},{65,8,0},{131,7,51},{0,8,118},{0,8,54},{0,9,205}, + {129,7,15},{0,8,102},{0,8,38},{0,9,173},{0,8,6},{0,8,134}, + {0,8,70},{0,9,237},{128,7,9},{0,8,94},{0,8,30},{0,9,157}, + {132,7,99},{0,8,126},{0,8,62},{0,9,221},{130,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253}, + {96,7,0},{0,8,81},{0,8,17},{133,8,131},{130,7,31},{0,8,113}, + {0,8,49},{0,9,195},{128,7,10},{0,8,97},{0,8,33},{0,9,163}, + {0,8,1},{0,8,129},{0,8,65},{0,9,227},{128,7,6},{0,8,89}, + {0,8,25},{0,9,147},{131,7,59},{0,8,121},{0,8,57},{0,9,211}, + {129,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},{0,8,137}, + {0,8,73},{0,9,243},{128,7,4},{0,8,85},{0,8,21},{144,8,3}, + {131,7,43},{0,8,117},{0,8,53},{0,9,203},{129,7,13},{0,8,101}, + {0,8,37},{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235}, + {128,7,8},{0,8,93},{0,8,29},{0,9,155},{132,7,83},{0,8,125}, + {0,8,61},{0,9,219},{130,7,23},{0,8,109},{0,8,45},{0,9,187}, + {0,8,13},{0,8,141},{0,8,77},{0,9,251},{128,7,3},{0,8,83}, + {0,8,19},{133,8,195},{131,7,35},{0,8,115},{0,8,51},{0,9,199}, + {129,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{128,7,7},{0,8,91},{0,8,27},{0,9,151}, + {132,7,67},{0,8,123},{0,8,59},{0,9,215},{130,7,19},{0,8,107}, + {0,8,43},{0,9,183},{0,8,11},{0,8,139},{0,8,75},{0,9,247}, + {128,7,5},{0,8,87},{0,8,23},{77,8,0},{131,7,51},{0,8,119}, + {0,8,55},{0,9,207},{129,7,15},{0,8,103},{0,8,39},{0,9,175}, + {0,8,7},{0,8,135},{0,8,71},{0,9,239},{128,7,9},{0,8,95}, + {0,8,31},{0,9,159},{132,7,99},{0,8,127},{0,8,63},{0,9,223}, + {130,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143}, + {0,8,79},{0,9,255} + }; + + static const code distfix[32] = { + {128,5,1},{135,5,257},{131,5,17},{139,5,4097},{129,5,5}, + {137,5,1025},{133,5,65},{141,5,16385},{128,5,3},{136,5,513}, + {132,5,33},{140,5,8193},{130,5,9},{138,5,2049},{134,5,129}, + {142,5,32769},{128,5,2},{135,5,385},{131,5,25},{139,5,6145}, + {129,5,7},{137,5,1537},{133,5,97},{141,5,24577},{128,5,4}, + {136,5,769},{132,5,49},{140,5,12289},{130,5,13},{138,5,3073}, + {134,5,193},{142,5,49153} + }; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inflate9.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inflate9.h new file mode 100644 index 00000000..ee9a7939 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inflate9.h @@ -0,0 +1,47 @@ +/* inflate9.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Possible inflate modes between inflate() calls */ +typedef enum { + TYPE, /* i: waiting for type bits, including last-flag bit */ + STORED, /* i: waiting for stored size (length and complement) */ + TABLE, /* i: waiting for dynamic block table lengths */ + LEN, /* i: waiting for length/lit code */ + DONE, /* finished check, done -- remain here until reset */ + BAD /* got a data error -- remain here until reset */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD mode -- not shown for clarity) + + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or DONE + STORED -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LEN or TYPE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + /* sliding window */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inftree9.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inftree9.c new file mode 100644 index 00000000..306c5f1b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inftree9.c @@ -0,0 +1,324 @@ +/* inftree9.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftree9.h" + +#define MAXBITS 15 + +const char inflate9_copyright[] = + " inflate9 1.2.5 Copyright 1995-2010 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table9(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, + 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 3, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, + 133, 133, 133, 133, 144, 73, 195}; + static const unsigned short dbase[32] = { /* Distance codes 0..31 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, + 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153}; + static const unsigned short dext[32] = { /* Distance codes 0..31 extra */ + 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, + 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, + 139, 139, 140, 140, 141, 141, 142, 142}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftree9.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inftree9.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inftree9.h new file mode 100644 index 00000000..5ab21f0c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/infback9/inftree9.h @@ -0,0 +1,61 @@ +/* inftree9.h -- header to use inftree9.c + * Copyright (C) 1995-2008 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 100eeeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1446, which is the sum of 852 for literal/length codes and 594 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 32 6 15" for distance codes returns 594. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in infback9.c. If the root table size is changed, + then these maximum sizes would be need to be recalculated and updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 594 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table9() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table9 OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/inflate86/inffas86.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/inflate86/inffas86.c new file mode 100644 index 00000000..7292f67b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/inflate86/inffas86.c @@ -0,0 +1,1157 @@ +/* inffas86.c is a hand tuned assembler version of + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ unsigned long hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } ar; + +#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->wnext; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((unsigned long)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + +#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) + __asm__ __volatile__ ( +" leaq %0, %%rax\n" +" movq %%rbp, 8(%%rax)\n" /* save regs rbp and rsp */ +" movq %%rsp, (%%rax)\n" +" movq %%rax, %%rsp\n" /* make rsp point to &ar */ +" movq 16(%%rsp), %%rsi\n" /* rsi = in */ +" movq 32(%%rsp), %%rdi\n" /* rdi = out */ +" movq 24(%%rsp), %%r9\n" /* r9 = last */ +" movq 48(%%rsp), %%r10\n" /* r10 = end */ +" movq 64(%%rsp), %%rbp\n" /* rbp = lcode */ +" movq 72(%%rsp), %%r11\n" /* r11 = dcode */ +" movq 80(%%rsp), %%rdx\n" /* rdx = hold */ +" movl 88(%%rsp), %%ebx\n" /* ebx = bits */ +" movl 100(%%rsp), %%r12d\n" /* r12d = lmask */ +" movl 104(%%rsp), %%r13d\n" /* r13d = dmask */ + /* r14d = len */ + /* r15d = dist */ +" cld\n" +" cmpq %%rdi, %%r10\n" +" je .L_one_time\n" /* if only one decode left */ +" cmpq %%rsi, %%r9\n" +" je .L_one_time\n" +" jmp .L_do_loop\n" + +".L_one_time:\n" +" movq %%r12, %%r8\n" /* r8 = lmask */ +" cmpb $32, %%bl\n" +" ja .L_get_length_code_one_time\n" + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ +" jmp .L_get_length_code_one_time\n" + +".align 32,0x90\n" +".L_while_test:\n" +" cmpq %%rdi, %%r10\n" +" jbe .L_break_loop\n" +" cmpq %%rsi, %%r9\n" +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" movq %%r12, %%r8\n" /* r8 = lmask */ +" cmpb $32, %%bl\n" +" ja .L_get_length_code\n" /* if (32 < bits) */ + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ + +".L_get_length_code:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" movq %%r12, %%r8\n" /* r8 = lmask */ +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" + +".L_get_length_code_one_time:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_length_base:\n" +" movl %%eax, %%r14d\n" /* len = this */ +" shrl $16, %%r14d\n" /* len = this.val */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ + +".L_add_bits_to_len:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrq %%cl, %%rdx\n" +" addl %%eax, %%r14d\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" movq %%r13, %%r8\n" /* r8 = dmask */ +" cmpb $32, %%bl\n" +" ja .L_get_distance_code\n" /* if (32 < bits) */ + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ + +".L_get_distance_code:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%r11,%%r8,4), %%eax\n" /* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%r15d\n" /* dist = this */ +" shrl $16, %%r15d\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" + +".L_add_bits_to_dist:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrq %%cl, %%rdx\n" +" addl %%eax, %%r15d\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movq %%rsi, %%r8\n" /* save in so from can use it's reg */ +" movq %%rdi, %%rax\n" +" subq 40(%%rsp), %%rax\n" /* nbytes = out - beg */ + +" cmpl %%r15d, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl %%r14d, %%ecx\n" /* ecx = len */ +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ + +" sarl %%ecx\n" +" jnc .L_copy_two\n" /* if len % 2 == 0 */ + +" rep movsw\n" +" movb (%%rsi), %%al\n" +" movb %%al, (%%rdi)\n" +" incq %%rdi\n" + +" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ +" jmp .L_while_test\n" + +".L_copy_two:\n" +" rep movsw\n" +" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_check_dist_one:\n" +" cmpl $1, %%r15d\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpq %%rdi, 40(%%rsp)\n" /* if out == beg, outside window */ +" je .L_check_window\n" + +" movl %%r14d, %%ecx\n" /* ecx = len */ +" movb -1(%%rdi), %%al\n" +" movb %%al, %%ah\n" + +" sarl %%ecx\n" +" jnc .L_set_two\n" +" movb %%al, (%%rdi)\n" +" incq %%rdi\n" + +".L_set_two:\n" +" rep stosw\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%r14d, %%eax\n" /* eax += len */ +" movl (%%rbp,%%rax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".align 32,0x90\n" +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%r15d, %%eax\n" /* eax += dist */ +" movl (%%r11,%%rax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".align 32,0x90\n" +".L_clip_window:\n" +" movl %%eax, %%ecx\n" /* ecx = nbytes */ +" movl 92(%%rsp), %%eax\n" /* eax = wsize, prepare for dist cmp */ +" negl %%ecx\n" /* nbytes = -nbytes */ + +" cmpl %%r15d, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%r15d, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 96(%%rsp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" movq 56(%%rsp), %%rsi\n" /* from = window */ +" subl %%ecx, %%eax\n" /* eax -= nbytes */ +" addq %%rax, %%rsi\n" /* from += wsize - nbytes */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%r14d\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* eax -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = &out[ -dist ] */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_wrap_around_window:\n" +" movl 96(%%rsp), %%eax\n" /* eax = write */ +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" movl 92(%%rsp), %%esi\n" /* from = wsize */ +" addq 56(%%rsp), %%rsi\n" /* from += window */ +" addq %%rax, %%rsi\n" /* from += write */ +" subq %%rcx, %%rsi\n" /* from -= nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq 56(%%rsp), %%rsi\n" /* from = window */ +" movl 96(%%rsp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_contiguous_in_window:\n" +" movq 56(%%rsp), %%rsi\n" /* rsi = window */ +" addq %%rax, %%rsi\n" +" subq %%rcx, %%rsi\n" /* from += write - nbytes */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ +" jmp .L_do_copy\n" /* if (nbytes >= len) */ + +".align 32,0x90\n" +".L_do_copy:\n" +" movl %%eax, %%ecx\n" /* ecx = len */ +" rep movsb\n" + +" movq %%r8, %%rsi\n" /* move in back to %esi, toss from */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl $4, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 116(%%rsp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movq %%rsi, 16(%%rsp)\n" /* in */ +" movq %%rdi, 32(%%rsp)\n" /* out */ +" movl %%ebx, 88(%%rsp)\n" /* bits */ +" movq %%rdx, 80(%%rsp)\n" /* hold */ +" movq (%%rsp), %%rax\n" /* restore rbp and rsp */ +" movq 8(%%rsp), %%rbp\n" +" movq %%rax, %%rsp\n" + : + : "m" (ar) + : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + ); +#elif ( defined( __GNUC__ ) || defined( __ICC ) ) && defined( __i386 ) + __asm__ __volatile__ ( +" leal %0, %%eax\n" +" movl %%esp, (%%eax)\n" /* save esp, ebp */ +" movl %%ebp, 4(%%eax)\n" +" movl %%eax, %%esp\n" +" movl 8(%%esp), %%esi\n" /* esi = in */ +" movl 16(%%esp), %%edi\n" /* edi = out */ +" movl 40(%%esp), %%edx\n" /* edx = hold */ +" movl 44(%%esp), %%ebx\n" /* ebx = bits */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ + +" cld\n" +" jmp .L_do_loop\n" + +".align 32,0x90\n" +".L_while_test:\n" +" cmpl %%edi, 24(%%esp)\n" /* out < end */ +" jbe .L_break_loop\n" +" cmpl %%esi, 12(%%esp)\n" /* in < last */ +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" cmpb $15, %%bl\n" +" ja .L_get_length_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_length_code:\n" +" movl 56(%%esp), %%eax\n" /* eax = lmask */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_length_base:\n" +" movl %%eax, %%ecx\n" /* len = this */ +" shrl $16, %%ecx\n" /* len = this.val */ +" movl %%ecx, 64(%%esp)\n" /* save len */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_len\n" /* if (op <= bits) */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_len:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, 64(%%esp)\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" cmpb $15, %%bl\n" +" ja .L_get_distance_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_distance_code:\n" +" movl 60(%%esp), %%eax\n" /* eax = dmask */ +" movl 36(%%esp), %%ecx\n" /* ecx = dcode */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%ebp\n" /* dist = this */ +" shrl $16, %%ebp\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_dist:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movl %%esi, 8(%%esp)\n" /* save in so from can use it's reg */ +" movl %%edi, %%eax\n" +" subl 20(%%esp), %%eax\n" /* nbytes = out - beg */ + +" cmpl %%ebp, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl 64(%%esp), %%ecx\n" /* ecx = len */ +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ + +" sarl %%ecx\n" +" jnc .L_copy_two\n" /* if len % 2 == 0 */ + +" rep movsw\n" +" movb (%%esi), %%al\n" +" movb %%al, (%%edi)\n" +" incl %%edi\n" + +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_copy_two:\n" +" rep movsw\n" +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_check_dist_one:\n" +" cmpl $1, %%ebp\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpl %%edi, 20(%%esp)\n" +" je .L_check_window\n" /* out == beg, if outside window */ + +" movl 64(%%esp), %%ecx\n" /* ecx = len */ +" movb -1(%%edi), %%al\n" +" movb %%al, %%ah\n" + +" sarl %%ecx\n" +" jnc .L_set_two\n" +" movb %%al, (%%edi)\n" +" incl %%edi\n" + +".L_set_two:\n" +" rep stosw\n" +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl 64(%%esp), %%eax\n" /* eax += len */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".align 32,0x90\n" +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%ebp, %%eax\n" /* eax += dist */ +" movl 36(%%esp), %%ecx\n" /* ecx = dcode */ +" movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".align 32,0x90\n" +".L_clip_window:\n" +" movl %%eax, %%ecx\n" +" movl 48(%%esp), %%eax\n" /* eax = wsize */ +" negl %%ecx\n" /* nbytes = -nbytes */ +" movl 28(%%esp), %%esi\n" /* from = window */ + +" cmpl %%ebp, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 52(%%esp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" subl %%ecx, %%eax\n" +" addl %%eax, %%esi\n" /* from += wsize - nbytes */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_wrap_around_window:\n" +" movl 52(%%esp), %%eax\n" /* eax = write */ +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" addl 48(%%esp), %%esi\n" /* from += wsize */ +" addl %%eax, %%esi\n" /* from += write */ +" subl %%ecx, %%esi\n" /* from -= nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl 28(%%esp), %%esi\n" /* from = window */ +" movl 52(%%esp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_contiguous_in_window:\n" +" addl %%eax, %%esi\n" +" subl %%ecx, %%esi\n" /* from += write - nbytes */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" /* if (nbytes >= len) */ + +".align 32,0x90\n" +".L_do_copy:\n" +" movl %%eax, %%ecx\n" +" rep movsb\n" + +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl 8(%%esp), %%esi\n" +" movl $4, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 72(%%esp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movl %%esi, 8(%%esp)\n" /* save in */ +" movl %%edi, 16(%%esp)\n" /* save out */ +" movl %%ebx, 44(%%esp)\n" /* save bits */ +" movl %%edx, 40(%%esp)\n" /* save hold */ +" movl 4(%%esp), %%ebp\n" /* restore esp, ebp */ +" movl (%%esp), %%esp\n" + : + : "m" (ar) + : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" + ); +#elif defined( _MSC_VER ) && ! defined( _M_AMD64 ) + __asm { + lea eax, ar + mov [eax], esp /* save esp, ebp */ + mov [eax+4], ebp + mov esp, eax + mov esi, [esp+8] /* esi = in */ + mov edi, [esp+16] /* edi = out */ + mov edx, [esp+40] /* edx = hold */ + mov ebx, [esp+44] /* ebx = bits */ + mov ebp, [esp+32] /* ebp = lcode */ + + cld + jmp L_do_loop + +ALIGN 4 +L_while_test: + cmp [esp+24], edi + jbe L_break_loop + cmp [esp+12], esi + jbe L_break_loop + +L_do_loop: + cmp bl, 15 + ja L_get_length_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_length_code: + mov eax, [esp+56] /* eax = lmask */ + and eax, edx /* eax &= hold */ + mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah /* cl = this.bits */ + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base /* if (op != 0) 45.7% */ + + shr eax, 16 /* output this.val char */ + stosb + jmp L_while_test + +ALIGN 4 +L_test_for_length_base: + mov ecx, eax /* len = this */ + shr ecx, 16 /* len = this.val */ + mov [esp+64], ecx /* save len */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + and cl, 15 /* op &= 15 */ + jz L_decode_distance /* if (!op) */ + cmp bl, cl + jae L_add_bits_to_len /* if (op <= bits) */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_len: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + shr edx, cl + add [esp+64], eax /* len += hold & mask[op] */ + +L_decode_distance: + cmp bl, 15 + ja L_get_distance_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_distance_code: + mov eax, [esp+60] /* eax = dmask */ + mov ecx, [esp+36] /* ecx = dcode */ + and eax, edx /* eax &= hold */ + mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */ + +L_dodist: + mov ebp, eax /* dist = this */ + shr ebp, 16 /* dist = this.val */ + mov cl, ah + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + mov cl, al /* cl = this.op */ + + test al, 16 /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 /* op &= 15 */ + jz L_check_dist_one + cmp bl, cl + jae L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_dist: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax /* (1 << op) - 1 */ + and eax, edx /* eax &= hold */ + shr edx, cl + add ebp, eax /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov [esp+8], esi /* save in so from can use it's reg */ + mov eax, edi + sub eax, [esp+20] /* nbytes = out - beg */ + + cmp eax, ebp + jb L_clip_window /* if (dist > nbytes) 4.2% */ + + mov ecx, [esp+64] /* ecx = len */ + mov esi, edi + sub esi, ebp /* from = out - dist */ + + sar ecx, 1 + jnc L_copy_two + + rep movsw + mov al, [esi] + mov [edi], al + inc edi + + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +L_copy_two: + rep movsw + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp ebp, 1 /* if dist 1, is a memset */ + jne L_check_window + cmp [esp+20], edi + je L_check_window /* out == beg, if outside window */ + + mov ecx, [esp+64] /* ecx = len */ + mov al, [edi-1] + mov ah, al + + sar ecx, 1 + jnc L_set_two + mov [edi], al /* memset out with from[-1] */ + inc edi + +L_set_two: + rep stosw + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, [esp+64] /* eax += len */ + mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, ebp /* eax += dist */ + mov ecx, [esp+36] /* ecx = dcode */ + mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +ALIGN 4 +L_clip_window: + mov ecx, eax + mov eax, [esp+48] /* eax = wsize */ + neg ecx /* nbytes = -nbytes */ + mov esi, [esp+28] /* from = window */ + + cmp eax, ebp + jb L_invalid_distance_too_far /* if (dist > wsize) */ + + add ecx, ebp /* nbytes = dist - nbytes */ + cmp dword ptr [esp+52], 0 + jne L_wrap_around_window /* if (write != 0) */ + + sub eax, ecx + add esi, eax /* from += wsize - nbytes */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_wrap_around_window: + mov eax, [esp+52] /* eax = write */ + cmp ecx, eax + jbe L_contiguous_in_window /* if (write >= nbytes) */ + + add esi, [esp+48] /* from += wsize */ + add esi, eax /* from += write */ + sub esi, ecx /* from -= nbytes */ + sub ecx, eax /* nbytes -= write */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, [esp+28] /* from = window */ + mov ecx, [esp+52] /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_contiguous_in_window: + add esi, eax + sub esi, ecx /* from += write - nbytes */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_do_copy: + mov ecx, eax + rep movsb + + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [esp+72], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [esp+72], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [esp+72], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov esi, [esp+4] + mov dword ptr [esp+72], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [esp+72], 0 + +L_break_loop_with_status: +/* put in, out, bits, and hold back into ar and pop esp */ + mov [esp+8], esi /* save in */ + mov [esp+16], edi /* save out */ + mov [esp+44], ebx /* save bits */ + mov [esp+40], edx /* save hold */ + mov ebp, [esp+4] /* restore esp, ebp */ + mov esp, [esp] + } +#else +#error "x86 architecture not defined" +#endif + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = ar.hold; + state->bits = ar.bits; + return; +} + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/inflate86/inffast.S b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/inflate86/inffast.S new file mode 100644 index 00000000..2245a290 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/inflate86/inffast.S @@ -0,0 +1,1368 @@ +/* + * inffast.S is a hand tuned assembler version of: + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * This version (Jan-23-2003) of inflate_fast was coded and tested under + * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that + * machine, I found that gzip style archives decompressed about 20% faster than + * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will + * depend on how large of a buffer is used for z_stream.next_in & next_out + * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in + * stream processing I/O and crc32/addler32. In my case, this routine used + * 70% of the cpu time and crc32 used 20%. + * + * I am confident that this version will work in the general case, but I have + * not tested a wide variety of datasets or a wide variety of platforms. + * + * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating. + * It should be a runtime flag instead of compile time flag... + * + * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction. + * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code + * is compiled. Without either option, runtime detection is enabled. Runtime + * detection should work on all modern cpus and the recomended algorithm (flip + * ID bit on eflags and then use the cpuid instruction) is used in many + * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12 + * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o + * inffast.obj generates a COFF object which can then be linked with MSVC++ + * compiled code. Tested under FreeBSD 4.7 with gcc-2.95. + * + * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and + * slower than compiler generated code). Adjusted cpuid check to use the MMX + * code only for Pentiums < P4 until I have more data on the P4. Speed + * improvment is only about 15% on the Athlon when compared with code generated + * with MSVC++. Not sure yet, but I think the P4 will also be slower using the + * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and + * have less latency than MMX ops. Added code to buffer the last 11 bytes of + * the input stream since the MMX code grabs bits in chunks of 32, which + * differs from the inffast.c algorithm. I don't think there would have been + * read overruns where a page boundary was crossed (a segfault), but there + * could have been overruns when next_in ends on unaligned memory (unintialized + * memory read). + * + * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C + * version of the non-MMX code so that it doesn't depend on zstrm and zstate + * structure offsets which are hard coded in this file. This was last tested + * with zlib-1.2.0 which is currently in beta testing, newer versions of this + * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and + * http://www.charm.net/~christop/zlib/ + */ + + +/* + * if you have underscore linking problems (_inflate_fast undefined), try + * using -DGAS_COFF + */ +#if ! defined( GAS_COFF ) && ! defined( GAS_ELF ) + +#if defined( WIN32 ) || defined( __CYGWIN__ ) +#define GAS_COFF /* windows object format */ +#else +#define GAS_ELF +#endif + +#endif /* ! GAS_COFF && ! GAS_ELF */ + + +#if defined( GAS_COFF ) + +/* coff externals have underscores */ +#define inflate_fast _inflate_fast +#define inflate_fast_use_mmx _inflate_fast_use_mmx + +#endif /* GAS_COFF */ + + +.file "inffast.S" + +.globl inflate_fast + +.text +.align 4,0 +.L_invalid_literal_length_code_msg: +.string "invalid literal/length code" + +.align 4,0 +.L_invalid_distance_code_msg: +.string "invalid distance code" + +.align 4,0 +.L_invalid_distance_too_far_msg: +.string "invalid distance too far back" + +#if ! defined( NO_MMX ) +.align 4,0 +.L_mask: /* mask[N] = ( 1 << N ) - 1 */ +.long 0 +.long 1 +.long 3 +.long 7 +.long 15 +.long 31 +.long 63 +.long 127 +.long 255 +.long 511 +.long 1023 +.long 2047 +.long 4095 +.long 8191 +.long 16383 +.long 32767 +.long 65535 +.long 131071 +.long 262143 +.long 524287 +.long 1048575 +.long 2097151 +.long 4194303 +.long 8388607 +.long 16777215 +.long 33554431 +.long 67108863 +.long 134217727 +.long 268435455 +.long 536870911 +.long 1073741823 +.long 2147483647 +.long 4294967295 +#endif /* NO_MMX */ + +.text + +/* + * struct z_stream offsets, in zlib.h + */ +#define next_in_strm 0 /* strm->next_in */ +#define avail_in_strm 4 /* strm->avail_in */ +#define next_out_strm 12 /* strm->next_out */ +#define avail_out_strm 16 /* strm->avail_out */ +#define msg_strm 24 /* strm->msg */ +#define state_strm 28 /* strm->state */ + +/* + * struct inflate_state offsets, in inflate.h + */ +#define mode_state 0 /* state->mode */ +#define wsize_state 32 /* state->wsize */ +#define write_state 40 /* state->write */ +#define window_state 44 /* state->window */ +#define hold_state 48 /* state->hold */ +#define bits_state 52 /* state->bits */ +#define lencode_state 68 /* state->lencode */ +#define distcode_state 72 /* state->distcode */ +#define lenbits_state 76 /* state->lenbits */ +#define distbits_state 80 /* state->distbits */ + +/* + * inflate_fast's activation record + */ +#define local_var_size 64 /* how much local space for vars */ +#define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */ +#define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */ + +/* + * offsets for local vars on stack + */ +#define out 60 /* unsigned char* */ +#define window 56 /* unsigned char* */ +#define wsize 52 /* unsigned int */ +#define write 48 /* unsigned int */ +#define in 44 /* unsigned char* */ +#define beg 40 /* unsigned char* */ +#define buf 28 /* char[ 12 ] */ +#define len 24 /* unsigned int */ +#define last 20 /* unsigned char* */ +#define end 16 /* unsigned char* */ +#define dcode 12 /* code* */ +#define lcode 8 /* code* */ +#define dmask 4 /* unsigned int */ +#define lmask 0 /* unsigned int */ + +/* + * typedef enum inflate_mode consts, in inflate.h + */ +#define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */ +#define INFLATE_MODE_BAD 26 + + +#if ! defined( USE_MMX ) && ! defined( NO_MMX ) + +#define RUN_TIME_MMX + +#define CHECK_MMX 1 +#define DO_USE_MMX 2 +#define DONT_USE_MMX 3 + +.globl inflate_fast_use_mmx + +.data + +.align 4,0 +inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */ +.long CHECK_MMX + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast_use_mmx,@object +.size inflate_fast_use_mmx,4 +#endif + +#endif /* RUN_TIME_MMX */ + +#if defined( GAS_COFF ) +/* coff info: scl 2 = extern, type 32 = function */ +.def inflate_fast; .scl 2; .type 32; .endef +#endif + +.text + +.align 32,0x90 +inflate_fast: + pushl %edi + pushl %esi + pushl %ebp + pushl %ebx + pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */ + subl $local_var_size, %esp + cld + +#define strm_r %esi +#define state_r %edi + + movl strm_sp(%esp), strm_r + movl state_strm(strm_r), state_r + + /* in = strm->next_in; + * out = strm->next_out; + * last = in + strm->avail_in - 11; + * beg = out - (start - strm->avail_out); + * end = out + (strm->avail_out - 257); + */ + movl avail_in_strm(strm_r), %edx + movl next_in_strm(strm_r), %eax + + addl %eax, %edx /* avail_in += next_in */ + subl $11, %edx /* avail_in -= 11 */ + + movl %eax, in(%esp) + movl %edx, last(%esp) + + movl start_sp(%esp), %ebp + movl avail_out_strm(strm_r), %ecx + movl next_out_strm(strm_r), %ebx + + subl %ecx, %ebp /* start -= avail_out */ + negl %ebp /* start = -start */ + addl %ebx, %ebp /* start += next_out */ + + subl $257, %ecx /* avail_out -= 257 */ + addl %ebx, %ecx /* avail_out += out */ + + movl %ebx, out(%esp) + movl %ebp, beg(%esp) + movl %ecx, end(%esp) + + /* wsize = state->wsize; + * write = state->write; + * window = state->window; + * hold = state->hold; + * bits = state->bits; + * lcode = state->lencode; + * dcode = state->distcode; + * lmask = ( 1 << state->lenbits ) - 1; + * dmask = ( 1 << state->distbits ) - 1; + */ + + movl lencode_state(state_r), %eax + movl distcode_state(state_r), %ecx + + movl %eax, lcode(%esp) + movl %ecx, dcode(%esp) + + movl $1, %eax + movl lenbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, lmask(%esp) + + movl $1, %eax + movl distbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, dmask(%esp) + + movl wsize_state(state_r), %eax + movl write_state(state_r), %ecx + movl window_state(state_r), %edx + + movl %eax, wsize(%esp) + movl %ecx, write(%esp) + movl %edx, window(%esp) + + movl hold_state(state_r), %ebp + movl bits_state(state_r), %ebx + +#undef strm_r +#undef state_r + +#define in_r %esi +#define from_r %esi +#define out_r %edi + + movl in(%esp), in_r + movl last(%esp), %ecx + cmpl in_r, %ecx + ja .L_align_long /* if in < last */ + + addl $11, %ecx /* ecx = &in[ avail_in ] */ + subl in_r, %ecx /* ecx = avail_in */ + movl $12, %eax + subl %ecx, %eax /* eax = 12 - avail_in */ + leal buf(%esp), %edi + rep movsb /* memcpy( buf, in, avail_in ) */ + movl %eax, %ecx + xorl %eax, %eax + rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */ + leal buf(%esp), in_r /* in = buf */ + movl in_r, last(%esp) /* last = in, do just one iteration */ + jmp .L_is_aligned + + /* align in_r on long boundary */ +.L_align_long: + testl $3, in_r + jz .L_is_aligned + xorl %eax, %eax + movb (in_r), %al + incl in_r + movl %ebx, %ecx + addl $8, %ebx + shll %cl, %eax + orl %eax, %ebp + jmp .L_align_long + +.L_is_aligned: + movl out(%esp), out_r + +#if defined( NO_MMX ) + jmp .L_do_loop +#endif + +#if defined( USE_MMX ) + jmp .L_init_mmx +#endif + +/*** Runtime MMX check ***/ + +#if defined( RUN_TIME_MMX ) +.L_check_mmx: + cmpl $DO_USE_MMX, inflate_fast_use_mmx + je .L_init_mmx + ja .L_do_loop /* > 2 */ + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushf + movl (%esp), %eax /* copy eflags to eax */ + xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21) + * to see if cpu supports cpuid... + * ID bit method not supported by NexGen but + * bios may load a cpuid instruction and + * cpuid may be disabled on Cyrix 5-6x86 */ + popf + pushf + popl %edx /* copy new eflags to edx */ + xorl %eax, %edx /* test if ID bit is flipped */ + jz .L_dont_use_mmx /* not flipped if zero */ + xorl %eax, %eax + cpuid + cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */ + jne .L_dont_use_mmx + cmpl $0x6c65746e, %ecx + jne .L_dont_use_mmx + cmpl $0x49656e69, %edx + jne .L_dont_use_mmx + movl $1, %eax + cpuid /* get cpu features */ + shrl $8, %eax + andl $15, %eax + cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */ + jne .L_dont_use_mmx + testl $0x800000, %edx /* test if MMX feature is set (bit 23) */ + jnz .L_use_mmx + jmp .L_dont_use_mmx +.L_use_mmx: + movl $DO_USE_MMX, inflate_fast_use_mmx + jmp .L_check_mmx_pop +.L_dont_use_mmx: + movl $DONT_USE_MMX, inflate_fast_use_mmx +.L_check_mmx_pop: + popl %edx + popl %ecx + popl %ebx + popl %eax + jmp .L_check_mmx +#endif + + +/*** Non-MMX code ***/ + +#if defined ( NO_MMX ) || defined( RUN_TIME_MMX ) + +#define hold_r %ebp +#define bits_r %bl +#define bitslong_r %ebx + +.align 32,0x90 +.L_while_test: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * do { + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = lcode[hold & lmask] + */ + cmpb $15, bits_r + ja .L_get_length_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_length_code: + movl lmask(%esp), %edx /* edx = lmask */ + movl lcode(%esp), %ecx /* ecx = lcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * dolen: + * bits -= this.bits; + * hold >>= this.bits + */ + movb %ah, %cl /* cl = this.bits */ + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* check if op is a literal + * if (op == 0) { + * PUP(out) = this.val; + * } + */ + testb %al, %al + jnz .L_test_for_length_base /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test + +.L_test_for_length_base: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len + * + * else if (op & 16) { + * len = this.val + * op &= 15 + * if (op) { + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * len += hold & mask[op]; + * bits -= op; + * hold >>= op; + * } + */ +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + movb %al, %cl + + testb $16, %al + jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + andb $15, %cl /* op &= 15 */ + jz .L_save_len /* if (!op) */ + cmpb %cl, bits_r + jae .L_add_bits_to_len /* if (op <= bits) */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_len: + movl $1, %eax + shll %cl, %eax + decl %eax + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, len_r /* len += hold & mask[op] */ + +.L_save_len: + movl len_r, len(%esp) /* save len */ +#undef len_r + +.L_decode_distance: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = dcode[hold & dmask]; + * dodist: + * bits -= this.bits; + * hold >>= this.bits; + * op = this.op; + */ + + cmpb $15, bits_r + ja .L_get_distance_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_distance_code: + movl dmask(%esp), %edx /* edx = dmask */ + movl dcode(%esp), %ecx /* ecx = dcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */ + +#define dist_r %edx +.L_dodist: + movl %eax, dist_r /* dist = this */ + shrl $16, dist_r /* dist = this.val */ + movb %ah, %cl + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* if (op & 16) { + * dist = this.val + * op &= 15 + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * dist += hold & mask[op]; + * bits -= op; + * hold >>= op; + */ + movb %al, %cl /* cl = this.op */ + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist + andb $15, %cl /* op &= 15 */ + jz .L_check_dist_one + cmpb %cl, bits_r + jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_dist: + movl $1, %eax + shll %cl, %eax + decl %eax /* (1 << op) - 1 */ + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */ + jmp .L_check_window + +.L_check_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * nbytes = out - beg; + * if (dist <= nbytes) { + * from = out - dist; + * do { + * PUP(out) = PUP(from); + * } while (--len > 0) { + * } + */ + + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window /* if (dist > nbytes) 4.2% */ + + movl len(%esp), %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +.align 16,0x90 +.L_check_dist_one: + cmpl $1, dist_r + jne .L_check_window + cmpl out_r, beg(%esp) + je .L_check_window + + decl out_r + movl len(%esp), %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + jmp .L_while_test + +.align 16,0x90 +.L_test_for_second_level_length: + /* else if ((op & 64) == 0) { + * this = lcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl lcode(%esp), %edx /* edx = lcode */ + movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */ + jmp .L_dolen + +.align 16,0x90 +.L_test_for_second_level_dist: + /* else if ((op & 64) == 0) { + * this = dcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl dcode(%esp), %edx /* edx = dcode */ + movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */ + jmp .L_dodist + +.align 16,0x90 +.L_clip_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * else { + * if (dist > wsize) { + * invalid distance + * } + * from = window; + * nbytes = dist - nbytes; + * if (write == 0) { + * from += wsize - nbytes; + */ +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = len + * + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define len_r %eax + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_wrap_around_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else if (write < nbytes) { + * from += wsize + write - nbytes; + * nbytes -= write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = window; + * nbytes = write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while(--nbytes); + * from = out - dist; + * } + * } + * } + */ +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_contiguous_in_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else { + * from += write - nbytes; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1: + /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out + * %eax = len + * + * while (len > 0) { + * PUP(out) = PUP(from); + * len--; + * } + * } + * } while (in < last && out < end); + */ +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +#undef len_r +#undef dist_r + +#endif /* NO_MMX || RUN_TIME_MMX */ + + +/*** MMX code ***/ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +.align 32,0x90 +.L_init_mmx: + emms + +#undef bits_r +#undef bitslong_r +#define bitslong_r %ebp +#define hold_mm %mm0 + movd %ebp, hold_mm + movl %ebx, bitslong_r + +#define used_mm %mm1 +#define dmask2_mm %mm2 +#define lmask2_mm %mm3 +#define lmask_mm %mm4 +#define dmask_mm %mm5 +#define tmp_mm %mm6 + + movd lmask(%esp), lmask_mm + movq lmask_mm, lmask2_mm + movd dmask(%esp), dmask_mm + movq dmask_mm, dmask2_mm + pxor used_mm, used_mm + movl lcode(%esp), %ebx /* ebx = lcode */ + jmp .L_do_loop_mmx + +.align 32,0x90 +.L_while_test_mmx: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_length_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_length_code_mmx: + pand hold_mm, lmask_mm + movd lmask_mm, %eax + movq lmask2_mm, lmask_mm + movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen_mmx: + movzbl %ah, %ecx /* ecx = this.bits */ + movd %ecx, used_mm + subl %ecx, bitslong_r /* bits -= this.bits */ + + testb %al, %al + jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test_mmx + +.L_test_for_length_base_mmx: +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + + testb $16, %al + jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */ + andl $15, %eax /* op &= 15 */ + jz .L_decode_distance_mmx /* if (!op) */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm + movd hold_mm, %ecx + subl %eax, bitslong_r + andl .L_mask(,%eax,4), %ecx + addl %ecx, len_r /* len += hold & mask[op] */ + +.L_decode_distance_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_dist_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_dist_code_mmx: + movl dcode(%esp), %ebx /* ebx = dcode */ + pand hold_mm, dmask_mm + movd dmask_mm, %eax + movq dmask2_mm, dmask_mm + movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */ + +.L_dodist_mmx: +#define dist_r %ebx + movzbl %ah, %ecx /* ecx = this.bits */ + movl %eax, dist_r + shrl $16, dist_r /* dist = this.val */ + subl %ecx, bitslong_r /* bits -= this.bits */ + movd %ecx, used_mm + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist_mmx + andl $15, %eax /* op &= 15 */ + jz .L_check_dist_one_mmx + +.L_add_bits_to_dist_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm /* save bit length of current op */ + movd hold_mm, %ecx /* get the next bits on input stream */ + subl %eax, bitslong_r /* bits -= op bits */ + andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */ + addl %ecx, dist_r /* dist += hold & mask[op] */ + +.L_check_window_mmx: + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */ + + movl len_r, %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_check_dist_one_mmx: + cmpl $1, dist_r + jne .L_check_window_mmx + cmpl out_r, beg(%esp) + je .L_check_window_mmx + + decl out_r + movl len_r, %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_test_for_second_level_length_mmx: + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + addl len_r, %ecx + movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dolen_mmx + +.align 16,0x90 +.L_test_for_second_level_dist_mmx: + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + movl dcode(%esp), %eax /* ecx = dcode */ + addl dist_r, %ecx + movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dodist_mmx + +.align 16,0x90 +.L_clip_window_mmx: +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window_mmx /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_wrap_around_window_mmx: +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_contiguous_in_window_mmx: +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1_mmx: +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +#undef hold_r +#undef bitslong_r + +#endif /* USE_MMX || RUN_TIME_MMX */ + + +/*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/ + +.L_invalid_distance_code: + /* else { + * strm->msg = "invalid distance code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_distance_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_test_for_end_of_block: + /* else if (op & 32) { + * state->mode = TYPE; + * break; + * } + */ + testb $32, %al + jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */ + + movl $0, %ecx + movl $INFLATE_MODE_TYPE, %edx + jmp .L_update_stream_state + +.L_invalid_literal_length_code: + /* else { + * strm->msg = "invalid literal/length code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_literal_length_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_invalid_distance_too_far: + /* strm->msg = "invalid distance too far back"; + * state->mode = BAD; + */ + movl in(%esp), in_r /* from_r has in's reg, put in back */ + movl $.L_invalid_distance_too_far_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_update_stream_state: + /* set strm->msg = %ecx, strm->state->mode = %edx */ + movl strm_sp(%esp), %eax + testl %ecx, %ecx /* if (msg != NULL) */ + jz .L_skip_msg + movl %ecx, msg_strm(%eax) /* strm->msg = msg */ +.L_skip_msg: + movl state_strm(%eax), %eax /* state = strm->state */ + movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */ + jmp .L_break_loop + +.align 32,0x90 +.L_break_loop: + +/* + * Regs: + * + * bits = %ebp when mmx, and in %ebx when non-mmx + * hold = %hold_mm when mmx, and in %ebp when non-mmx + * in = %esi + * out = %edi + */ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_next_in + +#endif /* RUN_TIME_MMX */ + + movl %ebp, %ebx + +.L_update_next_in: + +#endif + +#define strm_r %eax +#define state_r %edx + + /* len = bits >> 3; + * in -= len; + * bits -= len << 3; + * hold &= (1U << bits) - 1; + * state->hold = hold; + * state->bits = bits; + * strm->next_in = in; + * strm->next_out = out; + */ + movl strm_sp(%esp), strm_r + movl %ebx, %ecx + movl state_strm(strm_r), state_r + shrl $3, %ecx + subl %ecx, in_r + shll $3, %ecx + subl %ecx, %ebx + movl out_r, next_out_strm(strm_r) + movl %ebx, bits_state(state_r) + movl %ebx, %ecx + + leal buf(%esp), %ebx + cmpl %ebx, last(%esp) + jne .L_buf_not_used /* if buf != last */ + + subl %ebx, in_r /* in -= buf */ + movl next_in_strm(strm_r), %ebx + movl %ebx, last(%esp) /* last = strm->next_in */ + addl %ebx, in_r /* in += strm->next_in */ + movl avail_in_strm(strm_r), %ebx + subl $11, %ebx + addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */ + +.L_buf_not_used: + movl in_r, next_in_strm(strm_r) + + movl $1, %ebx + shll %cl, %ebx + decl %ebx + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_hold + +#endif /* RUN_TIME_MMX */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ebp + + emms + +.L_update_hold: + +#endif /* USE_MMX || RUN_TIME_MMX */ + + andl %ebx, %ebp + movl %ebp, hold_state(state_r) + +#define last_r %ebx + + /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */ + movl last(%esp), last_r + cmpl in_r, last_r + jbe .L_last_is_smaller /* if (in >= last) */ + + subl in_r, last_r /* last -= in */ + addl $11, last_r /* last += 11 */ + movl last_r, avail_in_strm(strm_r) + jmp .L_fixup_out +.L_last_is_smaller: + subl last_r, in_r /* in -= last */ + negl in_r /* in = -in */ + addl $11, in_r /* in += 11 */ + movl in_r, avail_in_strm(strm_r) + +#undef last_r +#define end_r %ebx + +.L_fixup_out: + /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/ + movl end(%esp), end_r + cmpl out_r, end_r + jbe .L_end_is_smaller /* if (out >= end) */ + + subl out_r, end_r /* end -= out */ + addl $257, end_r /* end += 257 */ + movl end_r, avail_out_strm(strm_r) + jmp .L_done +.L_end_is_smaller: + subl end_r, out_r /* out -= end */ + negl out_r /* out = -out */ + addl $257, out_r /* out += 257 */ + movl out_r, avail_out_strm(strm_r) + +#undef end_r +#undef strm_r +#undef state_r + +.L_done: + addl $local_var_size, %esp + popf + popl %ebx + popl %ebp + popl %esi + popl %edi + ret + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast,@function +.size inflate_fast,.-inflate_fast +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/test.cpp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/test.cpp new file mode 100644 index 00000000..7d265b3b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/test.cpp @@ -0,0 +1,24 @@ + +#include "zfstream.h" + +int main() { + + // Construct a stream object with this filebuffer. Anything sent + // to this stream will go to standard out. + gzofstream os( 1, ios::out ); + + // This text is getting compressed and sent to stdout. + // To prove this, run 'test | zcat'. + os << "Hello, Mommy" << endl; + + os << setcompressionlevel( Z_NO_COMPRESSION ); + os << "hello, hello, hi, ho!" << endl; + + setcompressionlevel( os, Z_DEFAULT_COMPRESSION ) + << "I'm compressing again" << endl; + + os.close(); + + return 0; + +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/zfstream.cpp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/zfstream.cpp new file mode 100644 index 00000000..d0cd85fa --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/zfstream.cpp @@ -0,0 +1,329 @@ + +#include "zfstream.h" + +gzfilebuf::gzfilebuf() : + file(NULL), + mode(0), + own_file_descriptor(0) +{ } + +gzfilebuf::~gzfilebuf() { + + sync(); + if ( own_file_descriptor ) + close(); + +} + +gzfilebuf *gzfilebuf::open( const char *name, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzopen(name, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 1; + + return this; + +} + +gzfilebuf *gzfilebuf::attach( int file_descriptor, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzdopen(file_descriptor, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 0; + + return this; + +} + +gzfilebuf *gzfilebuf::close() { + + if ( is_open() ) { + + sync(); + gzclose( file ); + file = NULL; + + } + + return this; + +} + +int gzfilebuf::setcompressionlevel( int comp_level ) { + + return gzsetparams(file, comp_level, -2); + +} + +int gzfilebuf::setcompressionstrategy( int comp_strategy ) { + + return gzsetparams(file, -2, comp_strategy); + +} + + +streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) { + + return streampos(EOF); + +} + +int gzfilebuf::underflow() { + + // If the file hasn't been opened for reading, error. + if ( !is_open() || !(mode & ios::in) ) + return EOF; + + // if a buffer doesn't exists, allocate one. + if ( !base() ) { + + if ( (allocate()) == EOF ) + return EOF; + setp(0,0); + + } else { + + if ( in_avail() ) + return (unsigned char) *gptr(); + + if ( out_waiting() ) { + if ( flushbuf() == EOF ) + return EOF; + } + + } + + // Attempt to fill the buffer. + + int result = fillbuf(); + if ( result == EOF ) { + // disable get area + setg(0,0,0); + return EOF; + } + + return (unsigned char) *gptr(); + +} + +int gzfilebuf::overflow( int c ) { + + if ( !is_open() || !(mode & ios::out) ) + return EOF; + + if ( !base() ) { + if ( allocate() == EOF ) + return EOF; + setg(0,0,0); + } else { + if (in_avail()) { + return EOF; + } + if (out_waiting()) { + if (flushbuf() == EOF) + return EOF; + } + } + + int bl = blen(); + setp( base(), base() + bl); + + if ( c != EOF ) { + + *pptr() = c; + pbump(1); + + } + + return 0; + +} + +int gzfilebuf::sync() { + + if ( !is_open() ) + return EOF; + + if ( out_waiting() ) + return flushbuf(); + + return 0; + +} + +int gzfilebuf::flushbuf() { + + int n; + char *q; + + q = pbase(); + n = pptr() - q; + + if ( gzwrite( file, q, n) < n ) + return EOF; + + setp(0,0); + + return 0; + +} + +int gzfilebuf::fillbuf() { + + int required; + char *p; + + p = base(); + + required = blen(); + + int t = gzread( file, p, required ); + + if ( t <= 0) return EOF; + + setg( base(), base(), base()+t); + + return t; + +} + +gzfilestream_common::gzfilestream_common() : + ios( gzfilestream_common::rdbuf() ) +{ } + +gzfilestream_common::~gzfilestream_common() +{ } + +void gzfilestream_common::attach( int fd, int io_mode ) { + + if ( !buffer.attach( fd, io_mode) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::open( const char *name, int io_mode ) { + + if ( !buffer.open( name, io_mode ) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::close() { + + if ( !buffer.close() ) + clear( ios::failbit | ios::badbit ); + +} + +gzfilebuf *gzfilestream_common::rdbuf() +{ + return &buffer; +} + +gzifstream::gzifstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzifstream::gzifstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzifstream::gzifstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzifstream::~gzifstream() { } + +gzofstream::gzofstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzofstream::gzofstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzofstream::gzofstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzofstream::~gzofstream() { } diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/zfstream.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/zfstream.h new file mode 100644 index 00000000..ed79098a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream/zfstream.h @@ -0,0 +1,128 @@ + +#ifndef zfstream_h +#define zfstream_h + +#include +#include "zlib.h" + +class gzfilebuf : public streambuf { + +public: + + gzfilebuf( ); + virtual ~gzfilebuf(); + + gzfilebuf *open( const char *name, int io_mode ); + gzfilebuf *attach( int file_descriptor, int io_mode ); + gzfilebuf *close(); + + int setcompressionlevel( int comp_level ); + int setcompressionstrategy( int comp_strategy ); + + inline int is_open() const { return (file !=NULL); } + + virtual streampos seekoff( streamoff, ios::seek_dir, int ); + + virtual int sync(); + +protected: + + virtual int underflow(); + virtual int overflow( int = EOF ); + +private: + + gzFile file; + short mode; + short own_file_descriptor; + + int flushbuf(); + int fillbuf(); + +}; + +class gzfilestream_common : virtual public ios { + + friend class gzifstream; + friend class gzofstream; + friend gzofstream &setcompressionlevel( gzofstream &, int ); + friend gzofstream &setcompressionstrategy( gzofstream &, int ); + +public: + virtual ~gzfilestream_common(); + + void attach( int fd, int io_mode ); + void open( const char *name, int io_mode ); + void close(); + +protected: + gzfilestream_common(); + +private: + gzfilebuf *rdbuf(); + + gzfilebuf buffer; + +}; + +class gzifstream : public gzfilestream_common, public istream { + +public: + + gzifstream(); + gzifstream( const char *name, int io_mode = ios::in ); + gzifstream( int fd, int io_mode = ios::in ); + + virtual ~gzifstream(); + +}; + +class gzofstream : public gzfilestream_common, public ostream { + +public: + + gzofstream(); + gzofstream( const char *name, int io_mode = ios::out ); + gzofstream( int fd, int io_mode = ios::out ); + + virtual ~gzofstream(); + +}; + +template class gzomanip { + friend gzofstream &operator<<(gzofstream &, const gzomanip &); +public: + gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { } +private: + gzofstream &(*func)(gzofstream &, T); + T val; +}; + +template gzofstream &operator<<(gzofstream &s, const gzomanip &m) +{ + return (*m.func)(s, m.val); +} + +inline gzofstream &setcompressionlevel( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionlevel(l); + return s; +} + +inline gzofstream &setcompressionstrategy( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionstrategy(l); + return s; +} + +inline gzomanip setcompressionlevel(int l) +{ + return gzomanip(&setcompressionlevel,l); +} + +inline gzomanip setcompressionstrategy(int l) +{ + return gzomanip(&setcompressionstrategy,l); +} + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream2/zstream.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream2/zstream.h new file mode 100644 index 00000000..8ba7f050 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream2/zstream.h @@ -0,0 +1,307 @@ +/* + * + * Copyright (c) 1997 + * Christian Michelsen Research AS + * Advanced Computing + * Fantoftvegen 38, 5036 BERGEN, Norway + * http://www.cmr.no + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Christian Michelsen Research AS makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef ZSTREAM__H +#define ZSTREAM__H + +/* + * zstream.h - C++ interface to the 'zlib' general purpose compression library + * $Id: zstream.h 66 2005-08-17 18:20:58Z andreas_kupries $ + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(_WIN32) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +class zstringlen { +public: + zstringlen(class izstream&); + zstringlen(class ozstream&, const char*); + size_t value() const { return val.word; } +private: + struct Val { unsigned char byte; size_t word; } val; +}; + +// ----------------------------- izstream ----------------------------- + +class izstream +{ + public: + izstream() : m_fp(0) {} + izstream(FILE* fp) : m_fp(0) { open(fp); } + izstream(const char* name) : m_fp(0) { open(name); } + ~izstream() { close(); } + + /* Opens a gzip (.gz) file for reading. + * open() can be used to read a file which is not in gzip format; + * in this case read() will directly read from the file without + * decompression. errno can be checked to distinguish two error + * cases (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name) { + if (m_fp) close(); + m_fp = ::gzopen(name, "rb"); + } + + void open(FILE* fp) { + SET_BINARY_MODE(fp); + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), "rb"); + } + + /* Flushes all pending input if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + int r = ::gzclose(m_fp); + m_fp = 0; return r; + } + + /* Binary read the given number of bytes from the compressed file. + */ + int read(void* buf, size_t len) { + return ::gzread(m_fp, buf, len); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + private: + gzFile m_fp; +}; + +/* + * Binary read the given (array of) object(s) from the compressed file. + * If the input file was not in gzip format, read() copies the objects number + * of bytes into the buffer. + * returns the number of uncompressed bytes actually read + * (0 for end of file, -1 for error). + */ +template +inline int read(izstream& zs, T* x, Items items) { + return ::gzread(zs.fp(), x, items*sizeof(T)); +} + +/* + * Binary input with the '>' operator. + */ +template +inline izstream& operator>(izstream& zs, T& x) { + ::gzread(zs.fp(), &x, sizeof(T)); + return zs; +} + + +inline zstringlen::zstringlen(izstream& zs) { + zs > val.byte; + if (val.byte == 255) zs > val.word; + else val.word = val.byte; +} + +/* + * Read length of string + the string with the '>' operator. + */ +inline izstream& operator>(izstream& zs, char* x) { + zstringlen len(zs); + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return zs; +} + +inline char* read_string(izstream& zs) { + zstringlen len(zs); + char* x = new char[len.value()+1]; + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return x; +} + +// ----------------------------- ozstream ----------------------------- + +class ozstream +{ + public: + ozstream() : m_fp(0), m_os(0) { + } + ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(fp, level); + } + ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(name, level); + } + ~ozstream() { + close(); + } + + /* Opens a gzip (.gz) file for writing. + * The compression level parameter should be in 0..9 + * errno can be checked to distinguish two error cases + * (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name, int level = Z_DEFAULT_COMPRESSION) { + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzopen(name, mode); + } + + /* open from a FILE pointer. + */ + void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) { + SET_BINARY_MODE(fp); + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), mode); + } + + /* Flushes all pending output if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + if (m_os) { + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = 0; + } + int r = ::gzclose(m_fp); m_fp = 0; return r; + } + + /* Binary write the given number of bytes into the compressed file. + */ + int write(const void* buf, size_t len) { + return ::gzwrite(m_fp, (voidp) buf, len); + } + + /* Flushes all pending output into the compressed file. The parameter + * _flush is as in the deflate() function. The return value is the zlib + * error number (see function gzerror below). flush() returns Z_OK if + * the flush_ parameter is Z_FINISH and all output could be flushed. + * flush() should be called only when strictly necessary because it can + * degrade compression. + */ + int flush(int _flush) { + os_flush(); + return ::gzflush(m_fp, _flush); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + ostream& os() { + if (m_os == 0) m_os = new ostrstream; + return *m_os; + } + + void os_flush() { + if (m_os && m_os->pcount()>0) { + ostrstream* oss = new ostrstream; + oss->fill(m_os->fill()); + oss->flags(m_os->flags()); + oss->precision(m_os->precision()); + oss->width(m_os->width()); + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = oss; + } + } + + private: + gzFile m_fp; + ostrstream* m_os; +}; + +/* + * Binary write the given (array of) object(s) into the compressed file. + * returns the number of uncompressed bytes actually written + * (0 in case of error). + */ +template +inline int write(ozstream& zs, const T* x, Items items) { + return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T)); +} + +/* + * Binary output with the '<' operator. + */ +template +inline ozstream& operator<(ozstream& zs, const T& x) { + ::gzwrite(zs.fp(), (voidp) &x, sizeof(T)); + return zs; +} + +inline zstringlen::zstringlen(ozstream& zs, const char* x) { + val.byte = 255; val.word = ::strlen(x); + if (val.word < 255) zs < (val.byte = val.word); + else zs < val; +} + +/* + * Write length of string + the string with the '<' operator. + */ +inline ozstream& operator<(ozstream& zs, const char* x) { + zstringlen len(zs, x); + ::gzwrite(zs.fp(), (voidp) x, len.value()); + return zs; +} + +#ifdef _MSC_VER +inline ozstream& operator<(ozstream& zs, char* const& x) { + return zs < (const char*) x; +} +#endif + +/* + * Ascii write with the << operator; + */ +template +inline ostream& operator<<(ozstream& zs, const T& x) { + zs.os_flush(); + return zs.os() << x; +} + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream2/zstream_test.cpp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream2/zstream_test.cpp new file mode 100644 index 00000000..6273f62d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream2/zstream_test.cpp @@ -0,0 +1,25 @@ +#include "zstream.h" +#include +#include +#include + +void main() { + char h[256] = "Hello"; + char* g = "Goodbye"; + ozstream out("temp.gz"); + out < "This works well" < h < g; + out.close(); + + izstream in("temp.gz"); // read it back + char *x = read_string(in), *y = new char[256], z[256]; + in > y > z; + in.close(); + cout << x << endl << y << endl << z << endl; + + out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results + out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl; + out << z << endl << y << endl << x << endl; + out << 1.1234567890123456789 << endl; + + delete[] x; delete[] y; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/README new file mode 100644 index 00000000..f7b319ab --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/README @@ -0,0 +1,35 @@ +These classes provide a C++ stream interface to the zlib library. It allows you +to do things like: + + gzofstream outf("blah.gz"); + outf << "These go into the gzip file " << 123 << endl; + +It does this by deriving a specialized stream buffer for gzipped files, which is +the way Stroustrup would have done it. :-> + +The gzifstream and gzofstream classes were originally written by Kevin Ruland +and made available in the zlib contrib/iostream directory. The older version still +compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of +this version. + +The new classes are as standard-compliant as possible, closely following the +approach of the standard library's fstream classes. It compiles under gcc versions +3.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard +library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs +from the previous one in the following respects: +- added showmanyc +- added setbuf, with support for unbuffered output via setbuf(0,0) +- a few bug fixes of stream behavior +- gzipped output file opened with default compression level instead of maximum level +- setcompressionlevel()/strategy() members replaced by single setcompression() + +The code is provided "as is", with the permission to use, copy, modify, distribute +and sell it for any purpose without fee. + +Ludwig Schwardt + + +DSP Lab +Electrical & Electronic Engineering Department +University of Stellenbosch +South Africa diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/TODO b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/TODO new file mode 100644 index 00000000..7032f97b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/TODO @@ -0,0 +1,17 @@ +Possible upgrades to gzfilebuf: + +- The ability to do putback (e.g. putbackfail) + +- The ability to seek (zlib supports this, but could be slow/tricky) + +- Simultaneous read/write access (does it make sense?) + +- Support for ios_base::ate open mode + +- Locale support? + +- Check public interface to see which calls give problems + (due to dependence on library internals) + +- Override operator<<(ostream&, gzfilebuf*) to allow direct copying + of stream buffer to stream ( i.e. os << is.rdbuf(); ) diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/test.cc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/test.cc new file mode 100644 index 00000000..94235334 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/test.cc @@ -0,0 +1,50 @@ +/* + * Test program for gzifstream and gzofstream + * + * by Ludwig Schwardt + * original version by Kevin Ruland + */ + +#include "zfstream.h" +#include // for cout + +int main() { + + gzofstream outf; + gzifstream inf; + char buf[80]; + + outf.open("test1.txt.gz"); + outf << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n" + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + + std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n"; + inf.open("test1.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + outf.rdbuf()->pubsetbuf(0,0); + outf.open("test2.txt.gz"); + outf << setcompression(Z_NO_COMPRESSION) + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form"; + + std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n"; + inf.rdbuf()->pubsetbuf(0,0); + inf.open("test2.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + return 0; + +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/zfstream.cc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/zfstream.cc new file mode 100644 index 00000000..94eb9334 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/zfstream.cc @@ -0,0 +1,479 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#include "zfstream.h" +#include // for strcpy, strcat, strlen (mode strings) +#include // for BUFSIZ + +// Internal buffer sizes (default and "unbuffered" versions) +#define BIGBUFSIZE BUFSIZ +#define SMALLBUFSIZE 1 + +/*****************************************************************************/ + +// Default constructor +gzfilebuf::gzfilebuf() +: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false), + buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true) +{ + // No buffers to start with + this->disable_buffer(); +} + +// Destructor +gzfilebuf::~gzfilebuf() +{ + // Sync output buffer and close only if responsible for file + // (i.e. attached streams should be left open at this stage) + this->sync(); + if (own_fd) + this->close(); + // Make sure internal buffer is deallocated + this->disable_buffer(); +} + +// Set compression level and strategy +int +gzfilebuf::setcompression(int comp_level, + int comp_strategy) +{ + return gzsetparams(file, comp_level, comp_strategy); +} + +// Open gzipped file +gzfilebuf* +gzfilebuf::open(const char *name, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to open file + if ((file = gzopen(name, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = true; + return this; +} + +// Attach to gzipped file +gzfilebuf* +gzfilebuf::attach(int fd, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzdopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to attach to file + if ((file = gzdopen(fd, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = false; + return this; +} + +// Close gzipped file +gzfilebuf* +gzfilebuf::close() +{ + // Fail immediately if no file is open + if (!this->is_open()) + return NULL; + // Assume success + gzfilebuf* retval = this; + // Attempt to sync and close gzipped file + if (this->sync() == -1) + retval = NULL; + if (gzclose(file) < 0) + retval = NULL; + // File is now gone anyway (postcondition [27.8.1.3.8]) + file = NULL; + own_fd = false; + // Destroy internal buffer if it exists + this->disable_buffer(); + return retval; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Convert int open mode to mode string +bool +gzfilebuf::open_mode(std::ios_base::openmode mode, + char* c_mode) const +{ + bool testb = mode & std::ios_base::binary; + bool testi = mode & std::ios_base::in; + bool testo = mode & std::ios_base::out; + bool testt = mode & std::ios_base::trunc; + bool testa = mode & std::ios_base::app; + + // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) + // Original zfstream hardcoded the compression level to maximum here... + // Double the time for less than 1% size improvement seems + // excessive though - keeping it at the default level + // To change back, just append "9" to the next three mode strings + if (!testi && testo && !testt && !testa) + strcpy(c_mode, "w"); + if (!testi && testo && !testt && testa) + strcpy(c_mode, "a"); + if (!testi && testo && testt && !testa) + strcpy(c_mode, "w"); + if (testi && !testo && !testt && !testa) + strcpy(c_mode, "r"); + // No read/write mode yet +// if (testi && testo && !testt && !testa) +// strcpy(c_mode, "r+"); +// if (testi && testo && testt && !testa) +// strcpy(c_mode, "w+"); + + // Mode string should be empty for invalid combination of flags + if (strlen(c_mode) == 0) + return false; + if (testb) + strcat(c_mode, "b"); + return true; +} + +// Determine number of characters in internal get buffer +std::streamsize +gzfilebuf::showmanyc() +{ + // Calls to underflow will fail if file not opened for reading + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return -1; + // Make sure get area is in use + if (this->gptr() && (this->gptr() < this->egptr())) + return std::streamsize(this->egptr() - this->gptr()); + else + return 0; +} + +// Fill get area from gzipped file +gzfilebuf::int_type +gzfilebuf::underflow() +{ + // If something is left in the get area by chance, return it + // (this shouldn't normally happen, as underflow is only supposed + // to be called when gptr >= egptr, but it serves as error check) + if (this->gptr() && (this->gptr() < this->egptr())) + return traits_type::to_int_type(*(this->gptr())); + + // If the file hasn't been opened for reading, produce error + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return traits_type::eof(); + + // Attempt to fill internal buffer from gzipped file + // (buffer must be guaranteed to exist...) + int bytes_read = gzread(file, buffer, buffer_size); + // Indicates error or EOF + if (bytes_read <= 0) + { + // Reset get area + this->setg(buffer, buffer, buffer); + return traits_type::eof(); + } + // Make all bytes read from file available as get area + this->setg(buffer, buffer, buffer + bytes_read); + + // Return next character in get area + return traits_type::to_int_type(*(this->gptr())); +} + +// Write put area to gzipped file +gzfilebuf::int_type +gzfilebuf::overflow(int_type c) +{ + // Determine whether put area is in use + if (this->pbase()) + { + // Double-check pointer range + if (this->pptr() > this->epptr() || this->pptr() < this->pbase()) + return traits_type::eof(); + // Add extra character to buffer if not EOF + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + *(this->pptr()) = traits_type::to_char_type(c); + this->pbump(1); + } + // Number of characters to write to file + int bytes_to_write = this->pptr() - this->pbase(); + // Overflow doesn't fail if nothing is to be written + if (bytes_to_write > 0) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // If gzipped file won't accept all bytes written to it, fail + if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write) + return traits_type::eof(); + // Reset next pointer to point to pbase on success + this->pbump(-bytes_to_write); + } + } + // Write extra character to file if not EOF + else if (!traits_type::eq_int_type(c, traits_type::eof())) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // Impromptu char buffer (allows "unbuffered" output) + char_type last_char = traits_type::to_char_type(c); + // If gzipped file won't accept this character, fail + if (gzwrite(file, &last_char, 1) != 1) + return traits_type::eof(); + } + + // If you got here, you have succeeded (even if c was EOF) + // The return value should therefore be non-EOF + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + else + return c; +} + +// Assign new buffer +std::streambuf* +gzfilebuf::setbuf(char_type* p, + std::streamsize n) +{ + // First make sure stuff is sync'ed, for safety + if (this->sync() == -1) + return NULL; + // If buffering is turned off on purpose via setbuf(0,0), still allocate one... + // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at + // least a buffer of size 1 (very inefficient though, therefore make it bigger?) + // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems) + if (!p || !n) + { + // Replace existing buffer (if any) with small internal buffer + this->disable_buffer(); + buffer = NULL; + buffer_size = 0; + own_buffer = true; + this->enable_buffer(); + } + else + { + // Replace existing buffer (if any) with external buffer + this->disable_buffer(); + buffer = p; + buffer_size = n; + own_buffer = false; + this->enable_buffer(); + } + return this; +} + +// Write put area to gzipped file (i.e. ensures that put area is empty) +int +gzfilebuf::sync() +{ + return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Allocate internal buffer +void +gzfilebuf::enable_buffer() +{ + // If internal buffer required, allocate one + if (own_buffer && !buffer) + { + // Check for buffered vs. "unbuffered" + if (buffer_size > 0) + { + // Allocate internal buffer + buffer = new char_type[buffer_size]; + // Get area starts empty and will be expanded by underflow as need arises + this->setg(buffer, buffer, buffer); + // Setup entire internal buffer as put area. + // The one-past-end pointer actually points to the last element of the buffer, + // so that overflow(c) can safely add the extra character c to the sequence. + // These pointers remain in place for the duration of the buffer + this->setp(buffer, buffer + buffer_size - 1); + } + else + { + // Even in "unbuffered" case, (small?) get buffer is still required + buffer_size = SMALLBUFSIZE; + buffer = new char_type[buffer_size]; + this->setg(buffer, buffer, buffer); + // "Unbuffered" means no put buffer + this->setp(0, 0); + } + } + else + { + // If buffer already allocated, reset buffer pointers just to make sure no + // stale chars are lying around + this->setg(buffer, buffer, buffer); + this->setp(buffer, buffer + buffer_size - 1); + } +} + +// Destroy internal buffer +void +gzfilebuf::disable_buffer() +{ + // If internal buffer exists, deallocate it + if (own_buffer && buffer) + { + // Preserve unbuffered status by zeroing size + if (!this->pbase()) + buffer_size = 0; + delete[] buffer; + buffer = NULL; + this->setg(0, 0, 0); + this->setp(0, 0); + } + else + { + // Reset buffer pointers to initial state if external buffer exists + this->setg(buffer, buffer, buffer); + if (buffer) + this->setp(buffer, buffer + buffer_size - 1); + else + this->setp(0, 0); + } +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzifstream::gzifstream() +: std::istream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzifstream::gzifstream(const char* name, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzifstream::gzifstream(int fd, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzifstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzifstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzifstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzofstream::gzofstream() +: std::ostream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzofstream::gzofstream(const char* name, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzofstream::gzofstream(int fd, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzofstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzofstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzofstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/zfstream.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/zfstream.h new file mode 100644 index 00000000..8574479a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/iostream3/zfstream.h @@ -0,0 +1,466 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#ifndef ZFSTREAM_H +#define ZFSTREAM_H + +#include // not iostream, since we don't need cin/cout +#include +#include "zlib.h" + +/*****************************************************************************/ + +/** + * @brief Gzipped file stream buffer class. + * + * This class implements basic_filebuf for gzipped files. It doesn't yet support + * seeking (allowed by zlib but slow/limited), putback and read/write access + * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard + * file streambuf. +*/ +class gzfilebuf : public std::streambuf +{ +public: + // Default constructor. + gzfilebuf(); + + // Destructor. + virtual + ~gzfilebuf(); + + /** + * @brief Set compression level and strategy on the fly. + * @param comp_level Compression level (see zlib.h for allowed values) + * @param comp_strategy Compression strategy (see zlib.h for allowed values) + * @return Z_OK on success, Z_STREAM_ERROR otherwise. + * + * Unfortunately, these parameters cannot be modified separately, as the + * previous zfstream version assumed. Since the strategy is seldom changed, + * it can default and setcompression(level) then becomes like the old + * setcompressionlevel(level). + */ + int + setcompression(int comp_level, + int comp_strategy = Z_DEFAULT_STRATEGY); + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() const { return (file != NULL); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + open(const char* name, + std::ios_base::openmode mode); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + attach(int fd, + std::ios_base::openmode mode); + + /** + * @brief Close gzipped file. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + close(); + +protected: + /** + * @brief Convert ios open mode int to mode string used by zlib. + * @return True if valid mode flag combination. + */ + bool + open_mode(std::ios_base::openmode mode, + char* c_mode) const; + + /** + * @brief Number of characters available in stream buffer. + * @return Number of characters. + * + * This indicates number of characters in get area of stream buffer. + * These characters can be read without accessing the gzipped file. + */ + virtual std::streamsize + showmanyc(); + + /** + * @brief Fill get area from gzipped file. + * @return First character in get area on success, EOF on error. + * + * This actually reads characters from gzipped file to stream + * buffer. Always buffered. + */ + virtual int_type + underflow(); + + /** + * @brief Write put area to gzipped file. + * @param c Extra character to add to buffer contents. + * @return Non-EOF on success, EOF on error. + * + * This actually writes characters in stream buffer to + * gzipped file. With unbuffered output this is done one + * character at a time. + */ + virtual int_type + overflow(int_type c = traits_type::eof()); + + /** + * @brief Installs external stream buffer. + * @param p Pointer to char buffer. + * @param n Size of external buffer. + * @return @c this on success, NULL on failure. + * + * Call setbuf(0,0) to enable unbuffered output. + */ + virtual std::streambuf* + setbuf(char_type* p, + std::streamsize n); + + /** + * @brief Flush stream buffer to file. + * @return 0 on success, -1 on error. + * + * This calls underflow(EOF) to do the job. + */ + virtual int + sync(); + +// +// Some future enhancements +// +// virtual int_type uflow(); +// virtual int_type pbackfail(int_type c = traits_type::eof()); +// virtual pos_type +// seekoff(off_type off, +// std::ios_base::seekdir way, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); +// virtual pos_type +// seekpos(pos_type sp, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); + +private: + /** + * @brief Allocate internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that a proper internal buffer exists if it is required. If the + * buffer already exists or is external, the buffer pointers will be + * reset to their original state. + */ + void + enable_buffer(); + + /** + * @brief Destroy internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that the internal buffer is deallocated if it exists. In any + * case, it will also reset the buffer pointers. + */ + void + disable_buffer(); + + /** + * Underlying file pointer. + */ + gzFile file; + + /** + * Mode in which file was opened. + */ + std::ios_base::openmode io_mode; + + /** + * @brief True if this object owns file descriptor. + * + * This makes the class responsible for closing the file + * upon destruction. + */ + bool own_fd; + + /** + * @brief Stream buffer. + * + * For simplicity this remains allocated on the free store for the + * entire life span of the gzfilebuf object, unless replaced by setbuf. + */ + char_type* buffer; + + /** + * @brief Stream buffer size. + * + * Defaults to system default buffer size (typically 8192 bytes). + * Modified by setbuf. + */ + std::streamsize buffer_size; + + /** + * @brief True if this object owns stream buffer. + * + * This makes the class responsible for deleting the buffer + * upon destruction. + */ + bool own_buffer; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file input stream class. + * + * This class implements ifstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzifstream : public std::istream +{ +public: + // Default constructor + gzifstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ifstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream class. + * + * This class implements ofstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzofstream : public std::ostream +{ +public: + // Default constructor + gzofstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ofstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream manipulator class. + * + * This class defines a two-argument manipulator for gzofstream. It is used + * as base for the setcompression(int,int) manipulator. +*/ +template + class gzomanip2 + { + public: + // Allows insertor to peek at internals + template + friend gzofstream& + operator<<(gzofstream&, + const gzomanip2&); + + // Constructor + gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2), + T1 v1, + T2 v2); + private: + // Underlying manipulator function + gzofstream& + (*func)(gzofstream&, T1, T2); + + // Arguments for manipulator function + T1 val1; + T2 val2; + }; + +/*****************************************************************************/ + +// Manipulator function thunks through to stream buffer +inline gzofstream& +setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) +{ + (gzs.rdbuf())->setcompression(l, s); + return gzs; +} + +// Manipulator constructor stores arguments +template + inline + gzomanip2::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), + T1 v1, + T2 v2) + : func(f), val1(v1), val2(v2) + { } + +// Insertor applies underlying manipulator function to stream +template + inline gzofstream& + operator<<(gzofstream& s, const gzomanip2& m) + { return (*m.func)(s, m.val1, m.val2); } + +// Insert this onto stream to simplify setting of compression level +inline gzomanip2 +setcompression(int l, int s = Z_DEFAULT_STRATEGY) +{ return gzomanip2(&setcompression, l, s); } + +#endif // ZFSTREAM_H diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/bld_ml64.bat b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/bld_ml64.bat new file mode 100644 index 00000000..f74bcef5 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/bld_ml64.bat @@ -0,0 +1,2 @@ +ml64.exe /Flinffasx64 /c /Zi inffasx64.asm +ml64.exe /Flgvmat64 /c /Zi gvmat64.asm diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/gvmat64.asm b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/gvmat64.asm new file mode 100644 index 00000000..c1817f1b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/gvmat64.asm @@ -0,0 +1,553 @@ +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); /* current match */ + +; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86_64 +; (AMD64 on Athlon 64, Opteron, Phenom +; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) +; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software +; 3. This notice may not be removed or altered from any source distribution. +; +; +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for infozip Zip, I use option: +; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm +; +; to compile this file for zLib, I use option: +; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm +; Be carrefull to adapt zlib1222add below to your version of zLib +; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change +; value of zlib1222add later) +; +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK +; +; (you can get Windows WDK with ml64 for AMD64 from +; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) +; + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ +.code +longest_match PROC + + +;LocalVarsSize equ 88 + LocalVarsSize equ 72 + +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp + + chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len + ; low word: s->wmask +;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10 +;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11 +;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w +;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx +;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13 +;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d +;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9 +IFDEF INFOZIP +ELSE + nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size +ENDIF + +save_rdi equ rsp + 24 - LocalVarsSize +save_rsi equ rsp + 32 - LocalVarsSize +save_rbx equ rsp + 40 - LocalVarsSize +save_rbp equ rsp + 48 - LocalVarsSize +save_r12 equ rsp + 56 - LocalVarsSize +save_r13 equ rsp + 64 - LocalVarsSize +;save_r14 equ rsp + 72 - LocalVarsSize +;save_r15 equ rsp + 80 - LocalVarsSize + + +; summary of register usage +; scanend ebx +; scanendw bx +; chainlenwmask edx +; curmatch rsi +; curmatchd esi +; windowbestlen r8 +; scanalign r9 +; scanalignd r9d +; window r10 +; bestlen r11 +; bestlend r11d +; scanstart r12d +; scanstartw r12w +; scan r13 +; nicematch r14d +; limit r15 +; limitd r15d +; prev rcx + +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure + + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + + +IFDEF INFOZIP + +_DATA SEGMENT +COMM window_size:DWORD +; WMask ; 7fff +COMM window:BYTE:010040H +COMM prev:WORD:08000H +; MatchLen : unused +; PrevMatch : unused +COMM strstart:DWORD +COMM match_start:DWORD +; Lookahead : ignore +COMM prev_length:DWORD ; PrevLen +COMM max_chain_length:DWORD +COMM good_match:DWORD +COMM nice_match:DWORD +prev_ad equ OFFSET prev +window_ad equ OFFSET window +nicematch equ nice_match +_DATA ENDS +WMask equ 07fffh + +ELSE + + IFNDEF zlib1222add + zlib1222add equ 8 + ENDIF +dsWSize equ 56+zlib1222add+(zlib1222add/2) +dsWMask equ 64+zlib1222add+(zlib1222add/2) +dsWindow equ 72+zlib1222add +dsPrev equ 88+zlib1222add +dsMatchLen equ 128+zlib1222add +dsPrevMatch equ 132+zlib1222add +dsStrStart equ 140+zlib1222add +dsMatchStart equ 144+zlib1222add +dsLookahead equ 148+zlib1222add +dsPrevLen equ 152+zlib1222add +dsMaxChainLen equ 156+zlib1222add +dsGoodMatch equ 172+zlib1222add +dsNiceMatch equ 176+zlib1222add + +window_size equ [ rcx + dsWSize] +WMask equ [ rcx + dsWMask] +window_ad equ [ rcx + dsWindow] +prev_ad equ [ rcx + dsPrev] +strstart equ [ rcx + dsStrStart] +match_start equ [ rcx + dsMatchStart] +Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip +prev_length equ [ rcx + dsPrevLen] +max_chain_length equ [ rcx + dsMaxChainLen] +good_match equ [ rcx + dsGoodMatch] +nice_match equ [ rcx + dsNiceMatch] +ENDIF + +; parameter 1 in r8(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + + + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) + +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx + + mov [save_rdi],rdi + mov [save_rsi],rsi + mov [save_rbx],rbx + mov [save_rbp],rbp +IFDEF INFOZIP + mov r8d,ecx +ELSE + mov r8d,edx +ENDIF + mov [save_r12],r12 + mov [save_r13],r13 +; mov [save_r14],r14 +; mov [save_r15],r15 + + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +;;; on zlib only +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + +IFDEF INFOZIP + mov [chainlenwmask], ebx +; on infozip nice_match = [nice_match] +ELSE + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d +ENDIF + +;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; +IFDEF INFOZIP + mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1)) +ELSE + mov eax, window_size + sub eax, MIN_LOOKAHEAD +ENDIF + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +;;; int best_len = s->prev_length; + + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx r12d,word ptr [r9] + movzx ebx, word ptr [r9 + r11 - 1] + + mov rdi, prev_ad + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop1: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry1: + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop2: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry2: + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop4: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry4: + + cmp bx,word ptr [rsi + r8 - 1] + jnz LookupLoop1 + jmp LookupLoopIsZero + + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry: + + cmp bx,word ptr [rsi + r8 - 1] + jnz LookupLoop1 +LookupLoopIsZero: + cmp r12w, word ptr [r10 + r8] + jnz LookupLoop1 + + +;;; Store the current value of chainlen. + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + lea rsi,[r8+r10] + mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + jnz short LoopCmps + jmp short LenMaximum +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0000FFFFh + jnz LenLower + + test eax,0ffffffffh + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + jnz LenLower + +LenLower32: + shr eax,16 + add rdx,2 +LenLower: sub al, 1 + adc rdx, 0 +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// + + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + jge LeaveNow + + lea rsi,[r10+rax] + + movzx ebx, word ptr [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: +IFDEF INFOZIP + mov eax,r11d +ELSE + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d +ENDIF + +;;; Restore the stack and return from whence we came. + + + mov rsi,[save_rsi] + mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] +; mov r14,[save_r14] +; mov r15,[save_r15] + + + ret 0 +; please don't remove this string ! +; Your can freely use gvmat64 in any free or commercial app +; but it is far better don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 +longest_match ENDP + +match_init PROC + ret 0 +match_init ENDP + + +END diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/inffas8664.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/inffas8664.c new file mode 100644 index 00000000..aa861a33 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/inffas8664.c @@ -0,0 +1,186 @@ +/* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding + * version for AMD64 on Windows using Microsoft C compiler + * + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant + * + * inffas8664.c call function inffas8664fnc in inffasx64.asm + * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + * + */ + +#include +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ + + + + typedef struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } type_ar; +#ifdef ASMINF + +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + type_ar ar; + void inffas8664fnc(struct inffast_ar * par); + + + +#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64)) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->wnext; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + + inffas8664fnc(&ar); + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = (unsigned long)ar.hold; + state->bits = ar.bits; + return; +} + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/inffasx64.asm b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/inffasx64.asm new file mode 100644 index 00000000..41ec8239 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/inffasx64.asm @@ -0,0 +1,396 @@ +; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding +; version for AMD64 on Windows using Microsoft C compiler +; +; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c +; inffasx64.asm is called by inffas8664.c, which contain more info. + + +; to compile this file, I use option +; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm +; with Microsoft Macro Assembler (x64) for AMD64 +; + +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK +; +; (you can get Windows WDK with ml64 for AMD64 from +; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) +; + + +.code +inffas8664fnc PROC + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch. + + + mov [rsp-8],rsi + mov [rsp-16],rdi + mov [rsp-24],r12 + mov [rsp-32],r13 + mov [rsp-40],r14 + mov [rsp-48],r15 + mov [rsp-56],rbx + + mov rax,rcx + + mov [rax+8], rbp ; /* save regs rbp and rsp */ + mov [rax], rsp + + mov rsp, rax ; /* make rsp point to &ar */ + + mov rsi, [rsp+16] ; /* rsi = in */ + mov rdi, [rsp+32] ; /* rdi = out */ + mov r9, [rsp+24] ; /* r9 = last */ + mov r10, [rsp+48] ; /* r10 = end */ + mov rbp, [rsp+64] ; /* rbp = lcode */ + mov r11, [rsp+72] ; /* r11 = dcode */ + mov rdx, [rsp+80] ; /* rdx = hold */ + mov ebx, [rsp+88] ; /* ebx = bits */ + mov r12d, [rsp+100] ; /* r12d = lmask */ + mov r13d, [rsp+104] ; /* r13d = dmask */ + ; /* r14d = len */ + ; /* r15d = dist */ + + + cld + cmp r10, rdi + je L_one_time ; /* if only one decode left */ + cmp r9, rsi + + jne L_do_loop + + +L_one_time: + mov r8, r12 ; /* r8 = lmask */ + cmp bl, 32 + ja L_get_length_code_one_time + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + jmp L_get_length_code_one_time + +ALIGN 4 +L_while_test: + cmp r10, rdi + jbe L_break_loop + cmp r9, rsi + jbe L_break_loop + +L_do_loop: + mov r8, r12 ; /* r8 = lmask */ + cmp bl, 32 + ja L_get_length_code ; /* if (32 < bits) */ + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + +L_get_length_code: + and r8, rdx ; /* r8 &= hold */ + mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ + + mov cl, ah ; /* cl = this.bits */ + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ + + mov r8, r12 ; /* r8 = lmask */ + shr eax, 16 ; /* output this.val char */ + stosb + +L_get_length_code_one_time: + and r8, rdx ; /* r8 &= hold */ + mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah ; /* cl = this.bits */ + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ + + shr eax, 16 ; /* output this.val char */ + stosb + jmp L_while_test + +ALIGN 4 +L_test_for_length_base: + mov r14d, eax ; /* len = this */ + shr r14d, 16 ; /* len = this.val */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */ + and cl, 15 ; /* op &= 15 */ + jz L_decode_distance ; /* if (!op) */ + +L_add_bits_to_len: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + shr rdx, cl + add r14d, eax ; /* len += hold & mask[op] */ + +L_decode_distance: + mov r8, r13 ; /* r8 = dmask */ + cmp bl, 32 + ja L_get_distance_code ; /* if (32 < bits) */ + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + +L_get_distance_code: + and r8, rdx ; /* r8 &= hold */ + mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */ + +L_dodist: + mov r15d, eax ; /* dist = this */ + shr r15d, 16 ; /* dist = this.val */ + mov cl, ah + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + mov cl, al ; /* cl = this.op */ + + test al, 16 ; /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 ; /* op &= 15 */ + jz L_check_dist_one + +L_add_bits_to_dist: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax ; /* (1 << op) - 1 */ + and eax, edx ; /* eax &= hold */ + shr rdx, cl + add r15d, eax ; /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov r8, rsi ; /* save in so from can use it's reg */ + mov rax, rdi + sub rax, [rsp+40] ; /* nbytes = out - beg */ + + cmp eax, r15d + jb L_clip_window ; /* if (dist > nbytes) 4.2% */ + + mov ecx, r14d ; /* ecx = len */ + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + + sar ecx, 1 + jnc L_copy_two ; /* if len % 2 == 0 */ + + rep movsw + mov al, [rsi] + mov [rdi], al + inc rdi + + mov rsi, r8 ; /* move in back to %rsi, toss from */ + jmp L_while_test + +L_copy_two: + rep movsw + mov rsi, r8 ; /* move in back to %rsi, toss from */ + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp r15d, 1 ; /* if dist 1, is a memset */ + jne L_check_window + cmp [rsp+40], rdi ; /* if out == beg, outside window */ + je L_check_window + + mov ecx, r14d ; /* ecx = len */ + mov al, [rdi-1] + mov ah, al + + sar ecx, 1 + jnc L_set_two + mov [rdi], al + inc rdi + +L_set_two: + rep stosw + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + add eax, r14d ; /* eax += len */ + mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + add eax, r15d ; /* eax += dist */ + mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +ALIGN 4 +L_clip_window: + mov ecx, eax ; /* ecx = nbytes */ + mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */ + neg ecx ; /* nbytes = -nbytes */ + + cmp eax, r15d + jb L_invalid_distance_too_far ; /* if (dist > wsize) */ + + add ecx, r15d ; /* nbytes = dist - nbytes */ + cmp dword ptr [rsp+96], 0 + jne L_wrap_around_window ; /* if (write != 0) */ + + mov rsi, [rsp+56] ; /* from = window */ + sub eax, ecx ; /* eax -= nbytes */ + add rsi, rax ; /* from += wsize - nbytes */ + + mov eax, r14d ; /* eax = len */ + cmp r14d, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* eax -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = &out[ -dist ] */ + jmp L_do_copy + +ALIGN 4 +L_wrap_around_window: + mov eax, [rsp+96] ; /* eax = write */ + cmp ecx, eax + jbe L_contiguous_in_window ; /* if (write >= nbytes) */ + + mov esi, [rsp+92] ; /* from = wsize */ + add rsi, [rsp+56] ; /* from += window */ + add rsi, rax ; /* from += write */ + sub rsi, rcx ; /* from -= nbytes */ + sub ecx, eax ; /* nbytes -= write */ + + mov eax, r14d ; /* eax = len */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, [rsp+56] ; /* from = window */ + mov ecx, [rsp+96] ; /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_contiguous_in_window: + mov rsi, [rsp+56] ; /* rsi = window */ + add rsi, rax + sub rsi, rcx ; /* from += write - nbytes */ + + mov eax, r14d ; /* eax = len */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + jmp L_do_copy ; /* if (nbytes >= len) */ + +ALIGN 4 +L_do_copy: + mov ecx, eax ; /* ecx = len */ + rep movsb + + mov rsi, r8 ; /* move in back to %esi, toss from */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [rsp+116], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [rsp+116], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [rsp+116], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov dword ptr [rsp+116], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [rsp+116], 0 + +L_break_loop_with_status: +; /* put in, out, bits, and hold back into ar and pop esp */ + mov [rsp+16], rsi ; /* in */ + mov [rsp+32], rdi ; /* out */ + mov [rsp+88], ebx ; /* bits */ + mov [rsp+80], rdx ; /* hold */ + + mov rax, [rsp] ; /* restore rbp and rsp */ + mov rbp, [rsp+8] + mov rsp, rax + + + + mov rsi,[rsp-8] + mov rdi,[rsp-16] + mov r12,[rsp-24] + mov r13,[rsp-32] + mov r14,[rsp-40] + mov r15,[rsp-48] + mov rbx,[rsp-56] + + ret 0 +; : +; : "m" (ar) +; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", +; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +; ); + +inffas8664fnc ENDP +;_TEXT ENDS +END diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/readme.txt new file mode 100644 index 00000000..652571c7 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx64/readme.txt @@ -0,0 +1,31 @@ +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t), +for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits. + +gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits + assembly optimized version from Jean-loup Gailly original longest_match function + +inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing + original function from Mark Adler + +Use instructions +---------------- +Assemble the .asm files using MASM and put the object files into the zlib source +directory. You can also get object files here: + + http://www.winimage.com/zLibDll/zlib124_masm_obj.zip + +define ASMV and ASMINF in your project. Include inffas8664.c in your source tree, +and inffasx64.obj and gvmat64.obj as object to link. + + +Build instructions +------------------ +run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe) + +ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK + +You can get Windows 2003 server DDK with ml64 and cl for AMD64 from + http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/bld_ml32.bat b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/bld_ml32.bat new file mode 100644 index 00000000..fcf5755e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/bld_ml32.bat @@ -0,0 +1,2 @@ +ml /coff /Zi /c /Flmatch686.lst match686.asm +ml /coff /Zi /c /Flinffas32.lst inffas32.asm diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/inffas32.asm b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/inffas32.asm new file mode 100644 index 00000000..14f9d351 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/inffas32.asm @@ -0,0 +1,1083 @@ +;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding +; * +; * inffas32.asm is derivated from inffas86.c, with translation of assembly code +; * +; * Copyright (C) 1995-2003 Mark Adler +; * For conditions of distribution and use, see copyright notice in zlib.h +; * +; * Copyright (C) 2003 Chris Anderson +; * Please use the copyright conditions above. +; * +; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from +; * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at +; * the moment. I have successfully compiled and tested this code with gcc2.96, +; * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S +; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX +; * enabled. I will attempt to merge the MMX code into this version. Newer +; * versions of this and inffast.S can be found at +; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ +; * +; * 2005 : modification by Gilles Vollant +; */ +; For Visual C++ 4.x and higher and ML 6.x and higher +; ml.exe is in directory \MASM611C of Win95 DDK +; ml.exe is also distributed in http://www.masm32.com/masmdl.htm +; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/ +; +; +; compile with command line option +; ml /coff /Zi /c /Flinffas32.lst inffas32.asm + +; if you define NO_GZIP (see inflate.h), compile with +; ml /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm + + +; zlib122sup is 0 fort zlib 1.2.2.1 and lower +; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head +; in inflate_state in inflate.h) +zlib1222sup equ 8 + + +IFDEF GUNZIP + INFLATE_MODE_TYPE equ 11 + INFLATE_MODE_BAD equ 26 +ELSE + IFNDEF NO_GUNZIP + INFLATE_MODE_TYPE equ 11 + INFLATE_MODE_BAD equ 26 + ELSE + INFLATE_MODE_TYPE equ 3 + INFLATE_MODE_BAD equ 17 + ENDIF +ENDIF + + +; 75 "inffast.S" +;FILE "inffast.S" + +;;;GLOBAL _inflate_fast + +;;;SECTION .text + + + + .586p + .mmx + + name inflate_fast_x86 + .MODEL FLAT + +_DATA segment +inflate_fast_use_mmx: + dd 1 + + +_TEXT segment +PUBLIC _inflate_fast + +ALIGN 4 +_inflate_fast: + jmp inflate_fast_entry + + + +ALIGN 4 + db 'Fast decoding Code from Chris Anderson' + db 0 + +ALIGN 4 +invalid_literal_length_code_msg: + db 'invalid literal/length code' + db 0 + +ALIGN 4 +invalid_distance_code_msg: + db 'invalid distance code' + db 0 + +ALIGN 4 +invalid_distance_too_far_msg: + db 'invalid distance too far back' + db 0 + + +ALIGN 4 +inflate_fast_mask: +dd 0 +dd 1 +dd 3 +dd 7 +dd 15 +dd 31 +dd 63 +dd 127 +dd 255 +dd 511 +dd 1023 +dd 2047 +dd 4095 +dd 8191 +dd 16383 +dd 32767 +dd 65535 +dd 131071 +dd 262143 +dd 524287 +dd 1048575 +dd 2097151 +dd 4194303 +dd 8388607 +dd 16777215 +dd 33554431 +dd 67108863 +dd 134217727 +dd 268435455 +dd 536870911 +dd 1073741823 +dd 2147483647 +dd 4294967295 + + +mode_state equ 0 ;/* state->mode */ +wsize_state equ (32+zlib1222sup) ;/* state->wsize */ +write_state equ (36+4+zlib1222sup) ;/* state->write */ +window_state equ (40+4+zlib1222sup) ;/* state->window */ +hold_state equ (44+4+zlib1222sup) ;/* state->hold */ +bits_state equ (48+4+zlib1222sup) ;/* state->bits */ +lencode_state equ (64+4+zlib1222sup) ;/* state->lencode */ +distcode_state equ (68+4+zlib1222sup) ;/* state->distcode */ +lenbits_state equ (72+4+zlib1222sup) ;/* state->lenbits */ +distbits_state equ (76+4+zlib1222sup) ;/* state->distbits */ + + +;;SECTION .text +; 205 "inffast.S" +;GLOBAL inflate_fast_use_mmx + +;SECTION .data + + +; GLOBAL inflate_fast_use_mmx:object +;.size inflate_fast_use_mmx, 4 +; 226 "inffast.S" +;SECTION .text + +ALIGN 4 +inflate_fast_entry: + push edi + push esi + push ebp + push ebx + pushfd + sub esp,64 + cld + + + + + mov esi, [esp+88] + mov edi, [esi+28] + + + + + + + + mov edx, [esi+4] + mov eax, [esi+0] + + add edx,eax + sub edx,11 + + mov [esp+44],eax + mov [esp+20],edx + + mov ebp, [esp+92] + mov ecx, [esi+16] + mov ebx, [esi+12] + + sub ebp,ecx + neg ebp + add ebp,ebx + + sub ecx,257 + add ecx,ebx + + mov [esp+60],ebx + mov [esp+40],ebp + mov [esp+16],ecx +; 285 "inffast.S" + mov eax, [edi+lencode_state] + mov ecx, [edi+distcode_state] + + mov [esp+8],eax + mov [esp+12],ecx + + mov eax,1 + mov ecx, [edi+lenbits_state] + shl eax,cl + dec eax + mov [esp+0],eax + + mov eax,1 + mov ecx, [edi+distbits_state] + shl eax,cl + dec eax + mov [esp+4],eax + + mov eax, [edi+wsize_state] + mov ecx, [edi+write_state] + mov edx, [edi+window_state] + + mov [esp+52],eax + mov [esp+48],ecx + mov [esp+56],edx + + mov ebp, [edi+hold_state] + mov ebx, [edi+bits_state] +; 321 "inffast.S" + mov esi, [esp+44] + mov ecx, [esp+20] + cmp ecx,esi + ja L_align_long + + add ecx,11 + sub ecx,esi + mov eax,12 + sub eax,ecx + lea edi, [esp+28] + rep movsb + mov ecx,eax + xor eax,eax + rep stosb + lea esi, [esp+28] + mov [esp+20],esi + jmp L_is_aligned + + +L_align_long: + test esi,3 + jz L_is_aligned + xor eax,eax + mov al, [esi] + inc esi + mov ecx,ebx + add ebx,8 + shl eax,cl + or ebp,eax + jmp L_align_long + +L_is_aligned: + mov edi, [esp+60] +; 366 "inffast.S" +L_check_mmx: + cmp dword ptr [inflate_fast_use_mmx],2 + je L_init_mmx + ja L_do_loop + + push eax + push ebx + push ecx + push edx + pushfd + mov eax, [esp] + xor dword ptr [esp],0200000h + + + + + popfd + pushfd + pop edx + xor edx,eax + jz L_dont_use_mmx + xor eax,eax + cpuid + cmp ebx,0756e6547h + jne L_dont_use_mmx + cmp ecx,06c65746eh + jne L_dont_use_mmx + cmp edx,049656e69h + jne L_dont_use_mmx + mov eax,1 + cpuid + shr eax,8 + and eax,15 + cmp eax,6 + jne L_dont_use_mmx + test edx,0800000h + jnz L_use_mmx + jmp L_dont_use_mmx +L_use_mmx: + mov dword ptr [inflate_fast_use_mmx],2 + jmp L_check_mmx_pop +L_dont_use_mmx: + mov dword ptr [inflate_fast_use_mmx],3 +L_check_mmx_pop: + pop edx + pop ecx + pop ebx + pop eax + jmp L_check_mmx +; 426 "inffast.S" +ALIGN 4 +L_do_loop: +; 437 "inffast.S" + cmp bl,15 + ja L_get_length_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_length_code: + mov edx, [esp+0] + mov ecx, [esp+8] + and edx,ebp + mov eax, [ecx+edx*4] + +L_dolen: + + + + + + + mov cl,ah + sub bl,ah + shr ebp,cl + + + + + + + test al,al + jnz L_test_for_length_base + + shr eax,16 + stosb + +L_while_test: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop + jmp L_break_loop + +L_test_for_length_base: +; 502 "inffast.S" + mov edx,eax + shr edx,16 + mov cl,al + + test al,16 + jz L_test_for_second_level_length + and cl,15 + jz L_save_len + cmp bl,cl + jae L_add_bits_to_len + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_len: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + +L_save_len: + mov [esp+24],edx + + +L_decode_distance: +; 549 "inffast.S" + cmp bl,15 + ja L_get_distance_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_distance_code: + mov edx, [esp+4] + mov ecx, [esp+12] + and edx,ebp + mov eax, [ecx+edx*4] + + +L_dodist: + mov edx,eax + shr edx,16 + mov cl,ah + sub bl,ah + shr ebp,cl +; 584 "inffast.S" + mov cl,al + + test al,16 + jz L_test_for_second_level_dist + and cl,15 + jz L_check_dist_one + cmp bl,cl + jae L_add_bits_to_dist + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_dist: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + jmp L_check_window + +L_check_window: +; 625 "inffast.S" + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,edx + jb L_clip_window + + mov ecx, [esp+24] + mov esi,edi + sub esi,edx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp edx,1 + jne L_check_window + cmp [esp+40],edi + je L_check_window + + dec edi + mov ecx, [esp+24] + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + + + + + test al,64 + jnz L_test_for_end_of_block + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+8] + mov eax, [edx+eax*4] + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + + + + + test al,64 + jnz L_invalid_distance_code + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+12] + mov eax, [edx+eax*4] + jmp L_dodist + +ALIGN 4 +L_clip_window: +; 721 "inffast.S" + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,edx + jb L_invalid_distance_too_far + + add ecx,edx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window + + sub eax,ecx + add esi,eax +; 749 "inffast.S" + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_wrap_around_window: +; 793 "inffast.S" + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_contiguous_in_window: +; 836 "inffast.S" + add esi,eax + sub esi,ecx + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + +L_do_copy1: +; 862 "inffast.S" + mov ecx,eax + rep movsb + + mov esi, [esp+44] + jmp L_while_test +; 878 "inffast.S" +ALIGN 4 +L_init_mmx: + emms + + + + + + movd mm0,ebp + mov ebp,ebx +; 896 "inffast.S" + movd mm4,dword ptr [esp+0] + movq mm3,mm4 + movd mm5,dword ptr [esp+4] + movq mm2,mm5 + pxor mm1,mm1 + mov ebx, [esp+8] + jmp L_do_loop_mmx + +ALIGN 4 +L_do_loop_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_length_code_mmx + + movd mm6,ebp + movd mm7,dword ptr [esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_length_code_mmx: + pand mm4,mm0 + movd eax,mm4 + movq mm4,mm3 + mov eax, [ebx+eax*4] + +L_dolen_mmx: + movzx ecx,ah + movd mm1,ecx + sub ebp,ecx + + test al,al + jnz L_test_for_length_base_mmx + + shr eax,16 + stosb + +L_while_test_mmx: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop_mmx + jmp L_break_loop + +L_test_for_length_base_mmx: + + mov edx,eax + shr edx,16 + + test al,16 + jz L_test_for_second_level_length_mmx + and eax,15 + jz L_decode_distance_mmx + + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add edx,ecx + +L_decode_distance_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_dist_code_mmx + + movd mm6,ebp + movd mm7,dword ptr [esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_dist_code_mmx: + mov ebx, [esp+12] + pand mm5,mm0 + movd eax,mm5 + movq mm5,mm2 + mov eax, [ebx+eax*4] + +L_dodist_mmx: + + movzx ecx,ah + mov ebx,eax + shr ebx,16 + sub ebp,ecx + movd mm1,ecx + + test al,16 + jz L_test_for_second_level_dist_mmx + and eax,15 + jz L_check_dist_one_mmx + +L_add_bits_to_dist_mmx: + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add ebx,ecx + +L_check_window_mmx: + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,ebx + jb L_clip_window_mmx + + mov ecx,edx + mov esi,edi + sub esi,ebx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_check_dist_one_mmx: + cmp ebx,1 + jne L_check_window_mmx + cmp [esp+40],edi + je L_check_window_mmx + + dec edi + mov ecx,edx + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_test_for_second_level_length_mmx: + test al,64 + jnz L_test_for_end_of_block + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + add ecx,edx + mov eax, [ebx+ecx*4] + jmp L_dolen_mmx + +ALIGN 4 +L_test_for_second_level_dist_mmx: + test al,64 + jnz L_invalid_distance_code + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + mov eax, [esp+12] + add ecx,ebx + mov eax, [eax+ecx*4] + jmp L_dodist_mmx + +ALIGN 4 +L_clip_window_mmx: + + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,ebx + jb L_invalid_distance_too_far + + add ecx,ebx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window_mmx + + sub eax,ecx + add esi,eax + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_wrap_around_window_mmx: + + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window_mmx + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_contiguous_in_window_mmx: + + add esi,eax + sub esi,ecx + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + +L_do_copy1_mmx: + + + mov ecx,edx + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx +; 1174 "inffast.S" +L_invalid_distance_code: + + + + + + mov ecx, invalid_distance_code_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_test_for_end_of_block: + + + + + + test al,32 + jz L_invalid_literal_length_code + + mov ecx,0 + mov edx,INFLATE_MODE_TYPE + jmp L_update_stream_state + +L_invalid_literal_length_code: + + + + + + mov ecx, invalid_literal_length_code_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_invalid_distance_too_far: + + + + mov esi, [esp+44] + mov ecx, invalid_distance_too_far_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_update_stream_state: + + mov eax, [esp+88] + test ecx,ecx + jz L_skip_msg + mov [eax+24],ecx +L_skip_msg: + mov eax, [eax+28] + mov [eax+mode_state],edx + jmp L_break_loop + +ALIGN 4 +L_break_loop: +; 1243 "inffast.S" + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_next_in + + + + mov ebx,ebp + +L_update_next_in: +; 1266 "inffast.S" + mov eax, [esp+88] + mov ecx,ebx + mov edx, [eax+28] + shr ecx,3 + sub esi,ecx + shl ecx,3 + sub ebx,ecx + mov [eax+12],edi + mov [edx+bits_state],ebx + mov ecx,ebx + + lea ebx, [esp+28] + cmp [esp+20],ebx + jne L_buf_not_used + + sub esi,ebx + mov ebx, [eax+0] + mov [esp+20],ebx + add esi,ebx + mov ebx, [eax+4] + sub ebx,11 + add [esp+20],ebx + +L_buf_not_used: + mov [eax+0],esi + + mov ebx,1 + shl ebx,cl + dec ebx + + + + + + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_hold + + + + psrlq mm0,mm1 + movd ebp,mm0 + + emms + +L_update_hold: + + + + and ebp,ebx + mov [edx+hold_state],ebp + + + + + mov ebx, [esp+20] + cmp ebx,esi + jbe L_last_is_smaller + + sub ebx,esi + add ebx,11 + mov [eax+4],ebx + jmp L_fixup_out +L_last_is_smaller: + sub esi,ebx + neg esi + add esi,11 + mov [eax+4],esi + + + + +L_fixup_out: + + mov ebx, [esp+16] + cmp ebx,edi + jbe L_end_is_smaller + + sub ebx,edi + add ebx,257 + mov [eax+16],ebx + jmp L_done +L_end_is_smaller: + sub edi,ebx + neg edi + add edi,257 + mov [eax+16],edi + + + + + +L_done: + add esp,64 + popfd + pop ebx + pop ebp + pop esi + pop edi + ret + +_TEXT ends +end diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/match686.asm b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/match686.asm new file mode 100644 index 00000000..1eaf5550 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/match686.asm @@ -0,0 +1,478 @@ +; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86 +; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; File written by Gilles Vollant, by converting match686.S from Brian Raiter +; for MASM. This is as assembly version of longest_match +; from Jean-loup Gailly in deflate.c +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; For Visual C++ 4.x and higher and ML 6.x and higher +; ml.exe is distributed in +; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 +; +; this file contain two implementation of longest_match +; +; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro +; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom) +; +; for using an assembly version of longest_match, you need define ASMV in project +; +; compile the asm file running +; ml /coff /Zi /c /Flmatch686.lst match686.asm +; and do not include match686.obj in your project +; +; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for +; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor +; with autoselect (with cpu detection code) +; if you want support the old pentium optimization, you can still use these version +; +; this file is not optimized for old pentium, but it compatible with all x86 32 bits +; processor (starting 80386) +; +; +; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2 + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ + + NbStack equ 76 + cur_match equ dword ptr[esp+NbStack-0] + str_s equ dword ptr[esp+NbStack-4] +; 5 dword on top (ret,ebp,esi,edi,ebx) + adrret equ dword ptr[esp+NbStack-8] + pushebp equ dword ptr[esp+NbStack-12] + pushedi equ dword ptr[esp+NbStack-16] + pushesi equ dword ptr[esp+NbStack-20] + pushebx equ dword ptr[esp+NbStack-24] + + chain_length equ dword ptr [esp+NbStack-28] + limit equ dword ptr [esp+NbStack-32] + best_len equ dword ptr [esp+NbStack-36] + window equ dword ptr [esp+NbStack-40] + prev equ dword ptr [esp+NbStack-44] + scan_start equ word ptr [esp+NbStack-48] + wmask equ dword ptr [esp+NbStack-52] + match_start_ptr equ dword ptr [esp+NbStack-56] + nice_match equ dword ptr [esp+NbStack-60] + scan equ dword ptr [esp+NbStack-64] + + windowlen equ dword ptr [esp+NbStack-68] + match_start equ dword ptr [esp+NbStack-72] + strend equ dword ptr [esp+NbStack-76] + NbStackAdd equ (NbStack-24) + + .386p + + name gvmatch + .MODEL FLAT + + + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + + zlib1222add equ 8 + +; Note : these value are good with a 8 bytes boundary pack structure + dep_chain_length equ 74h+zlib1222add + dep_window equ 30h+zlib1222add + dep_strstart equ 64h+zlib1222add + dep_prev_length equ 70h+zlib1222add + dep_nice_match equ 88h+zlib1222add + dep_w_size equ 24h+zlib1222add + dep_prev equ 38h+zlib1222add + dep_w_mask equ 2ch+zlib1222add + dep_good_match equ 84h+zlib1222add + dep_match_start equ 68h+zlib1222add + dep_lookahead equ 6ch+zlib1222add + + +_TEXT segment + +IFDEF NOUNDERLINE + public longest_match + public match_init +ELSE + public _longest_match + public _match_init +ENDIF + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + + +MAX_MATCH equ 258 +MIN_MATCH equ 3 +MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1) +MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h) + + +;;; stack frame offsets + +chainlenwmask equ esp + 0 ; high word: current chain len + ; low word: s->wmask +window equ esp + 4 ; local copy of s->window +windowbestlen equ esp + 8 ; s->window + bestlen +scanstart equ esp + 16 ; first two bytes of string +scanend equ esp + 12 ; last two bytes of string +scanalign equ esp + 20 ; dword-misalignment of string +nicematch equ esp + 24 ; a good enough match size +bestlen equ esp + 28 ; size of best match so far +scan equ esp + 32 ; ptr to string wanting match + +LocalVarsSize equ 36 +; saved ebx byte esp + 36 +; saved edi byte esp + 40 +; saved esi byte esp + 44 +; saved ebp byte esp + 48 +; return address byte esp + 52 +deflatestate equ esp + 56 ; the function arguments +curmatch equ esp + 60 + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +dsWSize equ 36+zlib1222add +dsWMask equ 44+zlib1222add +dsWindow equ 48+zlib1222add +dsPrev equ 56+zlib1222add +dsMatchLen equ 88+zlib1222add +dsPrevMatch equ 92+zlib1222add +dsStrStart equ 100+zlib1222add +dsMatchStart equ 104+zlib1222add +dsLookahead equ 108+zlib1222add +dsPrevLen equ 112+zlib1222add +dsMaxChainLen equ 116+zlib1222add +dsGoodMatch equ 132+zlib1222add +dsNiceMatch equ 136+zlib1222add + + +;;; match686.asm -- Pentium-Pro-optimized version of longest_match() +;;; Written for zlib 1.1.2 +;;; Copyright (C) 1998 Brian Raiter +;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html +;;; +;; +;; This software is provided 'as-is', without any express or implied +;; warranty. In no event will the authors be held liable for any damages +;; arising from the use of this software. +;; +;; Permission is granted to anyone to use this software for any purpose, +;; including commercial applications, and to alter it and redistribute it +;; freely, subject to the following restrictions: +;; +;; 1. The origin of this software must not be misrepresented; you must not +;; claim that you wrote the original software. If you use this software +;; in a product, an acknowledgment in the product documentation would be +;; appreciated but is not required. +;; 2. Altered source versions must be plainly marked as such, and must not be +;; misrepresented as being the original software +;; 3. This notice may not be removed or altered from any source distribution. +;; + +;GLOBAL _longest_match, _match_init + + +;SECTION .text + +;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch) + +;_longest_match: + IFDEF NOUNDERLINE + longest_match proc near + ELSE + _longest_match proc near + ENDIF + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + push ebp + push edi + push esi + push ebx + sub esp, LocalVarsSize + +;;; Retrieve the function arguments. ecx will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + + mov edx, [deflatestate] + mov ecx, [curmatch] + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov eax, [edx + dsPrevLen] + mov ebx, [edx + dsGoodMatch] + cmp eax, ebx + mov eax, [edx + dsWMask] + mov ebx, [edx + dsMaxChainLen] + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + mov [chainlenwmask], ebx + +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + mov eax, [edx + dsNiceMatch] + mov ebx, [edx + dsLookahead] + cmp ebx, eax + jl LookaheadLess + mov ebx, eax +LookaheadLess: mov [nicematch], ebx + +;;; register Bytef *scan = s->window + s->strstart; + + mov esi, [edx + dsWindow] + mov [window], esi + mov ebp, [edx + dsStrStart] + lea edi, [esi + ebp] + mov [scan], edi + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov eax, edi + neg eax + and eax, 3 + mov [scanalign], eax + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + mov eax, [edx + dsWSize] + sub eax, MIN_LOOKAHEAD + sub ebp, eax + jg LimitPositive + xor ebp, ebp +LimitPositive: + +;;; int best_len = s->prev_length; + + mov eax, [edx + dsPrevLen] + mov [bestlen], eax + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + add esi, eax + mov [windowbestlen], esi + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx ebx, word ptr [edi] + mov [scanstart], ebx + movzx ebx, word ptr [edi + eax - 1] + mov [scanend], ebx + mov edi, [edx + dsPrev] + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + jmp short LoopEntry + +align 4 + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; ecx = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and ecx, edx + movzx ecx, word ptr [edi + ecx*2] + cmp ecx, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow +LoopEntry: movzx eax, word ptr [esi + ecx - 1] + cmp eax, ebx + jnz LookupLoop + mov eax, [window] + movzx eax, word ptr [eax + ecx] + cmp eax, [scanstart] + jnz LookupLoop + +;;; Store the current value of chainlen. + + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + mov esi, [window] + mov edi, [scan] + add esi, ecx + mov eax, [scanalign] + mov edx, 0fffffef8h; -(MAX_MATCH_8) + lea edi, [edi + eax + 0108h] ;MAX_MATCH_8] + lea esi, [esi + eax + 0108h] ;MAX_MATCH_8] + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust edx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (esi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + +LoopCmps: + mov eax, [esi + edx] + xor eax, [edi + edx] + jnz LeaveLoopCmps + mov eax, [esi + edx + 4] + xor eax, [edi + edx + 4] + jnz LeaveLoopCmps4 + add edx, 8 + jnz LoopCmps + jmp short LenMaximum +LeaveLoopCmps4: add edx, 4 +LeaveLoopCmps: test eax, 0000FFFFh + jnz LenLower + add edx, 2 + shr eax, 16 +LenLower: sub al, 1 + adc edx, 0 + +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea eax, [edi + edx] + mov edi, [scan] + sub eax, edi + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. + + mov edx, [deflatestate] + mov ebx, [bestlen] + cmp eax, ebx + jg LongerMatch + mov esi, [windowbestlen] + mov edi, [edx + dsPrev] + mov ebx, [scanend] + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: mov ebx, [nicematch] + mov [bestlen], eax + mov [edx + dsMatchStart], ecx + cmp eax, ebx + jge LeaveNow + mov esi, [window] + add esi, eax + mov [windowbestlen], esi + movzx ebx, word ptr [edi + eax - 1] + mov edi, [edx + dsPrev] + mov [scanend], ebx + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: mov edx, [deflatestate] + mov dword ptr [bestlen], MAX_MATCH + mov [edx + dsMatchStart], ecx + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: + mov edx, [deflatestate] + mov ebx, [bestlen] + mov eax, [edx + dsLookahead] + cmp ebx, eax + jg LookaheadRet + mov eax, ebx +LookaheadRet: + +;;; Restore the stack and return from whence we came. + + add esp, LocalVarsSize + pop ebx + pop esi + pop edi + pop ebp + + ret +; please don't remove this string ! +; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah + + + IFDEF NOUNDERLINE + longest_match endp + ELSE + _longest_match endp + ENDIF + + IFDEF NOUNDERLINE + match_init proc near + ret + match_init endp + ELSE + _match_init proc near + ret + _match_init endp + ENDIF + + +_TEXT ends +end diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/readme.txt new file mode 100644 index 00000000..3f888867 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/masmx86/readme.txt @@ -0,0 +1,27 @@ + +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(). + + +Use instructions +---------------- +Assemble using MASM, and copy the object files into the zlib source +directory, then run the appropriate makefile, as suggested below. You can +donwload MASM from here: + + http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 + +You can also get objects files here: + + http://www.winimage.com/zLibDll/zlib124_masm_obj.zip + +Build instructions +------------------ +* With Microsoft C and MASM: +nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" + +* With Borland C and TASM: +make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" OBJPA="+match686c.obj+match686.obj+inffas32.obj" + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/Makefile b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/Makefile new file mode 100644 index 00000000..84eaad20 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/Makefile @@ -0,0 +1,25 @@ +CC=cc +CFLAGS=-O -I../.. + +UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a +ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +all: miniunz minizip + +miniunz: $(UNZ_OBJS) + $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) + +minizip: $(ZIP_OBJS) + $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) + +test: miniunz minizip + ./minizip test readme.txt + ./miniunz -l test.zip + mv readme.txt readme.old + ./miniunz test.zip + +clean: + /bin/rm -f *.o *~ minizip miniunz diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/MiniZip64_Changes.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/MiniZip64_Changes.txt new file mode 100644 index 00000000..13a1bd91 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/MiniZip64_Changes.txt @@ -0,0 +1,6 @@ + +MiniZip 1.1 was derrived from MiniZip at version 1.01f + +Change in 1.0 (Okt 2009) + - **TODO - Add history** + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/MiniZip64_info.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/MiniZip64_info.txt new file mode 100644 index 00000000..57d71524 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/MiniZip64_info.txt @@ -0,0 +1,74 @@ +MiniZip - Copyright (c) 1998-2010 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson + +Introduction +--------------------- +MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( http://www.winimage.com/zLibDll/minizip.html ) + +When adding ZIP64 support into minizip it would result into risk of breaking compatibility with minizip 1.0. +All possible work was done for compatibility. + + +Background +--------------------- +When adding ZIP64 support Mathias Svensson found that Even Rouault have added ZIP64 +support for unzip.c into minizip for a open source project called gdal ( http://www.gdal.org/ ) + +That was used as a starting point. And after that ZIP64 support was added to zip.c +some refactoring and code cleanup was also done. + + +Changed from MiniZip 1.0 to MiniZip 1.1 +--------------------------------------- +* Added ZIP64 support for unzip ( by Even Rouault ) +* Added ZIP64 support for zip ( by Mathias Svensson ) +* Reverted some changed that Even Rouault did. +* Bunch of patches received from Gulles Vollant that he received for MiniZip from various users. +* Added unzip patch for BZIP Compression method (patch create by Daniel Borca) +* Added BZIP Compress method for zip +* Did some refactoring and code cleanup + + +Credits + + Gilles Vollant - Original MiniZip author + Even Rouault - ZIP64 unzip Support + Daniel Borca - BZip Compression method support in unzip + Mathias Svensson - ZIP64 zip support + Mathias Svensson - BZip Compression method support in zip + + Resources + + ZipLayout http://result42.com/projects/ZipFileLayout + Command line tool for Windows that shows the layout and information of the headers in a zip archive. + Used when debugging and validating the creation of zip files using MiniZip64 + + + ZIP App Note http://www.pkware.com/documents/casestudies/APPNOTE.TXT + Zip File specification + + +Notes. + * To be able to use BZip compression method in zip64.c or unzip64.c the BZIP2 lib is needed and HAVE_BZIP2 need to be defined. + +License +---------------------------------------------------------- + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +---------------------------------------------------------- + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/crypt.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/crypt.h new file mode 100644 index 00000000..a01d08d9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/ioapi.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/ioapi.c new file mode 100644 index 00000000..49958f61 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/ioapi.c @@ -0,0 +1,235 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if (defined(_WIN32)) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen64((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = ftello64((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/ioapi.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/ioapi.h new file mode 100644 index 00000000..8309c4cf --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/ioapi.h @@ -0,0 +1,200 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/iowin32.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/iowin32.c new file mode 100644 index 00000000..6a2a883b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/iowin32.c @@ -0,0 +1,389 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); +uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); +int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + + +static void win32_translate_open_mode(int mode, + DWORD* lpdwDesiredAccess, + DWORD* lpdwCreationDisposition, + DWORD* lpdwShareMode, + DWORD* lpdwFlagsAndAttributes) +{ + *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + *lpdwDesiredAccess = GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + *lpdwShareMode = FILE_SHARE_READ; + } + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + } + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = CREATE_ALWAYS; + } +} + +static voidpf win32_build_iowin(HANDLE hFile) +{ + voidpf ret=NULL; + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + + if (ret==NULL) + CloseHandle(hFile); + else + *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + +voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)dwSet; + } + return ret; +} + +ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret= (ZPOS64_T)-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + if (hFile) + { + LARGE_INTEGER li; + li.QuadPart = 0; + li.u.LowPart = SetFilePointer(hFile, li.u.LowPart, &li.u.HighPart, FILE_CURRENT); + if ( (li.LowPart == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = (ZPOS64_T)-1; + } + else + ret=li.QuadPart; + } + return ret; +} + + +long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + long ret=-1; + + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile) + { + LARGE_INTEGER* li = (LARGE_INTEGER*)&offset; + DWORD dwSet = SetFilePointer(hFile, li->u.LowPart, &li->u.HighPart, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/iowin32.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/iowin32.h new file mode 100644 index 00000000..0ca0969a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/make_vms.com b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/make_vms.com new file mode 100644 index 00000000..9ac13a98 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/make_vms.com @@ -0,0 +1,25 @@ +$ if f$search("ioapi.h_orig") .eqs. "" then copy ioapi.h ioapi.h_orig +$ open/write zdef vmsdefs.h +$ copy sys$input: zdef +$ deck +#define unix +#define fill_zlib_filefunc64_32_def_from_filefunc32 fillzffunc64from +#define Write_Zip64EndOfCentralDirectoryLocator Write_Zip64EoDLocator +#define Write_Zip64EndOfCentralDirectoryRecord Write_Zip64EoDRecord +#define Write_EndOfCentralDirectoryRecord Write_EoDRecord +$ eod +$ close zdef +$ copy vmsdefs.h,ioapi.h_orig ioapi.h +$ cc/include=[--]/prefix=all ioapi.c +$ cc/include=[--]/prefix=all miniunz.c +$ cc/include=[--]/prefix=all unzip.c +$ cc/include=[--]/prefix=all minizip.c +$ cc/include=[--]/prefix=all zip.c +$ link miniunz,unzip,ioapi,[--]libz.olb/lib +$ link minizip,zip,ioapi,[--]libz.olb/lib +$ mcr []minizip test minizip_info.txt +$ mcr []miniunz -l test.zip +$ rename minizip_info.txt; minizip_info.txt_old +$ mcr []miniunz test.zip +$ delete test.zip;* +$exit diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/miniunz.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/miniunz.c new file mode 100644 index 00000000..9ed009fb --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/miniunz.c @@ -0,0 +1,648 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#ifndef _WIN32 + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef _WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef _WIN32 + ret = _mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + /* to avoid compatibility problem , we do here the conversion */ + char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + printf(" "); + } + } + + printf("%s",&number[pos_string]); +} + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + Display64BitsSize(file_info.uncompressed_size,7); + printf(" %6s%c",string_method,charCrypt); + Display64BitsSize(file_info.compressed_size,7); + printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen64(write_filename,"wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen64(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef _WIN32 + #define USEWIN32IOAPI + #include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef _WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen64(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); + printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen64(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +} + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = fopen64(filename, "rb"); + + if(pFile != NULL) + { + int n = fseeko64(pFile, 0, SEEK_END); + + pos = ftello64(pFile); + + printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + /* The path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = fopen64(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/mztools.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/mztools.c new file mode 100644 index 00000000..f9092e65 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/mztools.c @@ -0,0 +1,281 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/mztools.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/mztools.h new file mode 100644 index 00000000..88b34592 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/unzip.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/unzip.c new file mode 100644 index 00000000..7617f41f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == (unsigned long)-1) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/unzip.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/unzip.h new file mode 100644 index 00000000..3183968b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/zip.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/zip.c new file mode 100644 index 00000000..3c34fc8b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/zip.c @@ -0,0 +1,2004 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/zip.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/zip.h new file mode 100644 index 00000000..8aaebb62 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/minizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/example.pas b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/example.pas new file mode 100644 index 00000000..5518b36a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/example.pas @@ -0,0 +1,599 @@ +(* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Pascal translation + * Copyright (C) 1998 by Jacques Nomssi Nzali. + * For conditions of distribution and use, see copyright notice in readme.txt + * + * Adaptation to the zlibpas interface + * Copyright (C) 2003 by Cosmin Truta. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +program example; + +{$DEFINE TEST_COMPRESS} +{DO NOT $DEFINE TEST_GZIO} +{$DEFINE TEST_DEFLATE} +{$DEFINE TEST_INFLATE} +{$DEFINE TEST_FLUSH} +{$DEFINE TEST_SYNC} +{$DEFINE TEST_DICT} + +uses SysUtils, zlibpas; + +const TESTFILE = 'foo.gz'; + +(* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + *) +const hello: PChar = 'hello, hello!'; + +const dictionary: PChar = 'hello'; + +var dictId: LongInt; (* Adler32 value of the dictionary *) + +procedure CHECK_ERR(err: Integer; msg: String); +begin + if err <> Z_OK then + begin + WriteLn(msg, ' error: ', err); + Halt(1); + end; +end; + +procedure EXIT_ERR(const msg: String); +begin + WriteLn('Error: ', msg); + Halt(1); +end; + +(* =========================================================================== + * Test compress and uncompress + *) +{$IFDEF TEST_COMPRESS} +procedure test_compress(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + err := compress(compr, comprLen, hello, len); + CHECK_ERR(err, 'compress'); + + StrCopy(PChar(uncompr), 'garbage'); + + err := uncompress(uncompr, uncomprLen, compr, comprLen); + CHECK_ERR(err, 'uncompress'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad uncompress') + else + WriteLn('uncompress(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test read/write of .gz files + *) +{$IFDEF TEST_GZIO} +procedure test_gzio(const fname: PChar; (* compressed file name *) + uncompr: Pointer; + uncomprLen: LongInt); +var err: Integer; + len: Integer; + zfile: gzFile; + pos: LongInt; +begin + len := StrLen(hello)+1; + + zfile := gzopen(fname, 'wb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + gzputc(zfile, 'h'); + if gzputs(zfile, 'ello') <> 4 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$IFDEF GZ_FORMAT_STRING} + if gzprintf(zfile, ', %s!', 'hello') <> 8 then + begin + WriteLn('gzprintf err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ELSE} + if gzputs(zfile, ', hello!') <> 8 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ENDIF} + gzseek(zfile, 1, SEEK_CUR); (* add one zero byte *) + gzclose(zfile); + + zfile := gzopen(fname, 'rb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + + StrCopy(PChar(uncompr), 'garbage'); + + if gzread(zfile, uncompr, uncomprLen) <> len then + begin + WriteLn('gzread err: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello) <> 0 then + begin + WriteLn('bad gzread: ', PChar(uncompr)); + Halt(1); + end + else + WriteLn('gzread(): ', PChar(uncompr)); + + pos := gzseek(zfile, -8, SEEK_CUR); + if (pos <> 6) or (gztell(zfile) <> pos) then + begin + WriteLn('gzseek error, pos=', pos, ', gztell=', gztell(zfile)); + Halt(1); + end; + + if gzgetc(zfile) <> ' ' then + begin + WriteLn('gzgetc error'); + Halt(1); + end; + + if gzungetc(' ', zfile) <> ' ' then + begin + WriteLn('gzungetc error'); + Halt(1); + end; + + gzgets(zfile, PChar(uncompr), uncomprLen); + uncomprLen := StrLen(PChar(uncompr)); + if uncomprLen <> 7 then (* " hello!" *) + begin + WriteLn('gzgets err after gzseek: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello + 6) <> 0 then + begin + WriteLn('bad gzgets after gzseek'); + Halt(1); + end + else + WriteLn('gzgets() after gzseek: ', PChar(uncompr)); + + gzclose(zfile); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with small buffers + *) +{$IFDEF TEST_DEFLATE} +procedure test_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + + while (c_stream.total_in <> len) and + (c_stream.total_out < comprLen) do + begin + c_stream.avail_out := 1; { force small buffers } + c_stream.avail_in := 1; + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + end; + + (* Finish the stream, still forcing small buffers: *) + while TRUE do + begin + c_stream.avail_out := 1; + err := deflate(c_stream, Z_FINISH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'deflate'); + end; + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with small buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_inflate(compr: Pointer; comprLen : LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 0; + d_stream.next_out := uncompr; + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while (d_stream.total_out < uncomprLen) and + (d_stream.total_in < comprLen) do + begin + d_stream.avail_out := 1; (* force small buffers *) + d_stream.avail_in := 1; + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate') + else + WriteLn('inflate(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with large buffers and dynamic change of compression level + *) +{$IFDEF TEST_DEFLATE} +procedure test_large_deflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_SPEED); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + (* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + *) + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + if c_stream.avail_in <> 0 then + EXIT_ERR('deflate not greedy'); + + (* Feed in already compressed data and switch to no compression: *) + deflateParams(c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in := compr; + c_stream.avail_in := Integer(comprLen div 2); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + (* Switch back to compressing mode: *) + deflateParams(c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with large buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_large_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while TRUE do + begin + d_stream.next_out := uncompr; (* discard the output *) + d_stream.avail_out := Integer(uncomprLen); + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'large inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if d_stream.total_out <> 2 * uncomprLen + comprLen div 2 then + begin + WriteLn('bad large inflate: ', d_stream.total_out); + Halt(1); + end + else + WriteLn('large_inflate(): OK'); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with full flush + *) +{$IFDEF TEST_FLUSH} +procedure test_flush(compr: Pointer; var comprLen : LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: Integer; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + c_stream.avail_in := 3; + c_stream.avail_out := Integer(comprLen); + err := deflate(c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, 'deflate'); + + Inc(PByteArray(compr)^[3]); (* force an error in first compressed block *) + c_stream.avail_in := len - 3; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + CHECK_ERR(err, 'deflate'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); + + comprLen := c_stream.total_out; +end; +{$ENDIF} + +(* =========================================================================== + * Test inflateSync() + *) +{$IFDEF TEST_SYNC} +procedure test_sync(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 2; (* just read the zlib header *) + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + inflate(d_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'inflate'); + + d_stream.avail_in := Integer(comprLen-2); (* read all compressed data *) + err := inflateSync(d_stream); (* but skip the damaged part *) + CHECK_ERR(err, 'inflateSync'); + + err := inflate(d_stream, Z_FINISH); + if err <> Z_DATA_ERROR then + EXIT_ERR('inflate should report DATA_ERROR'); + (* Because of incorrect adler32 *) + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + WriteLn('after inflateSync(): hel', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + err := deflateSetDictionary(c_stream, dictionary, StrLen(dictionary)); + CHECK_ERR(err, 'deflateSetDictionary'); + + dictId := c_stream.adler; + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + c_stream.next_in := hello; + c_stream.avail_in := StrLen(hello)+1; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with a preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + while TRUE do + begin + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + if err = Z_NEED_DICT then + begin + if d_stream.adler <> dictId then + EXIT_ERR('unexpected dictionary'); + err := inflateSetDictionary(d_stream, dictionary, StrLen(dictionary)); + end; + CHECK_ERR(err, 'inflate with dict'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate with dict') + else + WriteLn('inflate with dictionary: ', PChar(uncompr)); +end; +{$ENDIF} + +var compr, uncompr: Pointer; + comprLen, uncomprLen: LongInt; + +begin + if zlibVersion^ <> ZLIB_VERSION[1] then + EXIT_ERR('Incompatible zlib version'); + + WriteLn('zlib version: ', zlibVersion); + WriteLn('zlib compile flags: ', Format('0x%x', [zlibCompileFlags])); + + comprLen := 10000 * SizeOf(Integer); (* don't overflow on MSDOS *) + uncomprLen := comprLen; + GetMem(compr, comprLen); + GetMem(uncompr, uncomprLen); + if (compr = NIL) or (uncompr = NIL) then + EXIT_ERR('Out of memory'); + (* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + *) + FillChar(compr^, comprLen, 0); + FillChar(uncompr^, uncomprLen, 0); + + {$IFDEF TEST_COMPRESS} + WriteLn('** Testing compress'); + test_compress(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_GZIO} + WriteLn('** Testing gzio'); + if ParamCount >= 1 then + test_gzio(ParamStr(1), uncompr, uncomprLen) + else + test_gzio(TESTFILE, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with small buffers'); + test_deflate(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with small buffers'); + test_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with large buffers'); + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with large buffers'); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_FLUSH} + WriteLn('** Testing deflate with full flush'); + test_flush(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_SYNC} + WriteLn('** Testing inflateSync'); + test_sync(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + comprLen := uncomprLen; + + {$IFDEF TEST_DICT} + WriteLn('** Testing deflate and inflate with preset dictionary'); + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + FreeMem(compr, comprLen); + FreeMem(uncompr, uncomprLen); +end. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/readme.txt new file mode 100644 index 00000000..60e87c8a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/readme.txt @@ -0,0 +1,76 @@ + +This directory contains a Pascal (Delphi, Kylix) interface to the +zlib data compression library. + + +Directory listing +================= + +zlibd32.mak makefile for Borland C++ +example.pas usage example of zlib +zlibpas.pas the Pascal interface to zlib +readme.txt this file + + +Compatibility notes +=================== + +- Although the name "zlib" would have been more normal for the + zlibpas unit, this name is already taken by Borland's ZLib unit. + This is somehow unfortunate, because that unit is not a genuine + interface to the full-fledged zlib functionality, but a suite of + class wrappers around zlib streams. Other essential features, + such as checksums, are missing. + It would have been more appropriate for that unit to have a name + like "ZStreams", or something similar. + +- The C and zlib-supplied types int, uInt, long, uLong, etc. are + translated directly into Pascal types of similar sizes (Integer, + LongInt, etc.), to avoid namespace pollution. In particular, + there is no conversion of unsigned int into a Pascal unsigned + integer. The Word type is non-portable and has the same size + (16 bits) both in a 16-bit and in a 32-bit environment, unlike + Integer. Even if there is a 32-bit Cardinal type, there is no + real need for unsigned int in zlib under a 32-bit environment. + +- Except for the callbacks, the zlib function interfaces are + assuming the calling convention normally used in Pascal + (__pascal for DOS and Windows16, __fastcall for Windows32). + Since the cdecl keyword is used, the old Turbo Pascal does + not work with this interface. + +- The gz* function interfaces are not translated, to avoid + interfacing problems with the C runtime library. Besides, + gzprintf(gzFile file, const char *format, ...) + cannot be translated into Pascal. + + +Legal issues +============ + +The zlibpas interface is: + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler. + Copyright (C) 1998 by Bob Dellaca. + Copyright (C) 2003 by Cosmin Truta. + +The example program is: + Copyright (C) 1995-2003 by Jean-loup Gailly. + Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali. + Copyright (C) 2003 by Cosmin Truta. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/zlibd32.mak b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/zlibd32.mak new file mode 100644 index 00000000..0d0699a6 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/zlibd32.mak @@ -0,0 +1,99 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/zlibpas.pas b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/zlibpas.pas new file mode 100644 index 00000000..637ae3a3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/pascal/zlibpas.pas @@ -0,0 +1,236 @@ +(* zlibpas -- Pascal interface to the zlib data compression library + * + * Copyright (C) 2003 Cosmin Truta. + * Derived from original sources by Bob Dellaca. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +unit zlibpas; + +interface + +const + ZLIB_VERSION = '1.2.5'; + +type + alloc_func = function(opaque: Pointer; items, size: Integer): Pointer; + cdecl; + free_func = procedure(opaque, address: Pointer); + cdecl; + + in_func = function(opaque: Pointer; var buf: PByte): Integer; + cdecl; + out_func = function(opaque: Pointer; buf: PByte; size: Integer): Integer; + cdecl; + + z_streamp = ^z_stream; + z_stream = packed record + next_in: PChar; (* next input byte *) + avail_in: Integer; (* number of bytes available at next_in *) + total_in: LongInt; (* total nb of input bytes read so far *) + + next_out: PChar; (* next output byte should be put there *) + avail_out: Integer; (* remaining free space at next_out *) + total_out: LongInt; (* total nb of bytes output so far *) + + msg: PChar; (* last error message, NULL if no error *) + state: Pointer; (* not visible by applications *) + + zalloc: alloc_func; (* used to allocate the internal state *) + zfree: free_func; (* used to free the internal state *) + opaque: Pointer; (* private data object passed to zalloc and zfree *) + + data_type: Integer; (* best guess about the data type: ascii or binary *) + adler: LongInt; (* adler32 value of the uncompressed data *) + reserved: LongInt; (* reserved for future use *) + end; + +(* constants *) +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = -1; + Z_STREAM_ERROR = -2; + Z_DATA_ERROR = -3; + Z_MEM_ERROR = -4; + Z_BUF_ERROR = -5; + Z_VERSION_ERROR = -6; + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = -1; + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + +(* basic functions *) +function zlibVersion: PChar; +function deflateInit(var strm: z_stream; level: Integer): Integer; +function deflate(var strm: z_stream; flush: Integer): Integer; +function deflateEnd(var strm: z_stream): Integer; +function inflateInit(var strm: z_stream): Integer; +function inflate(var strm: z_stream; flush: Integer): Integer; +function inflateEnd(var strm: z_stream): Integer; + +(* advanced functions *) +function deflateInit2(var strm: z_stream; level, method, windowBits, + memLevel, strategy: Integer): Integer; +function deflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function deflateCopy(var dest, source: z_stream): Integer; +function deflateReset(var strm: z_stream): Integer; +function deflateParams(var strm: z_stream; level, strategy: Integer): Integer; +function deflateBound(var strm: z_stream; sourceLen: LongInt): LongInt; +function deflatePrime(var strm: z_stream; bits, value: Integer): Integer; +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +function inflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function inflateSync(var strm: z_stream): Integer; +function inflateCopy(var dest, source: z_stream): Integer; +function inflateReset(var strm: z_stream): Integer; +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +function inflateBack(var strm: z_stream; in_fn: in_func; in_desc: Pointer; + out_fn: out_func; out_desc: Pointer): Integer; +function inflateBackEnd(var strm: z_stream): Integer; +function zlibCompileFlags: LongInt; + +(* utility functions *) +function compress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; +function compress2(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt; + level: Integer): Integer; +function compressBound(sourceLen: LongInt): LongInt; +function uncompress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; + +(* checksum functions *) +function adler32(adler: LongInt; const buf: PChar; len: Integer): LongInt; +function crc32(crc: LongInt; const buf: PChar; len: Integer): LongInt; + +(* various hacks, don't look :) *) +function deflateInit_(var strm: z_stream; level: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit_(var strm: z_stream; const version: PChar; + stream_size: Integer): Integer; +function deflateInit2_(var strm: z_stream; + level, method, windowBits, memLevel, strategy: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit2_(var strm: z_stream; windowBits: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateBackInit_(var strm: z_stream; + windowBits: Integer; window: PChar; + const version: PChar; stream_size: Integer): Integer; + + +implementation + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +function adler32; external; +function compress; external; +function compress2; external; +function compressBound; external; +function crc32; external; +function deflate; external; +function deflateBound; external; +function deflateCopy; external; +function deflateEnd; external; +function deflateInit_; external; +function deflateInit2_; external; +function deflateParams; external; +function deflatePrime; external; +function deflateReset; external; +function deflateSetDictionary; external; +function inflate; external; +function inflateBack; external; +function inflateBackEnd; external; +function inflateBackInit_; external; +function inflateCopy; external; +function inflateEnd; external; +function inflateInit_; external; +function inflateInit2_; external; +function inflateReset; external; +function inflateSetDictionary; external; +function inflateSync; external; +function uncompress; external; +function zlibCompileFlags; external; +function zlibVersion; external; + +function deflateInit(var strm: z_stream; level: Integer): Integer; +begin + Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream)); +end; + +function deflateInit2(var strm: z_stream; level, method, windowBits, memLevel, + strategy: Integer): Integer; +begin + Result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit(var strm: z_stream): Integer; +begin + Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +begin + Result := inflateInit2_(strm, windowBits, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +begin + Result := inflateBackInit_(strm, windowBits, window, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + GetMem(Result, Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + +end. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/Makefile b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/Makefile new file mode 100644 index 00000000..b6b69404 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/Makefile @@ -0,0 +1,8 @@ +puff: puff.c puff.h + cc -DTEST -o puff puff.c + +test: puff + puff zeros.raw + +clean: + rm -f puff puff.o diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/README new file mode 100644 index 00000000..bbc4cb59 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/README @@ -0,0 +1,63 @@ +Puff -- A Simple Inflate +3 Mar 2003 +Mark Adler +madler@alumni.caltech.edu + +What this is -- + +puff.c provides the routine puff() to decompress the deflate data format. It +does so more slowly than zlib, but the code is about one-fifth the size of the +inflate code in zlib, and written to be very easy to read. + +Why I wrote this -- + +puff.c was written to document the deflate format unambiguously, by virtue of +being working C code. It is meant to supplement RFC 1951, which formally +describes the deflate format. I have received many questions on details of the +deflate format, and I hope that reading this code will answer those questions. +puff.c is heavily commented with details of the deflate format, especially +those little nooks and cranies of the format that might not be obvious from a +specification. + +puff.c may also be useful in applications where code size or memory usage is a +very limited resource, and speed is not as important. + +How to use it -- + +Well, most likely you should just be reading puff.c and using zlib for actual +applications, but if you must ... + +Include puff.h in your code, which provides this prototype: + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ + +Then you can call puff() to decompress a deflate stream that is in memory in +its entirety at source, to a sufficiently sized block of memory for the +decompressed data at dest. puff() is the only external symbol in puff.c The +only C library functions that puff.c needs are setjmp() and longjmp(), which +are used to simplify error checking in the code to improve readabilty. puff.c +does no memory allocation, and uses less than 2K bytes off of the stack. + +If destlen is not enough space for the uncompressed data, then inflate will +return an error without writing more than destlen bytes. Note that this means +that in order to decompress the deflate data successfully, you need to know +the size of the uncompressed data ahead of time. + +If needed, puff() can determine the size of the uncompressed data with no +output space. This is done by passing dest equal to (unsigned char *)0. Then +the initial value of *destlen is ignored and *destlen is set to the length of +the uncompressed data. So if the size of the uncompressed data is not known, +then two passes of puff() can be used--first to determine the size, and second +to do the actual inflation after allocating the appropriate memory. Not +pretty, but it works. (This is one of the reasons you should be using zlib.) + +The deflate format is self-terminating. If the deflate stream does not end +in *sourcelen bytes, puff() will return an error without reading at or past +endsource. + +On return, *sourcelen is updated to the amount of input data consumed, and +*destlen is updated to the size of the uncompressed data. See the comments +in puff.c for the possible return codes for puff(). diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/puff.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/puff.c new file mode 100644 index 00000000..650694e9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/puff.c @@ -0,0 +1,955 @@ +/* + * puff.c + * Copyright (C) 2002-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 2.1, 4 Apr 2010 + * + * puff.c is a simple inflate written to be an unambiguous way to specify the + * deflate format. It is not written for speed but rather simplicity. As a + * side benefit, this code might actually be useful when small code is more + * important than speed, such as bootstrap applications. For typical deflate + * data, zlib's inflate() is about four times as fast as puff(). zlib's + * inflate compiles to around 20K on my machine, whereas puff.c compiles to + * around 4K on my machine (a PowerPC using GNU cc). If the faster decode() + * function here is used, then puff() is only twice as slow as zlib's + * inflate(). + * + * All dynamically allocated memory comes from the stack. The stack required + * is less than 2K bytes. This code is compatible with 16-bit int's and + * assumes that long's are at least 32 bits. puff.c uses the short data type, + * assumed to be 16 bits, for arrays in order to to conserve memory. The code + * works whether integers are stored big endian or little endian. + * + * In the comments below are "Format notes" that describe the inflate process + * and document some of the less obvious aspects of the format. This source + * code is meant to supplement RFC 1951, which formally describes the deflate + * format: + * + * http://www.zlib.org/rfc-deflate.html + */ + +/* + * Change history: + * + * 1.0 10 Feb 2002 - First version + * 1.1 17 Feb 2002 - Clarifications of some comments and notes + * - Update puff() dest and source pointers on negative + * errors to facilitate debugging deflators + * - Remove longest from struct huffman -- not needed + * - Simplify offs[] index in construct() + * - Add input size and checking, using longjmp() to + * maintain easy readability + * - Use short data type for large arrays + * - Use pointers instead of long to specify source and + * destination sizes to avoid arbitrary 4 GB limits + * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), + * but leave simple version for readabilty + * - Make sure invalid distances detected if pointers + * are 16 bits + * - Fix fixed codes table error + * - Provide a scanning mode for determining size of + * uncompressed data + * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup] + * - Add a puff.h file for the interface + * - Add braces in puff() for else do [Jean-loup] + * - Use indexes instead of pointers for readability + * 1.4 31 Mar 2002 - Simplify construct() code set check + * - Fix some comments + * - Add FIXLCODES #define + * 1.5 6 Apr 2002 - Minor comment fixes + * 1.6 7 Aug 2002 - Minor format changes + * 1.7 3 Mar 2003 - Added test code for distribution + * - Added zlib-like license + * 1.8 9 Jan 2004 - Added some comments on no distance codes case + * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland] + * - Catch missing end-of-block symbol error + * 2.0 25 Jul 2008 - Add #define to permit distance too far back + * - Add option in TEST code for puff to write the data + * - Add option in TEST code to skip input bytes + * - Allow TEST code to read from piped stdin + * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers + * - Avoid unsigned comparisons for even happier compilers + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "puff.h" /* prototype for puff() */ + +#define local static /* for local function definitions */ +#define NIL ((unsigned char *)0) /* for no output option */ + +/* + * Maximums for allocations and loops. It is not useful to change these -- + * they are fixed by the deflate format. + */ +#define MAXBITS 15 /* maximum bits in a code */ +#define MAXLCODES 286 /* maximum number of literal/length codes */ +#define MAXDCODES 30 /* maximum number of distance codes */ +#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ +#define FIXLCODES 288 /* number of fixed literal/length codes */ + +/* input and output state */ +struct state { + /* output state */ + unsigned char *out; /* output buffer */ + unsigned long outlen; /* available space at out */ + unsigned long outcnt; /* bytes written to out so far */ + + /* input state */ + unsigned char *in; /* input buffer */ + unsigned long inlen; /* available input at in */ + unsigned long incnt; /* bytes read so far */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + long val; /* bit accumulator (can use up to 20 bits) */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ + val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = (int)(val >> need); + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return (int)(val & ((1L << need) - 1)); +} + +/* + * Process a stored block. + * + * Format notes: + * + * - After the two-bit stored block type (00), the stored block length and + * stored bytes are byte-aligned for fast copying. Therefore any leftover + * bits in the byte that has the last bit of the type, as many as seven, are + * discarded. The value of the discarded bits are not defined and should not + * be checked against any expectation. + * + * - The second inverted copy of the stored block length does not have to be + * checked, but it's probably a good idea to do so anyway. + * + * - A stored block can have zero length. This is sometimes used to byte-align + * subsets of the compressed data for random access or partial recovery. + */ +local int stored(struct state *s) +{ + unsigned len; /* length of stored block */ + + /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ + s->bitbuf = 0; + s->bitcnt = 0; + + /* get length and check against its one's complement */ + if (s->incnt + 4 > s->inlen) return 2; /* not enough input */ + len = s->in[s->incnt++]; + len |= s->in[s->incnt++] << 8; + if (s->in[s->incnt++] != (~len & 0xff) || + s->in[s->incnt++] != ((~len >> 8) & 0xff)) + return -2; /* didn't match complement! */ + + /* copy len bytes from in to out */ + if (s->incnt + len > s->inlen) return 2; /* not enough input */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; /* not enough output space */ + while (len--) + s->out[s->outcnt++] = s->in[s->incnt++]; + } + else { /* just scanning */ + s->outcnt += len; + s->incnt += len; + } + + /* done with a valid stored block */ + return 0; +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -10 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. A table-based decoding + * scheme (as used in zlib) does not need to do this reversal. + * + * - The first code for the shortest length is all zeros. Subsequent codes of + * the same length are simply integer increments of the previous code. When + * moving up a length, a zero bit is appended to the code. For a complete + * code, the last code of the longest length will be all ones. + * + * - Incomplete codes are handled by this decoder, since they are permitted + * in the deflate format. See the format notes for fixed() and dynamic(). + */ +#ifdef SLOW +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + + code = first = index = 0; + for (len = 1; len <= MAXBITS; len++) { + code |= bits(s, 1); /* get next bit */ + count = h->count[len]; + if (code - count < first) /* if length len, return symbol */ + return h->symbol[index + (code - first)]; + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + } + return -10; /* ran out of codes */ +} + +/* + * A faster version of decode() for real applications of this code. It's not + * as readable, but it makes puff() twice as fast. And it only makes the code + * a few percent larger. + */ +#else /* !SLOW */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= bitbuf & 1; + bitbuf >>= 1; + count = *next++; + if (code - count < first) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ + bitbuf = s->in[s->incnt++]; + if (left > 8) left = 8; + } + return -10; /* ran out of codes */ +} +#endif /* SLOW */ + +/* + * Given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + * + * Not used by decode(), but used for error checking, h->count[0] is the number + * of the n symbols not in the code. So n - h->count[0] is the number of + * codes. This is useful for checking for incomplete codes that have more than + * one symbol, which is an error in a dynamic block. + * + * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS + * This is assured by the construction of the length arrays in dynamic() and + * fixed() and is not verified by construct(). + * + * Format notes: + * + * - Permitted and expected examples of incomplete codes are one of the fixed + * codes and any code with a single symbol which in deflate is coded as one + * bit instead of zero bits. See the format notes for fixed() and dynamic(). + * + * - Within a given code length, the symbols are kept in ascending order for + * the code bits definition. + */ +local int construct(struct huffman *h, short *length, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode literal/length and distance codes until an end-of-block code. + * + * Format notes: + * + * - Compressed data that is after the block type if fixed or after the code + * description if dynamic is a combination of literals and length/distance + * pairs terminated by and end-of-block code. Literals are simply Huffman + * coded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - Literals, lengths, and the end-of-block code are combined into a single + * code of up to 286 symbols. They are 256 literals (0..255), 29 length + * symbols (257..285), and the end-of-block symbol (256). + * + * - There are 256 possible lengths (3..258), and so 29 symbols are not enough + * to represent all of those. Lengths 3..10 and 258 are in fact represented + * by just a length symbol. Lengths 11..257 are represented as a symbol and + * some number of extra bits that are added as an integer to the base length + * of the length symbol. The number of extra bits is determined by the base + * length symbol. These are in the static arrays below, lens[] for the base + * lengths and lext[] for the corresponding number of extra bits. + * + * - The reason that 258 gets its own symbol is that the longest length is used + * often in highly redundant files. Note that 258 can also be coded as the + * base value 227 plus the maximum extra value of 31. While a good deflate + * should never do this, it is not an error, and should be decoded properly. + * + * - If a length is decoded, including its extra bits if any, then it is + * followed a distance code. There are up to 30 distance symbols. Again + * there are many more possible distances (1..32768), so extra bits are added + * to a base value represented by the symbol. The distances 1..4 get their + * own symbol, but the rest require extra bits. The base distances and + * corresponding number of extra bits are below in the static arrays dist[] + * and dext[]. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 258 + * simply copies the last byte 258 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. You should not use memcpy() since its behavior is not + * defined for overlapped arrays. You should not use memmove() or bcopy() + * since though their behavior -is- defined for overlapping arrays, it is + * defined to do the wrong thing in this case. + */ +local int codes(struct state *s, + struct huffman *lencode, + struct huffman *distcode) +{ + int symbol; /* decoded symbol */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + static const short lens[29] = { /* Size base for length codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const short lext[29] = { /* Extra bits for length codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const short dists[30] = { /* Offset base for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const short dext[30] = { /* Extra bits for distance codes 0..29 */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + /* decode literals and length/distance pairs */ + do { + symbol = decode(s, lencode); + if (symbol < 0) return symbol; /* invalid symbol */ + if (symbol < 256) { /* literal: symbol is the byte */ + /* write out the literal */ + if (s->out != NIL) { + if (s->outcnt == s->outlen) return 1; + s->out[s->outcnt] = symbol; + } + s->outcnt++; + } + else if (symbol > 256) { /* length */ + /* get and compute length */ + symbol -= 257; + if (symbol >= 29) return -10; /* invalid fixed code */ + len = lens[symbol] + bits(s, lext[symbol]); + + /* get and check distance */ + symbol = decode(s, distcode); + if (symbol < 0) return symbol; /* invalid symbol */ + dist = dists[symbol] + bits(s, dext[symbol]); +#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (dist > s->outcnt) + return -11; /* distance too far back */ +#endif + + /* copy length bytes from distance bytes back */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) return 1; + while (len--) { + s->out[s->outcnt] = +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + dist > s->outcnt ? 0 : +#endif + s->out[s->outcnt - dist]; + s->outcnt++; + } + } + else + s->outcnt += len; + } + } while (symbol != 256); /* end of block symbol */ + + /* done with a valid fixed or dynamic block */ + return 0; +} + +/* + * Process a fixed codes block. + * + * Format notes: + * + * - This block type can be useful for compressing small amounts of data for + * which the size of the code descriptions in a dynamic block exceeds the + * benefit of custom codes for that block. For fixed codes, no bits are + * spent on code descriptions. Instead the code lengths for literal/length + * codes and distance codes are fixed. The specific lengths for each symbol + * can be seen in the "for" loops below. + * + * - The literal/length code is complete, but has two symbols that are invalid + * and should result in an error if received. This cannot be implemented + * simply as an incomplete code since those two symbols are in the "middle" + * of the code. They are eight bits long and the longest literal/length\ + * code is nine bits. Therefore the code must be constructed with those + * symbols, and the invalid symbols must be detected after decoding. + * + * - The fixed distance codes also have two invalid symbols that should result + * in an error if received. Since all of the distance codes are the same + * length, this can be implemented as an incomplete code. Then the invalid + * codes are detected while decoding. + */ +local int fixed(struct state *s) +{ + static int virgin = 1; + static short lencnt[MAXBITS+1], lensym[FIXLCODES]; + static short distcnt[MAXBITS+1], distsym[MAXDCODES]; + static struct huffman lencode, distcode; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + int symbol; + short lengths[FIXLCODES]; + + /* literal/length table */ + for (symbol = 0; symbol < 144; symbol++) + lengths[symbol] = 8; + for (; symbol < 256; symbol++) + lengths[symbol] = 9; + for (; symbol < 280; symbol++) + lengths[symbol] = 7; + for (; symbol < FIXLCODES; symbol++) + lengths[symbol] = 8; + construct(&lencode, lengths, FIXLCODES); + + /* distance table */ + for (symbol = 0; symbol < MAXDCODES; symbol++) + lengths[symbol] = 5; + construct(&distcode, lengths, MAXDCODES); + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* do this just once */ + virgin = 0; + } + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Process a dynamic codes block. + * + * Format notes: + * + * - A dynamic block starts with a description of the literal/length and + * distance codes for that block. New dynamic blocks allow the compressor to + * rapidly adapt to changing data with new codes optimized for that data. + * + * - The codes used by the deflate format are "canonical", which means that + * the actual bits of the codes are generated in an unambiguous way simply + * from the number of bits in each code. Therefore the code descriptions + * are simply a list of code lengths for each symbol. + * + * - The code lengths are stored in order for the symbols, so lengths are + * provided for each of the literal/length symbols, and for each of the + * distance symbols. + * + * - If a symbol is not used in the block, this is represented by a zero as + * as the code length. This does not mean a zero-length code, but rather + * that no code should be created for this symbol. There is no way in the + * deflate format to represent a zero-length code. + * + * - The maximum number of bits in a code is 15, so the possible lengths for + * any code are 1..15. + * + * - The fact that a length of zero is not permitted for a code has an + * interesting consequence. Normally if only one symbol is used for a given + * code, then in fact that code could be represented with zero bits. However + * in deflate, that code has to be at least one bit. So for example, if + * only a single distance base symbol appears in a block, then it will be + * represented by a single code of length one, in particular one 0 bit. This + * is an incomplete code, since if a 1 bit is received, it has no meaning, + * and should result in an error. So incomplete distance codes of one symbol + * should be permitted, and the receipt of invalid codes should be handled. + * + * - It is also possible to have a single literal/length code, but that code + * must be the end-of-block code, since every dynamic block has one. This + * is not the most efficient way to create an empty block (an empty fixed + * block is fewer bits), but it is allowed by the format. So incomplete + * literal/length codes of one symbol should also be permitted. + * + * - If there are only literal codes and no lengths, then there are no distance + * codes. This is represented by one distance code with zero bits. + * + * - The list of up to 286 length/literal lengths and up to 30 distance lengths + * are themselves compressed using Huffman codes and run-length encoding. In + * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means + * that length, and the symbols 16, 17, and 18 are run-length instructions. + * Each of 16, 17, and 18 are follwed by extra bits to define the length of + * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 + * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols + * are common, hence the special coding for zero lengths. + * + * - The symbols for 0..18 are Huffman coded, and so that code must be + * described first. This is simply a sequence of up to 19 three-bit values + * representing no code (0) or the code length for that symbol (1..7). + * + * - A dynamic block starts with three fixed-size counts from which is computed + * the number of literal/length code lengths, the number of distance code + * lengths, and the number of code length code lengths (ok, you come up with + * a better name!) in the code descriptions. For the literal/length and + * distance codes, lengths after those provided are considered zero, i.e. no + * code. The code length code lengths are received in a permuted order (see + * the order[] array below) to make a short code length code length list more + * likely. As it turns out, very short and very long codes are less likely + * to be seen in a dynamic code description, hence what may appear initially + * to be a peculiar ordering. + * + * - Given the number of literal/length code lengths (nlen) and distance code + * lengths (ndist), then they are treated as one long list of nlen + ndist + * code lengths. Therefore run-length coding can and often does cross the + * boundary between the two sets of lengths. + * + * - So to summarize, the code description at the start of a dynamic block is + * three counts for the number of code lengths for the literal/length codes, + * the distance codes, and the code length codes. This is followed by the + * code length code lengths, three bits each. This is used to construct the + * code length code which is used to read the remainder of the lengths. Then + * the literal/length code lengths and distance lengths are read as a single + * set of lengths using the code length codes. Codes are constructed from + * the resulting two sets of lengths, and then finally you can start + * decoding actual compressed data in the block. + * + * - For reference, a "typical" size for the code description in a dynamic + * block is around 80 bytes. + */ +local int dynamic(struct state *s) +{ + int nlen, ndist, ncode; /* number of lengths in descriptor */ + int index; /* index of lengths[] */ + int err; /* construct() return value */ + short lengths[MAXCODES]; /* descriptor code lengths */ + short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ + short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ + struct huffman lencode, distcode; /* length and distance codes */ + static const short order[19] = /* permutation of code length codes */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* get number of lengths in each table, check lengths */ + nlen = bits(s, 5) + 257; + ndist = bits(s, 5) + 1; + ncode = bits(s, 4) + 4; + if (nlen > MAXLCODES || ndist > MAXDCODES) + return -3; /* bad counts */ + + /* read code length code lengths (really), missing lengths are zero */ + for (index = 0; index < ncode; index++) + lengths[order[index]] = bits(s, 3); + for (; index < 19; index++) + lengths[order[index]] = 0; + + /* build huffman table for code lengths codes (use lencode temporarily) */ + err = construct(&lencode, lengths, 19); + if (err != 0) return -4; /* require complete code set here */ + + /* read length/literal and distance code length tables */ + index = 0; + while (index < nlen + ndist) { + int symbol; /* decoded value */ + int len; /* last length to repeat */ + + symbol = decode(s, &lencode); + if (symbol < 16) /* length in 0..15 */ + lengths[index++] = symbol; + else { /* repeat instruction */ + len = 0; /* assume repeating zeros */ + if (symbol == 16) { /* repeat last length 3..6 times */ + if (index == 0) return -5; /* no last length! */ + len = lengths[index - 1]; /* last length */ + symbol = 3 + bits(s, 2); + } + else if (symbol == 17) /* repeat zero 3..10 times */ + symbol = 3 + bits(s, 3); + else /* == 18, repeat zero 11..138 times */ + symbol = 11 + bits(s, 7); + if (index + symbol > nlen + ndist) + return -6; /* too many lengths! */ + while (symbol--) /* repeat last or zero symbol times */ + lengths[index++] = len; + } + } + + /* check for end-of-block code -- there better be one! */ + if (lengths[256] == 0) + return -9; + + /* build huffman table for literal/length codes */ + err = construct(&lencode, lengths, nlen); + if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) + return -7; /* only allow incomplete codes if just one code */ + + /* build huffman table for distance codes */ + err = construct(&distcode, lengths + nlen, ndist); + if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) + return -8; /* only allow incomplete codes if just one code */ + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Inflate source to dest. On return, destlen and sourcelen are updated to the + * size of the uncompressed data and the size of the deflate data respectively. + * On success, the return value of puff() is zero. If there is an error in the + * source data, i.e. it is not in the deflate format, then a negative value is + * returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. In that case, destlen and + * sourcelen are not updated to facilitate retrying from the beginning with the + * provision of more input data or more output space. In the case of invalid + * inflate data (a negative error), the dest and source pointers are updated to + * facilitate the debugging of deflators. + * + * puff() also has a mode to determine the size of the uncompressed output with + * no output written. For this dest must be (unsigned char *)0. In this case, + * the input value of *destlen is ignored, and on return *destlen is set to the + * size of the uncompressed output. + * + * The return codes are: + * + * 2: available inflate data did not terminate + * 1: output space exhausted before completing inflate + * 0: successful inflate + * -1: invalid block type (type == 3) + * -2: stored block length did not match one's complement + * -3: dynamic block code description: too many length or distance codes + * -4: dynamic block code description: code lengths codes incomplete + * -5: dynamic block code description: repeat lengths with no first length + * -6: dynamic block code description: repeat more than specified lengths + * -7: dynamic block code description: invalid literal/length code lengths + * -8: dynamic block code description: invalid distance code lengths + * -9: dynamic block code description: missing end-of-block code + * -10: invalid literal/length or distance code in fixed or dynamic block + * -11: distance is too far back in fixed or dynamic block + * + * Format notes: + * + * - Three bits are read for each block to determine the kind of block and + * whether or not it is the last block. Then the block is decoded and the + * process repeated if it was not the last block. + * + * - The leftover bits in the last byte of the deflate data after the last + * block (if it was a fixed or dynamic block) are undefined and have no + * expected values to check. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen) /* amount of input available */ +{ + struct state s; /* input/output state */ + int last, type; /* block information */ + int err; /* return value */ + + /* initialize output state */ + s.out = dest; + s.outlen = *destlen; /* ignored if dest is NIL */ + s.outcnt = 0; + + /* initialize input state */ + s.in = source; + s.inlen = *sourcelen; + s.incnt = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp() */ + err = 2; /* then skip do-loop, return error */ + else { + /* process blocks until last block or error */ + do { + last = bits(&s, 1); /* one if last block */ + type = bits(&s, 2); /* block type 0..3 */ + err = type == 0 ? stored(&s) : + (type == 1 ? fixed(&s) : + (type == 2 ? dynamic(&s) : + -1)); /* type == 3, invalid */ + if (err != 0) break; /* return with error */ + } while (!last); + } + + /* update the lengths and return */ + if (err <= 0) { + *destlen = s.outcnt; + *sourcelen = s.incnt; + } + return err; +} + +#ifdef TEST +/* Examples of how to use puff(). + + Usage: puff [-w] [-nnn] file + ... | puff [-w] [-nnn] + + where file is the input file with deflate data, nnn is the number of bytes + of input to skip before inflating (e.g. to skip a zlib or gzip header), and + -w is used to write the decompressed data to stdout */ + +#include +#include + +/* Return size times approximately the cube root of 2, keeping the result as 1, + 3, or 5 times a power of 2 -- the result is always > size, until the result + is the maximum value of an unsigned long, where it remains. This is useful + to keep reallocations less than ~33% over the actual data. */ +local size_t bythirds(size_t size) +{ + int n; + size_t m; + + m = size; + for (n = 0; m; n++) + m >>= 1; + if (n < 3) + return size + 1; + n -= 3; + m = size >> n; + m += m == 6 ? 2 : 1; + m <<= n; + return m > size ? m : (size_t)(-1); +} + +/* Read the input file *name, or stdin if name is NULL, into allocated memory. + Reallocate to larger buffers until the entire file is read in. Return a + pointer to the allocated data, or NULL if there was a memory allocation + failure. *len is the number of bytes of data read from the input file (even + if load() returns NULL). If the input file was empty or could not be opened + or read, *len is zero. */ +local void *load(char *name, size_t *len) +{ + size_t size; + void *buf, *swap; + FILE *in; + + *len = 0; + buf = malloc(size = 4096); + if (buf == NULL) + return NULL; + in = name == NULL ? stdin : fopen(name, "rb"); + if (in != NULL) { + for (;;) { + *len += fread((char *)buf + *len, 1, size - *len, in); + if (*len < size) break; + size = bythirds(size); + if (size == *len || (swap = realloc(buf, size)) == NULL) { + free(buf); + buf = NULL; + break; + } + buf = swap; + } + fclose(in); + } + return buf; +} + +int main(int argc, char **argv) +{ + int ret, put = 0; + unsigned skip = 0; + char *arg, *name = NULL; + unsigned char *source = NULL, *dest; + size_t len = 0; + unsigned long sourcelen, destlen; + + /* process arguments */ + while (arg = *++argv, --argc) + if (arg[0] == '-') { + if (arg[1] == 'w' && arg[2] == 0) + put = 1; + else if (arg[1] >= '0' && arg[1] <= '9') + skip = (unsigned)atoi(arg + 1); + else { + fprintf(stderr, "invalid option %s\n", arg); + return 3; + } + } + else if (name != NULL) { + fprintf(stderr, "only one file name allowed\n"); + return 3; + } + else + name = arg; + source = load(name, &len); + if (source == NULL) { + fprintf(stderr, "memory allocation failure\n"); + return 4; + } + if (len == 0) { + fprintf(stderr, "could not read %s, or it was empty\n", + name == NULL ? "" : name); + free(source); + return 3; + } + if (skip >= len) { + fprintf(stderr, "skip request of %d leaves no input\n", skip); + free(source); + return 3; + } + + /* test inflate data with offset skip */ + len -= skip; + sourcelen = (unsigned long)len; + ret = puff(NIL, &destlen, source + skip, &sourcelen); + if (ret) + fprintf(stderr, "puff() failed with return code %d\n", ret); + else { + fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen); + if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n", + len - sourcelen); + } + + /* if requested, inflate again and write decompressd data to stdout */ + if (put) { + dest = malloc(destlen); + if (dest == NULL) { + fprintf(stderr, "memory allocation failure\n"); + free(source); + return 4; + } + puff(dest, &destlen, source + skip, &sourcelen); + fwrite(dest, 1, destlen, stdout); + free(dest); + } + + /* clean up */ + free(source); + return ret; +} +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/puff.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/puff.h new file mode 100644 index 00000000..88d1b384 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/puff.h @@ -0,0 +1,31 @@ +/* puff.h + Copyright (C) 2002-2010 Mark Adler, all rights reserved + version 2.1, 4 Apr 2010 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * See puff.c for purpose and usage. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/zeros.raw b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/zeros.raw new file mode 100644 index 00000000..637b7be6 Binary files /dev/null and b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/puff/zeros.raw differ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/testzlib/testzlib.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/testzlib/testzlib.c new file mode 100644 index 00000000..f559a364 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/testzlib/testzlib.c @@ -0,0 +1,275 @@ +#include +#include +#include + +#include "zlib.h" + + +void MyDoMinus64(LARGE_INTEGER *R,LARGE_INTEGER A,LARGE_INTEGER B) +{ + R->HighPart = A.HighPart - B.HighPart; + if (A.LowPart >= B.LowPart) + R->LowPart = A.LowPart - B.LowPart; + else + { + R->LowPart = A.LowPart - B.LowPart; + R->HighPart --; + } +} + +#ifdef _M_X64 +// see http://msdn2.microsoft.com/library/twchhe95(en-us,vs.80).aspx for __rdtsc +unsigned __int64 __rdtsc(void); +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ + // printf("rdtsc = %I64x\n",__rdtsc()); + pbeginTime64->QuadPart=__rdtsc(); +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER LIres; + unsigned _int64 res=__rdtsc()-((unsigned _int64)(beginTime64.QuadPart)); + LIres.QuadPart=res; + // printf("rdtsc = %I64x\n",__rdtsc()); + return LIres; +} +#else +#ifdef _M_IX86 +void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) +{ + DWORD dwEdx,dwEax; + _asm + { + rdtsc + mov dwEax,eax + mov dwEdx,edx + } + pbeginTime64->LowPart=dwEax; + pbeginTime64->HighPart=dwEdx; +} + +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ + myGetRDTSC32(pbeginTime64); +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER LIres,endTime64; + myGetRDTSC32(&endTime64); + + LIres.LowPart=LIres.HighPart=0; + MyDoMinus64(&LIres,endTime64,beginTime64); + return LIres; +} +#else +void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) +{ +} + +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER lr; + lr.QuadPart=0; + return lr; +} +#endif +#endif + +void BeginCountPerfCounter(LARGE_INTEGER * pbeginTime64,BOOL fComputeTimeQueryPerf) +{ + if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(pbeginTime64))) + { + pbeginTime64->LowPart = GetTickCount(); + pbeginTime64->HighPart = 0; + } +} + +DWORD GetMsecSincePerfCounter(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER endTime64,ticksPerSecond,ticks; + DWORDLONG ticksShifted,tickSecShifted; + DWORD dwLog=16+0; + DWORD dwRet; + if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(&endTime64))) + dwRet = (GetTickCount() - beginTime64.LowPart)*1; + else + { + MyDoMinus64(&ticks,endTime64,beginTime64); + QueryPerformanceFrequency(&ticksPerSecond); + + + { + ticksShifted = Int64ShrlMod32(*(DWORDLONG*)&ticks,dwLog); + tickSecShifted = Int64ShrlMod32(*(DWORDLONG*)&ticksPerSecond,dwLog); + + } + + dwRet = (DWORD)((((DWORD)ticksShifted)*1000)/(DWORD)(tickSecShifted)); + dwRet *=1; + } + return dwRet; +} + +int ReadFileMemory(const char* filename,long* plFileSize,void** pFilePtr) +{ + FILE* stream; + void* ptr; + int retVal=1; + stream=fopen(filename, "rb"); + if (stream==NULL) + return 0; + + fseek(stream,0,SEEK_END); + + *plFileSize=ftell(stream); + fseek(stream,0,SEEK_SET); + ptr=malloc((*plFileSize)+1); + if (ptr==NULL) + retVal=0; + else + { + if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize)) + retVal=0; + } + fclose(stream); + *pFilePtr=ptr; + return retVal; +} + +int main(int argc, char *argv[]) +{ + int BlockSizeCompress=0x8000; + int BlockSizeUncompress=0x8000; + int cprLevel=Z_DEFAULT_COMPRESSION ; + long lFileSize; + unsigned char* FilePtr; + long lBufferSizeCpr; + long lBufferSizeUncpr; + long lCompressedSize=0; + unsigned char* CprPtr; + unsigned char* UncprPtr; + long lSizeCpr,lSizeUncpr; + DWORD dwGetTick,dwMsecQP; + LARGE_INTEGER li_qp,li_rdtsc,dwResRdtsc; + + if (argc<=1) + { + printf("run TestZlib [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n"); + return 0; + } + + if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) + { + printf("error reading %s\n",argv[1]); + return 1; + } + else printf("file %s read, %u bytes\n",argv[1],lFileSize); + + if (argc>=3) + BlockSizeCompress=atol(argv[2]); + + if (argc>=4) + BlockSizeUncompress=atol(argv[3]); + + if (argc>=5) + cprLevel=(int)atol(argv[4]); + + lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200; + lBufferSizeUncpr = lBufferSizeCpr; + + CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress); + + BeginCountPerfCounter(&li_qp,TRUE); + dwGetTick=GetTickCount(); + BeginCountRdtsc(&li_rdtsc); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lFileSize; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + deflateInit(&zcpr,cprLevel); + + zcpr.next_in = FilePtr; + zcpr.next_out = CprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeCompress); + zcpr.avail_out = BlockSizeCompress; + ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeCpr=zcpr.total_out; + deflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); + dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); + printf("total compress size = %u, in %u step\n",lSizeCpr,step); + printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); + printf("defcpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); + printf("defcpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); + } + + CprPtr=(unsigned char*)realloc(CprPtr,lSizeCpr); + UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress); + + BeginCountPerfCounter(&li_qp,TRUE); + dwGetTick=GetTickCount(); + BeginCountRdtsc(&li_rdtsc); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lSizeCpr; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + inflateInit(&zcpr); + + zcpr.next_in = CprPtr; + zcpr.next_out = UncprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress); + zcpr.avail_out = BlockSizeUncompress; + ret=inflate(&zcpr,Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeUncpr=zcpr.total_out; + inflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); + dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); + printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step); + printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); + printf("uncpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); + printf("uncpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); + } + + if (lSizeUncpr==lFileSize) + { + if (memcmp(FilePtr,UncprPtr,lFileSize)==0) + printf("compare ok\n"); + + } + + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/testzlib/testzlib.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/testzlib/testzlib.txt new file mode 100644 index 00000000..e508bb22 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/testzlib/testzlib.txt @@ -0,0 +1,10 @@ +To build testzLib with Visual Studio 2005: + +copy to a directory file from : +- root of zLib tree +- contrib/testzlib +- contrib/masmx86 +- contrib/masmx64 +- contrib/vstudio/vc7 + +and open testzlib8.sln \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/Makefile b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/Makefile new file mode 100644 index 00000000..b54266fb --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/Makefile @@ -0,0 +1,14 @@ +CC=cc +CFLAGS=-g + +untgz: untgz.o ../../libz.a + $(CC) $(CFLAGS) -o untgz untgz.o -L../.. -lz + +untgz.o: untgz.c ../../zlib.h + $(CC) $(CFLAGS) -c -I../.. untgz.c + +../../libz.a: + cd ../..; ./configure; make + +clean: + rm -f untgz untgz.o *~ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/Makefile.msc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/Makefile.msc new file mode 100644 index 00000000..77b86022 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/Makefile.msc @@ -0,0 +1,17 @@ +CC=cl +CFLAGS=-MD + +untgz.exe: untgz.obj ..\..\zlib.lib + $(CC) $(CFLAGS) untgz.obj ..\..\zlib.lib + +untgz.obj: untgz.c ..\..\zlib.h + $(CC) $(CFLAGS) -c -I..\.. untgz.c + +..\..\zlib.lib: + cd ..\.. + $(MAKE) -f win32\makefile.msc + cd contrib\untgz + +clean: + -del untgz.obj + -del untgz.exe diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/untgz.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/untgz.c new file mode 100644 index 00000000..2c391e59 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/untgz/untgz.c @@ -0,0 +1,674 @@ +/* + * untgz.c -- Display contents and extract files from a gzip'd TAR file + * + * written by Pedro A. Aranda Gutierrez + * adaptation to Unix by Jean-loup Gailly + * various fixes by Cosmin Truta + */ + +#include +#include +#include +#include +#include + +#include "zlib.h" + +#ifdef unix +# include +#else +# include +# include +#endif + +#ifdef WIN32 +#include +# ifndef F_OK +# define F_OK 0 +# endif +# define mkdir(dirname,mode) _mkdir(dirname) +# ifdef _MSC_VER +# define access(path,mode) _access(path,mode) +# define chmod(path,mode) _chmod(path,mode) +# define strdup(str) _strdup(str) +# endif +#else +# include +#endif + + +/* values used in typeflag field */ + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved */ + +/* GNU tar extensions */ + +#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */ +#define GNUTYPE_LONGLINK 'K' /* long link name */ +#define GNUTYPE_LONGNAME 'L' /* long file name */ +#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */ +#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */ +#define GNUTYPE_SPARSE 'S' /* sparse file */ +#define GNUTYPE_VOLHDR 'V' /* tape/volume header */ + + +/* tar header */ + +#define BLOCKSIZE 512 +#define SHORTNAMESIZE 100 + +struct tar_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +union tar_buffer +{ + char buffer[BLOCKSIZE]; + struct tar_header header; +}; + +struct attr_item +{ + struct attr_item *next; + char *fname; + int mode; + time_t time; +}; + +enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; + +char *TGZfname OF((const char *)); +void TGZnotfound OF((const char *)); + +int getoct OF((char *, int)); +char *strtime OF((time_t *)); +int setfiletime OF((char *, time_t)); +void push_attr OF((struct attr_item **, char *, int, time_t)); +void restore_attr OF((struct attr_item **)); + +int ExprMatch OF((char *, char *)); + +int makedir OF((char *)); +int matchname OF((int, int, char **, char *)); + +void error OF((const char *)); +int tar OF((gzFile, int, int, int, char **)); + +void help OF((int)); +int main OF((int, char **)); + +char *prog; + +const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL }; + +/* return the file name of the TGZ archive */ +/* or NULL if it does not exist */ + +char *TGZfname (const char *arcname) +{ + static char buffer[1024]; + int origlen,i; + + strcpy(buffer,arcname); + origlen = strlen(buffer); + + for (i=0; TGZsuffix[i]; i++) + { + strcpy(buffer+origlen,TGZsuffix[i]); + if (access(buffer,F_OK) == 0) + return buffer; + } + return NULL; +} + + +/* error message for the filename */ + +void TGZnotfound (const char *arcname) +{ + int i; + + fprintf(stderr,"%s: Couldn't find ",prog); + for (i=0;TGZsuffix[i];i++) + fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n", + arcname, + TGZsuffix[i]); + exit(1); +} + + +/* convert octal digits to int */ +/* on error return -1 */ + +int getoct (char *p,int width) +{ + int result = 0; + char c; + + while (width--) + { + c = *p++; + if (c == 0) + break; + if (c == ' ') + continue; + if (c < '0' || c > '7') + return -1; + result = result * 8 + (c - '0'); + } + return result; +} + + +/* convert time_t to string */ +/* use the "YYYY/MM/DD hh:mm:ss" format */ + +char *strtime (time_t *t) +{ + struct tm *local; + static char result[32]; + + local = localtime(t); + sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d", + local->tm_year+1900, local->tm_mon+1, local->tm_mday, + local->tm_hour, local->tm_min, local->tm_sec); + return result; +} + + +/* set file time */ + +int setfiletime (char *fname,time_t ftime) +{ +#ifdef WIN32 + static int isWinNT = -1; + SYSTEMTIME st; + FILETIME locft, modft; + struct tm *loctm; + HANDLE hFile; + int result; + + loctm = localtime(&ftime); + if (loctm == NULL) + return -1; + + st.wYear = (WORD)loctm->tm_year + 1900; + st.wMonth = (WORD)loctm->tm_mon + 1; + st.wDayOfWeek = (WORD)loctm->tm_wday; + st.wDay = (WORD)loctm->tm_mday; + st.wHour = (WORD)loctm->tm_hour; + st.wMinute = (WORD)loctm->tm_min; + st.wSecond = (WORD)loctm->tm_sec; + st.wMilliseconds = 0; + if (!SystemTimeToFileTime(&st, &locft) || + !LocalFileTimeToFileTime(&locft, &modft)) + return -1; + + if (isWinNT < 0) + isWinNT = (GetVersion() < 0x80000000) ? 1 : 0; + hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0), + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1; + CloseHandle(hFile); + return result; +#else + struct utimbuf settime; + + settime.actime = settime.modtime = ftime; + return utime(fname,&settime); +#endif +} + + +/* push file attributes */ + +void push_attr(struct attr_item **list,char *fname,int mode,time_t time) +{ + struct attr_item *item; + + item = (struct attr_item *)malloc(sizeof(struct attr_item)); + if (item == NULL) + error("Out of memory"); + item->fname = strdup(fname); + item->mode = mode; + item->time = time; + item->next = *list; + *list = item; +} + + +/* restore file attributes */ + +void restore_attr(struct attr_item **list) +{ + struct attr_item *item, *prev; + + for (item = *list; item != NULL; ) + { + setfiletime(item->fname,item->time); + chmod(item->fname,item->mode); + prev = item; + item = item->next; + free(prev); + } + *list = NULL; +} + + +/* match regular expression */ + +#define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) + +int ExprMatch (char *string,char *expr) +{ + while (1) + { + if (ISSPECIAL(*expr)) + { + if (*expr == '/') + { + if (*string != '\\' && *string != '/') + return 0; + string ++; expr++; + } + else if (*expr == '*') + { + if (*expr ++ == 0) + return 1; + while (*++string != *expr) + if (*string == 0) + return 0; + } + } + else + { + if (*string != *expr) + return 0; + if (*expr++ == 0) + return 1; + string++; + } + } +} + + +/* recursive mkdir */ +/* abort on ENOENT; ignore other errors like "directory already exists" */ +/* return 1 if OK */ +/* 0 on error */ + +int makedir (char *newdir) +{ + char *buffer = strdup(newdir); + char *p; + int len = strlen(buffer); + + if (len <= 0) { + free(buffer); + return 0; + } + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mkdir(buffer, 0755) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT)) + { + fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + + +int matchname (int arg,int argc,char **argv,char *fname) +{ + if (arg == argc) /* no arguments given (untgz tgzarchive) */ + return 1; + + while (arg < argc) + if (ExprMatch(fname,argv[arg++])) + return 1; + + return 0; /* ignore this for the moment being */ +} + + +/* tar file list or extract */ + +int tar (gzFile in,int action,int arg,int argc,char **argv) +{ + union tar_buffer buffer; + int len; + int err; + int getheader = 1; + int remaining = 0; + FILE *outfile = NULL; + char fname[BLOCKSIZE]; + int tarmode; + time_t tartime; + struct attr_item *attributes = NULL; + + if (action == TGZ_LIST) + printf(" date time size file\n" + " ---------- -------- --------- -------------------------------------\n"); + while (1) + { + len = gzread(in, &buffer, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + /* + * Always expect complete blocks to process + * the tar information. + */ + if (len != BLOCKSIZE) + { + action = TGZ_INVALID; /* force error exit */ + remaining = 0; /* force I/O cleanup */ + } + + /* + * If we have to get a tar header + */ + if (getheader >= 1) + { + /* + * if we met the end of the tar + * or the end-of-tar block, + * we are done + */ + if (len == 0 || buffer.header.name[0] == 0) + break; + + tarmode = getoct(buffer.header.mode,8); + tartime = (time_t)getoct(buffer.header.mtime,12); + if (tarmode == -1 || tartime == (time_t)-1) + { + buffer.header.name[0] = 0; + action = TGZ_INVALID; + } + + if (getheader == 1) + { + strncpy(fname,buffer.header.name,SHORTNAMESIZE); + if (fname[SHORTNAMESIZE-1] != 0) + fname[SHORTNAMESIZE] = 0; + } + else + { + /* + * The file name is longer than SHORTNAMESIZE + */ + if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0) + error("bad long name"); + getheader = 1; + } + + /* + * Act according to the type flag + */ + switch (buffer.header.typeflag) + { + case DIRTYPE: + if (action == TGZ_LIST) + printf(" %s %s\n",strtime(&tartime),fname); + if (action == TGZ_EXTRACT) + { + makedir(fname); + push_attr(&attributes,fname,tarmode,tartime); + } + break; + case REGTYPE: + case AREGTYPE: + remaining = getoct(buffer.header.size,12); + if (remaining == -1) + { + action = TGZ_INVALID; + break; + } + if (action == TGZ_LIST) + printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); + else if (action == TGZ_EXTRACT) + { + if (matchname(arg,argc,argv,fname)) + { + outfile = fopen(fname,"wb"); + if (outfile == NULL) { + /* try creating directory */ + char *p = strrchr(fname, '/'); + if (p != NULL) { + *p = '\0'; + makedir(fname); + *p = '/'; + outfile = fopen(fname,"wb"); + } + } + if (outfile != NULL) + printf("Extracting %s\n",fname); + else + fprintf(stderr, "%s: Couldn't create %s",prog,fname); + } + else + outfile = NULL; + } + getheader = 0; + break; + case GNUTYPE_LONGLINK: + case GNUTYPE_LONGNAME: + remaining = getoct(buffer.header.size,12); + if (remaining < 0 || remaining >= BLOCKSIZE) + { + action = TGZ_INVALID; + break; + } + len = gzread(in, fname, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining) + { + action = TGZ_INVALID; + break; + } + getheader = 2; + break; + default: + if (action == TGZ_LIST) + printf(" %s <---> %s\n",strtime(&tartime),fname); + break; + } + } + else + { + unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; + + if (outfile != NULL) + { + if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) + { + fprintf(stderr, + "%s: Error writing %s -- skipping\n",prog,fname); + fclose(outfile); + outfile = NULL; + remove(fname); + } + } + remaining -= bytes; + } + + if (remaining == 0) + { + getheader = 1; + if (outfile != NULL) + { + fclose(outfile); + outfile = NULL; + if (action != TGZ_INVALID) + push_attr(&attributes,fname,tarmode,tartime); + } + } + + /* + * Abandon if errors are found + */ + if (action == TGZ_INVALID) + { + error("broken archive"); + break; + } + } + + /* + * Restore file modes and time stamps + */ + restore_attr(&attributes); + + if (gzclose(in) != Z_OK) + error("failed gzclose"); + + return 0; +} + + +/* ============================================================ */ + +void help(int exitval) +{ + printf("untgz version 0.2.1\n" + " using zlib version %s\n\n", + zlibVersion()); + printf("Usage: untgz file.tgz extract all files\n" + " untgz file.tgz fname ... extract selected files\n" + " untgz -l file.tgz list archive contents\n" + " untgz -h display this help\n"); + exit(exitval); +} + +void error(const char *msg) +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + + +/* ============================================================ */ + +#if defined(WIN32) && defined(__GNUC__) +int _CRT_glob = 0; /* disable argument globbing in MinGW */ +#endif + +int main(int argc,char **argv) +{ + int action = TGZ_EXTRACT; + int arg = 1; + char *TGZfile; + gzFile *f; + + prog = strrchr(argv[0],'\\'); + if (prog == NULL) + { + prog = strrchr(argv[0],'/'); + if (prog == NULL) + { + prog = strrchr(argv[0],':'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + } + else + prog++; + } + else + prog++; + + if (argc == 1) + help(0); + + if (strcmp(argv[arg],"-l") == 0) + { + action = TGZ_LIST; + if (argc == ++arg) + help(0); + } + else if (strcmp(argv[arg],"-h") == 0) + { + help(0); + } + + if ((TGZfile = TGZfname(argv[arg])) == NULL) + TGZnotfound(argv[arg]); + + ++arg; + if ((action == TGZ_LIST) && (arg != argc)) + help(1); + +/* + * Process the TGZ file + */ + switch(action) + { + case TGZ_LIST: + case TGZ_EXTRACT: + f = gzopen(TGZfile,"rb"); + if (f == NULL) + { + fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile); + return 1; + } + exit(tar(f, action, arg, argc, argv)); + break; + + default: + error("Unknown option"); + exit(1); + } + + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/readme.txt new file mode 100644 index 00000000..ebe13bf1 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/readme.txt @@ -0,0 +1,60 @@ +Building instructions for the DLL versions of Zlib 1.2.4 +======================================================== + +This directory contains projects that build zlib and minizip using +Microsoft Visual C++ 9.0/10.0, and Visual C++ . + +You don't need to build these projects yourself. You can download the +binaries from: + http://www.winimage.com/zLibDll + +More information can be found at this site. + +first compile assembly code by running +bld_ml64.bat in contrib\masmx64 +bld_ml32.bat in contrib\masmx86 + + + + +Build instructions for Visual Studio 2008 (32 bits or 64 bits) +-------------------------------------------------------------- +- Uncompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc9\zlibvc.sln with Microsoft Visual C++ 2008.0 +- Or run: vcbuild /rebuild contrib\vstudio\vc9\zlibvc.sln "Release|Win32" + +Build instructions for Visual Studio 2010 (32 bits or 64 bits) +-------------------------------------------------------------- +- Uncompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc10\zlibvc.sln with Microsoft Visual C++ 2010.0 + + +Important +--------- +- To use zlibwapi.dll in your application, you must define the + macro ZLIB_WINAPI when compiling your application's source files. + + +Additional notes +---------------- +- This DLL, named zlibwapi.dll, is compatible to the old zlib.dll built + by Gilles Vollant from the zlib 1.1.x sources, and distributed at + http://www.winimage.com/zLibDll + It uses the WINAPI calling convention for the exported functions, and + includes the minizip functionality. If your application needs that + particular build of zlib.dll, you can rename zlibwapi.dll to zlib.dll. + +- The new DLL was renamed because there exist several incompatible + versions of zlib.dll on the Internet. + +- There is also an official DLL build of zlib, named zlib1.dll. This one + is exporting the functions using the CDECL convention. See the file + win32\DLL_FAQ.txt found in this zlib distribution. + +- There used to be a ZLIB_DLL macro in zlib 1.1.x, but now this symbol + has a slightly different effect. To avoid compatibility problems, do + not define it here. + + +Gilles Vollant +info@winimage.com diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj new file mode 100644 index 00000000..74e15c90 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj @@ -0,0 +1,310 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters new file mode 100644 index 00000000..0b2a3de2 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {048af943-022b-4db6-beeb-a54c34774ee2} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c1d600d2-888f-4aea-b73e-8b0dd9befa0c} + h;hpp;hxx;hm;inl;inc + + + {0844199a-966b-4f19-81db-1e0125e141b9} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj.user b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/miniunz.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj new file mode 100644 index 00000000..917e1565 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj @@ -0,0 +1,307 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters new file mode 100644 index 00000000..dd73cd31 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {c0419b40-bf50-40da-b153-ff74215b79de} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {bb87b070-735b-478e-92ce-7383abb2f36c} + h;hpp;hxx;hm;inl;inc + + + {f46ab6a6-548f-43cb-ae96-681abb5bd5db} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj.user b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/minizip.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj new file mode 100644 index 00000000..9088d176 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj @@ -0,0 +1,420 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + true + + + Application + true + + + Application + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + EditAndContinue + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters new file mode 100644 index 00000000..249daa89 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters @@ -0,0 +1,58 @@ + + + + + {c1f6a2e3-5da5-4955-8653-310d3efe05a9} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2aaffdc-2c95-4d6f-8466-4bec5890af2c} + h;hpp;hxx;hm;inl;inc + + + {c274fe07-05f2-461c-964b-f6341e4e7eb5} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj.user b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlib.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj new file mode 100644 index 00000000..2d628158 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj @@ -0,0 +1,310 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters new file mode 100644 index 00000000..53a8693b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {fa61a89f-93fc-4c89-b29e-36224b7592f4} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {d4b85da0-2ba2-4934-b57f-e2584e3848ee} + h;hpp;hxx;hm;inl;inc + + + {e573e075-00bd-4a7d-bd67-a8cc9bfc5aca} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.user b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlib.rc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlib.rc new file mode 100644 index 00000000..f8224508 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,5,0 + PRODUCTVERSION 1,2,5,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.5\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlib.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2010 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj new file mode 100644 index 00000000..2682fca2 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj @@ -0,0 +1,457 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebug + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters new file mode 100644 index 00000000..c8c7f7ea --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters @@ -0,0 +1,77 @@ + + + + + {174213f6-7f66-4ae8-a3a8-a1e0a1e6ffdd} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.user b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.def b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.def new file mode 100644 index 00000000..0269ef72 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.def @@ -0,0 +1,130 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.24 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.sln b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.sln new file mode 100644 index 00000000..6f6ffd5e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.sln @@ -0,0 +1,135 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj new file mode 100644 index 00000000..98623989 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj @@ -0,0 +1,659 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebug + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters new file mode 100644 index 00000000..180b71cd --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters @@ -0,0 +1,118 @@ + + + + + {07934a85-8b61-443d-a0ee-b2eedb74f3cd} + cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 + + + {1d99675b-433d-4a21-9e50-ed4ab8b19762} + h;hpp;hxx;hm;inl;fi;fd + + + {431c0958-fa71-44d0-9084-2d19d100c0cc} + ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.user b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/miniunz.vcproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/miniunz.vcproj new file mode 100644 index 00000000..7da32b91 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/miniunz.vcproj @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/minizip.vcproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/minizip.vcproj new file mode 100644 index 00000000..e57e07d9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/minizip.vcproj @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/testzlib.vcproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/testzlib.vcproj new file mode 100644 index 00000000..9cb0bf87 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/testzlib.vcproj @@ -0,0 +1,852 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/testzlibdll.vcproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/testzlibdll.vcproj new file mode 100644 index 00000000..b1ddde05 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/testzlibdll.vcproj @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlib.rc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlib.rc new file mode 100644 index 00000000..f8224508 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,5,0 + PRODUCTVERSION 1,2,5,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.5\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlib.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2010 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibstat.vcproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibstat.vcproj new file mode 100644 index 00000000..61c76c7c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibstat.vcproj @@ -0,0 +1,835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.def b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.def new file mode 100644 index 00000000..0269ef72 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.def @@ -0,0 +1,130 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.24 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.sln b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.sln new file mode 100644 index 00000000..b4829671 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.sln @@ -0,0 +1,144 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestZlibDll", "testzlibdll.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.vcproj b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.vcproj new file mode 100644 index 00000000..c9a89471 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/contrib/vstudio/vc9/zlibvc.vcproj @@ -0,0 +1,1156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/crc32.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/crc32.c new file mode 100644 index 00000000..17a6fbf0 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/crc32.c @@ -0,0 +1,442 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/crc32.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/crc32.h new file mode 100644 index 00000000..8053b611 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/deflate.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/deflate.c new file mode 100644 index 00000000..617673f6 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/deflate.c @@ -0,0 +1,1834 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > s->w_size) { + length = s->w_size; + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_BLOCK); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong complen, wraplen; + Bytef *str; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (strm == Z_NULL || strm->state == Z_NULL) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return conservative bound */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + (s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush)); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (int)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/deflate.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/deflate.h new file mode 100644 index 00000000..7867e58f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/deflate.h @@ -0,0 +1,342 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2010 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h 246 2010-04-23 10:54:55Z nijtmans $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/algorithm.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/algorithm.txt new file mode 100644 index 00000000..34960bdd --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend too much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://www.ietf.org/rfc/rfc1951.txt diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1950.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1950.txt new file mode 100644 index 00000000..ce6428a0 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1950.txt @@ -0,0 +1,619 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1950 Aladdin Enterprises +Category: Informational J-L. Gailly + Info-ZIP + May 1996 + + + ZLIB Compressed Data Format Specification version 3.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch and Jean-Loup Gailly + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format. The + data can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a priori + bounded amount of intermediate storage. The format presently uses + the DEFLATE compression method but can be easily extended to use + other compression methods. It can be implemented readily in a manner + not covered by patents. This specification also defines the ADLER-32 + checksum (an extension and improvement of the Fletcher checksum), + used for detection of data corruption, and provides an algorithm for + computing it. + + + + +Deutsch & Gailly Informational [Page 1] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 3 + 2.1. Overall conventions ....................................... 3 + 2.2. Data format ............................................... 4 + 2.3. Compliance ................................................ 7 + 3. References ..................................................... 7 + 4. Source code .................................................... 8 + 5. Security Considerations ........................................ 8 + 6. Acknowledgements ............................................... 8 + 7. Authors' Addresses ............................................. 8 + 8. Appendix: Rationale ............................................ 9 + 9. Appendix: Sample code ..........................................10 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence can + be used in data communications or similar structures such as + Unix filters; + + * Can use a number of different compression methods; + + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely. + + The data format defined by this specification does not attempt to + allow random access to compressed data. + + + + + + + +Deutsch & Gailly Informational [Page 2] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into zlib format and/or decompress data from zlib + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compressed data format that can be + used for in-memory compression of a sequence of arbitrary bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below, for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + Version 3.1 was the first public release of this specification. + In version 3.2, some terminology was changed and the Adler-32 + sample code was rewritten for clarity. In version 3.3, the + support for a preset dictionary was introduced, and the + specification was converted to RFC style. + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + + + +Deutsch & Gailly Informational [Page 3] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the MOST-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00000010|00001000| + +--------+--------+ + ^ ^ + | | + | + less significant byte = 8 + + more significant byte = 2 x 256 + + 2.2. Data format + + A zlib stream has the following structure: + + 0 1 + +---+---+ + |CMF|FLG| (more-->) + +---+---+ + + + + + + + + +Deutsch & Gailly Informational [Page 4] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + (if FLG.FDICT set) + + 0 1 2 3 + +---+---+---+---+ + | DICTID | (more-->) + +---+---+---+---+ + + +=====================+---+---+---+---+ + |...compressed data...| ADLER32 | + +=====================+---+---+---+---+ + + Any data which may appear after ADLER32 are not part of the zlib + stream. + + CMF (Compression Method and flags) + This byte is divided into a 4-bit compression method and a 4- + bit information field depending on the compression method. + + bits 0 to 3 CM Compression method + bits 4 to 7 CINFO Compression info + + CM (Compression method) + This identifies the compression method used in the file. CM = 8 + denotes the "deflate" compression method with a window size up + to 32K. This is the method used by gzip and PNG (see + references [1] and [2] in Chapter 3, below, for the reference + documents). CM = 15 is reserved. It might be used in a future + version of this specification to indicate the presence of an + extra field before the compressed data. + + CINFO (Compression info) + For CM = 8, CINFO is the base-2 logarithm of the LZ77 window + size, minus eight (CINFO=7 indicates a 32K window size). Values + of CINFO above 7 are not allowed in this version of the + specification. CINFO is not defined in this specification for + CM not equal to 8. + + FLG (FLaGs) + This flag byte is divided as follows: + + bits 0 to 4 FCHECK (check bits for CMF and FLG) + bit 5 FDICT (preset dictionary) + bits 6 to 7 FLEVEL (compression level) + + The FCHECK value must be such that CMF and FLG, when viewed as + a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG), + is a multiple of 31. + + + + +Deutsch & Gailly Informational [Page 5] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + FDICT (Preset dictionary) + If FDICT is set, a DICT dictionary identifier is present + immediately after the FLG byte. The dictionary is a sequence of + bytes which are initially fed to the compressor without + producing any compressed output. DICT is the Adler-32 checksum + of this sequence of bytes (see the definition of ADLER32 + below). The decompressor can use this identifier to determine + which dictionary has been used by the compressor. + + FLEVEL (Compression level) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + 0 - compressor used fastest algorithm + 1 - compressor used fast algorithm + 2 - compressor used default algorithm + 3 - compressor used maximum compression, slowest algorithm + + The information in FLEVEL is not needed for decompression; it + is there to indicate if recompression might be worthwhile. + + compressed data + For compression method 8, the compressed data is stored in the + deflate compressed data format as described in the document + "DEFLATE Compressed Data Format Specification" by L. Peter + Deutsch. (See reference [3] in Chapter 3, below) + + Other compressed data formats are not specified in this version + of the zlib specification. + + ADLER32 (Adler-32 checksum) + This contains a checksum value of the uncompressed data + (excluding any dictionary data) computed according to Adler-32 + algorithm. This algorithm is a 32-bit extension and improvement + of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 + standard. See references [4] and [5] in Chapter 3, below) + + Adler-32 is composed of two sums accumulated per byte: s1 is + the sum of all bytes, s2 is the sum of all s1 values. Both sums + are done modulo 65521. s1 is initialized to 1, s2 to zero. The + Adler-32 checksum is stored as s2*65536 + s1 in most- + significant-byte first (network) order. + + + + + + + + +Deutsch & Gailly Informational [Page 6] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 2.3. Compliance + + A compliant compressor must produce streams with correct CMF, FLG + and ADLER32, but need not support preset dictionaries. When the + zlib data format is used as part of another standard data format, + the compressor may use only preset dictionaries that are specified + by this other data format. If this other format does not use the + preset dictionary feature, the compressor must not set the FDICT + flag. + + A compliant decompressor must check CMF, FLG, and ADLER32, and + provide an error indication if any of these have incorrect values. + A compliant decompressor must give an error indication if CM is + not one of the values defined in this specification (only the + value 8 is permitted in this version), since another value could + indicate the presence of new features that would cause subsequent + data to be interpreted incorrectly. A compliant decompressor must + give an error indication if FDICT is set and DICTID is not the + identifier of a known preset dictionary. A decompressor may + ignore FLEVEL and still be compliant. When the zlib data format + is being used as a part of another standard format, a compliant + decompressor must support all the preset dictionaries specified by + the other format. When the other format does not use the preset + dictionary feature, a compliant decompressor must reject any + stream in which the FDICT flag is set. + +3. References + + [1] Deutsch, L.P.,"GZIP Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [2] Thomas Boutell, "PNG (Portable Network Graphics) specification", + available in ftp://ftp.uu.net/graphics/png/documents/ + + [3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Fletcher, J. G., "An Arithmetic Checksum for Serial + Transmissions," IEEE Transactions on Communications, Vol. COM-30, + No. 1, January 1982, pp. 247-252. + + [5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms," + November, 1993, pp. 144, 145. (Available from + gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073. + + + + + + + +Deutsch & Gailly Informational [Page 7] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +4. Source code + + Source code for a C language implementation of a "zlib" compliant + library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +5. Security Considerations + + A decoder that fails to check the ADLER32 checksum value may be + subject to undetected data corruption. + +6. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly and Mark Adler designed the zlib format and wrote + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +7. Authors' Addresses + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + + Jean-Loup Gailly + + EMail: + + Questions about the technical content of this specification can be + sent by email to + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + +Deutsch & Gailly Informational [Page 8] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +8. Appendix: Rationale + + 8.1. Preset dictionaries + + A preset dictionary is specially useful to compress short input + sequences. The compressor can take advantage of the dictionary + context to encode the input in a more compact manner. The + decompressor can be initialized with the appropriate context by + virtually decompressing a compressed version of the dictionary + without producing any output. However for certain compression + algorithms such as the deflate algorithm this operation can be + achieved without actually performing any decompression. + + The compressor and the decompressor must use exactly the same + dictionary. The dictionary may be fixed or may be chosen among a + certain number of predefined dictionaries, according to the kind + of input data. The decompressor can determine which dictionary has + been chosen by the compressor by checking the dictionary + identifier. This document does not specify the contents of + predefined dictionaries, since the optimal dictionaries are + application specific. Standard data formats using this feature of + the zlib specification must precisely define the allowed + dictionaries. + + 8.2. The Adler-32 algorithm + + The Adler-32 algorithm is much faster than the CRC32 algorithm yet + still provides an extremely low probability of undetected errors. + + The modulo on unsigned long accumulators can be delayed for 5552 + bytes, so the modulo operation time is negligible. If the bytes + are a, b, c, the second sum is 3a + 2b + c + 3, and so is position + and order sensitive, unlike the first sum, which is just a + checksum. That 65521 is prime is important to avoid a possible + large class of two-byte errors that leave the check unchanged. + (The Fletcher checksum uses 255, which is not prime and which also + makes the Fletcher check insensitive to single byte changes 0 <-> + 255.) + + The sum s1 is initialized to 1 instead of zero to make the length + of the sequence part of s2, so that the length does not have to be + checked separately. (Any sequence of zeroes has a Fletcher + checksum of zero.) + + + + + + + + +Deutsch & Gailly Informational [Page 9] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +9. Appendix: Sample code + + The following C code computes the Adler-32 checksum of a data buffer. + It is written for clarity, not for speed. The sample code is in the + ANSI C programming language. Non C users may find it easier to read + with these hints: + + & Bitwise AND operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero bit(s) + at the left. + << Bitwise left shift operator. Left shift inserts zero + bit(s) at the right. + ++ "n++" increments the variable n. + % modulo operator: a % b is the remainder of a divided by b. + + #define BASE 65521 /* largest prime smaller than 65536 */ + + /* + Update a running Adler-32 checksum with the bytes buf[0..len-1] + and return the updated checksum. The Adler-32 checksum should be + initialized to 1. + + Usage example: + + unsigned long adler = 1L; + + while (read_buffer(buffer, length) != EOF) { + adler = update_adler32(adler, buffer, length); + } + if (adler != original_adler) error(); + */ + unsigned long update_adler32(unsigned long adler, + unsigned char *buf, int len) + { + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++) { + s1 = (s1 + buf[n]) % BASE; + s2 = (s2 + s1) % BASE; + } + return (s2 << 16) + s1; + } + + /* Return the adler32 of the bytes buf[0..len-1] */ + + + + +Deutsch & Gailly Informational [Page 10] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + unsigned long adler32(unsigned char *buf, int len) + { + return update_adler32(1L, buf, len); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch & Gailly Informational [Page 11] + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1951.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1951.txt new file mode 100644 index 00000000..403c8c72 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1951.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1951 Aladdin Enterprises +Category: Informational May 1996 + + + DEFLATE Compressed Data Format Specification version 1.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that + compresses data using a combination of the LZ77 algorithm and Huffman + coding, with efficiency comparable to the best currently available + general-purpose compression methods. The data can be produced or + consumed, even for an arbitrarily long sequentially presented input + data stream, using only an a priori bounded amount of intermediate + storage. The format can be implemented readily in a manner not + covered by patents. + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 4 + 2. Compressed representation overview ............................. 4 + 3. Detailed specification ......................................... 5 + 3.1. Overall conventions ....................................... 5 + 3.1.1. Packing into bytes .................................. 5 + 3.2. Compressed block format ................................... 6 + 3.2.1. Synopsis of prefix and Huffman coding ............... 6 + 3.2.2. Use of Huffman coding in the "deflate" format ....... 7 + 3.2.3. Details of block format ............................. 9 + 3.2.4. Non-compressed blocks (BTYPE=00) ................... 11 + 3.2.5. Compressed blocks (length and distance codes) ...... 11 + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12 + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13 + 3.3. Compliance ............................................... 14 + 4. Compression algorithm details ................................. 14 + 5. References .................................................... 16 + 6. Security Considerations ....................................... 16 + 7. Source code ................................................... 16 + 8. Acknowledgements .............................................. 16 + 9. Author's Address .............................................. 17 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence + can be used in data communications or similar structures + such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + + + +Deutsch Informational [Page 2] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + The data format defined by this specification does not attempt to: + + * Allow random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well + as the best currently available specialized algorithms. + + A simple counting argument shows that no lossless compression + algorithm can compress every possible input data set. For the + format defined here, the worst case expansion is 5 bytes per 32K- + byte block, i.e., a size increase of 0.015% for large data sets. + English text usually compresses by a factor of 2.5 to 3; + executable files usually compress somewhat less; graphical data + such as raster images may compress much more. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into "deflate" format and/or decompress data from + "deflate" format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. Familiarity with the technique of Huffman coding + is helpful but not required. + + 1.3. Scope + + The specification specifies a method for representing a sequence + of bytes as a (usually shorter) sequence of bits, and a method for + packing the latter bit sequence into bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + Byte: 8 bits stored or transmitted as a unit (same as an octet). + For this specification, a byte is exactly 8 bits, even on machines + + + +Deutsch Informational [Page 3] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + which store a character on a number of bits different from eight. + See below, for the numbering of bits within a byte. + + String: a sequence of arbitrary bytes. + + 1.6. Changes from previous versions + + There have been no technical changes to the deflate format since + version 1.1 of this specification. In version 1.2, some + terminology was changed. Version 1.3 is a conversion of the + specification to RFC style. + +2. Compressed representation overview + + A compressed data set consists of a series of blocks, corresponding + to successive blocks of input data. The block sizes are arbitrary, + except that non-compressible blocks are limited to 65,535 bytes. + + Each block is compressed using a combination of the LZ77 algorithm + and Huffman coding. The Huffman trees for each block are independent + of those for previous or subsequent blocks; the LZ77 algorithm may + use a reference to a duplicated string occurring in a previous block, + up to 32K input bytes before. + + Each block consists of two parts: a pair of Huffman code trees that + describe the representation of the compressed data part, and a + compressed data part. (The Huffman trees themselves are compressed + using Huffman encoding.) The compressed data consists of a series of + elements of two types: literal bytes (of strings that have not been + detected as duplicated within the previous 32K input bytes), and + pointers to duplicated strings, where a pointer is represented as a + pair . The representation used in the + "deflate" format limits distances to 32K bytes and lengths to 258 + bytes, but does not limit the size of a block, except for + uncompressible blocks, which are limited as noted above. + + Each type of value (literals, distances, and lengths) in the + compressed data is represented using a Huffman code, using one code + tree for literals and lengths and a separate code tree for distances. + The code trees for each block appear in a compact form just before + the compressed data for that block. + + + + + + + + + + +Deutsch Informational [Page 4] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +3. Detailed specification + + 3.1. Overall conventions In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + 3.1.1. Packing into bytes + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, + since the final data format described here is byte- rather than + + + +Deutsch Informational [Page 5] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + bit-oriented. However, we describe the compressed block format + in below, as a sequence of data elements of various bit + lengths, not a sequence of bytes. We must therefore specify + how to pack these data elements into bytes to form the final + compressed byte sequence: + + * Data elements are packed into bytes in order of + increasing bit number within the byte, i.e., starting + with the least-significant bit of the byte. + * Data elements other than Huffman codes are packed + starting with the least-significant bit of the data + element. + * Huffman codes are packed starting with the most- + significant bit of the code. + + In other words, if one were to print out the compressed data as + a sequence of bytes, starting with the first byte at the + *right* margin and proceeding to the *left*, with the most- + significant bit of each byte on the left as usual, one would be + able to parse the result from right to left, with fixed-width + elements in the correct MSB-to-LSB order and Huffman codes in + bit-reversed order (i.e., with the first bit of the code in the + relative LSB position). + + 3.2. Compressed block format + + 3.2.1. Synopsis of prefix and Huffman coding + + Prefix coding represents symbols from an a priori known + alphabet by bit sequences (codes), one code for each symbol, in + a manner such that different symbols may be represented by bit + sequences of different lengths, but a parser can always parse + an encoded string unambiguously symbol-by-symbol. + + We define a prefix code in terms of a binary tree in which the + two edges descending from each non-leaf node are labeled 0 and + 1 and in which the leaf nodes correspond one-for-one with (are + labeled with) the symbols of the alphabet; then the code for a + symbol is the sequence of 0's and 1's on the edges leading from + the root to the leaf labeled with that symbol. For example: + + + + + + + + + + + +Deutsch Informational [Page 6] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + /\ Symbol Code + 0 1 ------ ---- + / \ A 00 + /\ B B 1 + 0 1 C 011 + / \ D 010 + A /\ + 0 1 + / \ + D C + + A parser can decode the next symbol from an encoded input + stream by walking down the tree from the root, at each step + choosing the edge corresponding to the next input bit. + + Given an alphabet with known symbol frequencies, the Huffman + algorithm allows the construction of an optimal prefix code + (one which represents strings with those symbol frequencies + using the fewest bits of any possible prefix codes for that + alphabet). Such a code is called a Huffman code. (See + reference [1] in Chapter 5, references for additional + information on Huffman codes.) + + Note that in the "deflate" format, the Huffman codes for the + various alphabets must not exceed certain maximum code lengths. + This constraint complicates the algorithm for computing code + lengths from symbol frequencies. Again, see Chapter 5, + references for details. + + 3.2.2. Use of Huffman coding in the "deflate" format + + The Huffman codes used for each alphabet in the "deflate" + format have two additional rules: + + * All codes of a given bit length have lexicographically + consecutive values, in the same order as the symbols + they represent; + + * Shorter codes lexicographically precede longer codes. + + + + + + + + + + + + +Deutsch Informational [Page 7] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + We could recode the example above to follow this rule as + follows, assuming that the order of the alphabet is ABCD: + + Symbol Code + ------ ---- + A 10 + B 0 + C 110 + D 111 + + I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are + lexicographically consecutive. + + Given this rule, we can define the Huffman code for an alphabet + just by giving the bit lengths of the codes for each symbol of + the alphabet in order; this is sufficient to determine the + actual codes. In our example, the code is completely defined + by the sequence of bit lengths (2, 1, 3, 3). The following + algorithm generates the codes as integers, intended to be read + from most- to least-significant bit. The code lengths are + initially in tree[I].Len; the codes are produced in + tree[I].Code. + + 1) Count the number of codes for each code length. Let + bl_count[N] be the number of codes of length N, N >= 1. + + 2) Find the numerical value of the smallest code for each + code length: + + code = 0; + bl_count[0] = 0; + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = code; + } + + 3) Assign numerical values to all codes, using consecutive + values for all codes of the same length with the base + values determined at step 2. Codes that are never used + (which have a bit length of zero) must not be assigned a + value. + + for (n = 0; n <= max_code; n++) { + len = tree[n].Len; + if (len != 0) { + tree[n].Code = next_code[len]; + next_code[len]++; + } + + + +Deutsch Informational [Page 8] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + } + + Example: + + Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3, + 3, 2, 4, 4). After step 1, we have: + + N bl_count[N] + - ----------- + 2 1 + 3 5 + 4 2 + + Step 2 computes the following next_code values: + + N next_code[N] + - ------------ + 1 0 + 2 0 + 3 2 + 4 14 + + Step 3 produces the following code values: + + Symbol Length Code + ------ ------ ---- + A 3 010 + B 3 011 + C 3 100 + D 3 101 + E 3 110 + F 2 00 + G 4 1110 + H 4 1111 + + 3.2.3. Details of block format + + Each block of compressed data begins with 3 header bits + containing the following data: + + first bit BFINAL + next 2 bits BTYPE + + Note that the header bits do not necessarily begin on a byte + boundary, since a block does not necessarily occupy an integral + number of bytes. + + + + + +Deutsch Informational [Page 9] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + BFINAL is set if and only if this is the last block of the data + set. + + BTYPE specifies how the data are compressed, as follows: + + 00 - no compression + 01 - compressed with fixed Huffman codes + 10 - compressed with dynamic Huffman codes + 11 - reserved (error) + + The only difference between the two compressed cases is how the + Huffman codes for the literal/length and distance alphabets are + defined. + + In all cases, the decoding algorithm for the actual data is as + follows: + + do + read block header from input stream. + if stored with no compression + skip any remaining bits in current partially + processed byte + read LEN and NLEN (see next section) + copy LEN bytes of data to output + otherwise + if compressed with dynamic Huffman codes + read representation of code trees (see + subsection below) + loop (until end of block code recognized) + decode literal/length value from input stream + if value < 256 + copy value (literal byte) to output stream + otherwise + if value = end of block (256) + break from loop + otherwise (value = 257..285) + decode distance from input stream + + move backwards distance bytes in the output + stream, and copy length bytes from this + position to the output stream. + end loop + while not last block + + Note that a duplicated string reference may refer to a string + in a previous block; i.e., the backward distance may cross one + or more block boundaries. However a distance cannot refer past + the beginning of the output stream. (An application using a + + + +Deutsch Informational [Page 10] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + preset dictionary might discard part of the output stream; a + distance can refer to that part of the output stream anyway) + Note also that the referenced string may overlap the current + position; for example, if the last 2 bytes decoded have values + X and Y, a string reference with + adds X,Y,X,Y,X to the output stream. + + We now specify each compression method in turn. + + 3.2.4. Non-compressed blocks (BTYPE=00) + + Any bits of input up to the next byte boundary are ignored. + The rest of the block consists of the following information: + + 0 1 2 3 4... + +---+---+---+---+================================+ + | LEN | NLEN |... LEN bytes of literal data...| + +---+---+---+---+================================+ + + LEN is the number of data bytes in the block. NLEN is the + one's complement of LEN. + + 3.2.5. Compressed blocks (length and distance codes) + + As noted above, encoded data blocks in the "deflate" format + consist of sequences of symbols drawn from three conceptually + distinct alphabets: either literal bytes, from the alphabet of + byte values (0..255), or pairs, + where the length is drawn from (3..258) and the distance is + drawn from (1..32,768). In fact, the literal and length + alphabets are merged into a single alphabet (0..285), where + values 0..255 represent literal bytes, the value 256 indicates + end-of-block, and values 257..285 represent length codes + (possibly in conjunction with extra bits following the symbol + code) as follows: + + + + + + + + + + + + + + + + +Deutsch Informational [Page 11] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + Extra Extra Extra + Code Bits Length(s) Code Bits Lengths Code Bits Length(s) + ---- ---- ------ ---- ---- ------- ---- ---- ------- + 257 0 3 267 1 15,16 277 4 67-82 + 258 0 4 268 1 17,18 278 4 83-98 + 259 0 5 269 2 19-22 279 4 99-114 + 260 0 6 270 2 23-26 280 4 115-130 + 261 0 7 271 2 27-30 281 5 131-162 + 262 0 8 272 2 31-34 282 5 163-194 + 263 0 9 273 3 35-42 283 5 195-226 + 264 0 10 274 3 43-50 284 5 227-257 + 265 1 11,12 275 3 51-58 285 0 258 + 266 1 13,14 276 3 59-66 + + The extra bits should be interpreted as a machine integer + stored with the most-significant bit first, e.g., bits 1110 + represent the value 14. + + Extra Extra Extra + Code Bits Dist Code Bits Dist Code Bits Distance + ---- ---- ---- ---- ---- ------ ---- ---- -------- + 0 0 1 10 4 33-48 20 9 1025-1536 + 1 0 2 11 4 49-64 21 9 1537-2048 + 2 0 3 12 5 65-96 22 10 2049-3072 + 3 0 4 13 5 97-128 23 10 3073-4096 + 4 1 5,6 14 6 129-192 24 11 4097-6144 + 5 1 7,8 15 6 193-256 25 11 6145-8192 + 6 2 9-12 16 7 257-384 26 12 8193-12288 + 7 2 13-16 17 7 385-512 27 12 12289-16384 + 8 3 17-24 18 8 513-768 28 13 16385-24576 + 9 3 25-32 19 8 769-1024 29 13 24577-32768 + + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) + + The Huffman codes for the two alphabets are fixed, and are not + represented explicitly in the data. The Huffman code lengths + for the literal/length alphabet are: + + Lit Value Bits Codes + --------- ---- ----- + 0 - 143 8 00110000 through + 10111111 + 144 - 255 9 110010000 through + 111111111 + 256 - 279 7 0000000 through + 0010111 + 280 - 287 8 11000000 through + 11000111 + + + +Deutsch Informational [Page 12] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + The code lengths are sufficient to generate the actual codes, + as described above; we show the codes in the table for added + clarity. Literal/length values 286-287 will never actually + occur in the compressed data, but participate in the code + construction. + + Distance codes 0-31 are represented by (fixed-length) 5-bit + codes, with possible additional bits as shown in the table + shown in Paragraph 3.2.5, above. Note that distance codes 30- + 31 will never actually occur in the compressed data. + + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) + + The Huffman codes for the two alphabets appear in the block + immediately after the header bits and before the actual + compressed data, first the literal/length code and then the + distance code. Each code is defined by a sequence of code + lengths, as discussed in Paragraph 3.2.2, above. For even + greater compactness, the code length sequences themselves are + compressed using a Huffman code. The alphabet for code lengths + is as follows: + + 0 - 15: Represent code lengths of 0 - 15 + 16: Copy the previous code length 3 - 6 times. + The next 2 bits indicate repeat length + (0 = 3, ... , 3 = 6) + Example: Codes 8, 16 (+2 bits 11), + 16 (+2 bits 10) will expand to + 12 code lengths of 8 (1 + 6 + 5) + 17: Repeat a code length of 0 for 3 - 10 times. + (3 bits of length) + 18: Repeat a code length of 0 for 11 - 138 times + (7 bits of length) + + A code length of 0 indicates that the corresponding symbol in + the literal/length or distance alphabet will not occur in the + block, and should not participate in the Huffman code + construction algorithm given earlier. If only one distance + code is used, it is encoded using one bit, not zero bits; in + this case there is a single code length of one, with one unused + code. One distance code of zero bits means that there are no + distance codes used at all (the data is all literals). + + We can now define the format of the block: + + 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) + 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) + 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) + + + +Deutsch Informational [Page 13] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + (HCLEN + 4) x 3 bits: code lengths for the code length + alphabet given just above, in the order: 16, 17, 18, + 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + + These code lengths are interpreted as 3-bit integers + (0-7); as above, a code length of 0 means the + corresponding symbol (literal/length or distance code + length) is not used. + + HLIT + 257 code lengths for the literal/length alphabet, + encoded using the code length Huffman code + + HDIST + 1 code lengths for the distance alphabet, + encoded using the code length Huffman code + + The actual compressed data of the block, + encoded using the literal/length and distance Huffman + codes + + The literal/length symbol 256 (end of data), + encoded using the literal/length Huffman code + + The code length repeat codes can cross from HLIT + 257 to the + HDIST + 1 code lengths. In other words, all code lengths form + a single sequence of HLIT + HDIST + 258 values. + + 3.3. Compliance + + A compressor may limit further the ranges of values specified in + the previous section and still be compliant; for example, it may + limit the range of backward pointers to some value smaller than + 32K. Similarly, a compressor may limit the size of blocks so that + a compressible block fits in memory. + + A compliant decompressor must accept the full range of possible + values defined in the previous section, and must accept blocks of + arbitrary size. + +4. Compression algorithm details + + While it is the intent of this document to define the "deflate" + compressed data format without reference to any particular + compression algorithm, the format is related to the compressed + formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below); + since many variations of LZ77 are patented, it is strongly + recommended that the implementor of a compressor follow the general + algorithm presented here, which is known not to be patented per se. + The material in this section is not part of the definition of the + + + +Deutsch Informational [Page 14] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + specification per se, and a compressor need not follow it in order to + be compliant. + + The compressor terminates a block when it determines that starting a + new block with fresh trees would be useful, or when the block size + fills up the compressor's block buffer. + + The compressor uses a chained hash table to find duplicated strings, + using a hash function that operates on 3-byte sequences. At any + given point during compression, let XYZ be the next 3 input bytes to + be examined (not necessarily all different, of course). First, the + compressor examines the hash chain for XYZ. If the chain is empty, + the compressor simply writes out X as a literal byte and advances one + byte in the input. If the hash chain is not empty, indicating that + the sequence XYZ (or, if we are unlucky, some other 3 bytes with the + same hash function value) has occurred recently, the compressor + compares all strings on the XYZ hash chain with the actual input data + sequence starting at the current point, and selects the longest + match. + + The compressor searches the hash chains starting with the most recent + strings, to favor small distances and thus take advantage of the + Huffman encoding. The hash chains are singly linked. There are no + deletions from the hash chains; the algorithm simply discards matches + that are too old. To avoid a worst-case situation, very long hash + chains are arbitrarily truncated at a certain length, determined by a + run-time parameter. + + To improve overall compression, the compressor optionally defers the + selection of matches ("lazy matching"): after a match of length N has + been found, the compressor searches for a longer match starting at + the next input byte. If it finds a longer match, it truncates the + previous match to a length of one (thus producing a single literal + byte) and then emits the longer match. Otherwise, it emits the + original match, and, as described above, advances N bytes before + continuing. + + Run-time parameters also control this "lazy match" procedure. If + compression ratio is most important, the compressor attempts a + complete second search regardless of the length of the first match. + In the normal case, if the current match is "long enough", the + compressor reduces the search for a longer match, thus speeding up + the process. If speed is most important, the compressor inserts new + strings in the hash table only when no match was found, or when the + match is not "too long". This degrades the compression ratio but + saves time since there are both fewer insertions and fewer searches. + + + + + +Deutsch Informational [Page 15] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +5. References + + [1] Huffman, D. A., "A Method for the Construction of Minimum + Redundancy Codes", Proceedings of the Institute of Radio + Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101. + + [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data + Compression", IEEE Transactions on Information Theory, Vol. 23, + No. 3, pp. 337-343. + + [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources, + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources, + available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/ + + [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix + encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169. + + [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes," + Comm. ACM, 33,4, April 1990, pp. 449-459. + +6. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data. See + reference [3], for example. + +7. Source code + + Source code for a C language implementation of a "deflate" compliant + compressor and decompressor is available within the zlib package at + ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +8. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Phil Katz designed the deflate format. Jean-Loup Gailly and Mark + Adler wrote the related software described in this specification. + Glenn Randers-Pehrson converted this document to RFC and HTML format. + + + +Deutsch Informational [Page 16] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +9. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch Informational [Page 17] + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1952.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1952.txt new file mode 100644 index 00000000..a8e51b45 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/rfc1952.txt @@ -0,0 +1,675 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1952 Aladdin Enterprises +Category: Informational May 1996 + + + GZIP file format specification version 4.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that is + compatible with the widely used GZIP utility. The format includes a + cyclic redundancy check value for detecting data corruption. The + format presently uses the DEFLATE method of compression but can be + easily extended to use other compression methods. The format can be + implemented readily in a manner not covered by patents. + + + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1952 GZIP File Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................. 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 4 + 2.1. Overall conventions ....................................... 4 + 2.2. File format ............................................... 5 + 2.3. Member format ............................................. 5 + 2.3.1. Member header and trailer ........................... 6 + 2.3.1.1. Extra field ................................... 8 + 2.3.1.2. Compliance .................................... 9 + 3. References .................................................. 9 + 4. Security Considerations .................................... 10 + 5. Acknowledgements ........................................... 10 + 6. Author's Address ........................................... 10 + 7. Appendix: Jean-Loup Gailly's gzip utility .................. 11 + 8. Appendix: Sample CRC Code .................................. 11 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can compress or decompress a data stream (as opposed to a + randomly accessible file) to produce another data stream, + using only an a priori bounded amount of intermediate + storage, and hence can be used in data communications or + similar structures such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + + + +Deutsch Informational [Page 2] + +RFC 1952 GZIP File Format Specification May 1996 + + + The data format defined by this specification does not attempt to: + + * Provide random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well as + the best currently available specialized algorithms. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into gzip format and/or decompress data from gzip + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compression method and a file format + (the latter assuming only that a file can store a sequence of + arbitrary bytes). It does not specify any particular interface to + a file system or anything about character sets or encodings + (except for file names and comments, which are optional). + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any file that conforms to all the + specifications presented here; a compliant compressor must produce + files that conform to all the specifications presented here. The + material in the appendices is not part of the specification per se + and is not relevant to compliance. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + There have been no technical changes to the gzip format since + version 4.1 of this specification. In version 4.2, some + terminology was changed, and the sample CRC code was rewritten for + clarity and to eliminate the requirement for the caller to do pre- + and post-conditioning. Version 4.3 is a conversion of the + specification to RFC style. + + + +Deutsch Informational [Page 3] + +RFC 1952 GZIP File Format Specification May 1996 + + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, since + the data format described here is byte- rather than bit-oriented. + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + + +Deutsch Informational [Page 4] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.2. File format + + A gzip file consists of a series of "members" (compressed data + sets). The format of each member is specified in the following + section. The members simply appear one after another in the file, + with no additional information before, between, or after them. + + 2.3. Member format + + Each member has the following structure: + + +---+---+---+---+---+---+---+---+---+---+ + |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) + +---+---+---+---+---+---+---+---+---+---+ + + (if FLG.FEXTRA set) + + +---+---+=================================+ + | XLEN |...XLEN bytes of "extra field"...| (more-->) + +---+---+=================================+ + + (if FLG.FNAME set) + + +=========================================+ + |...original file name, zero-terminated...| (more-->) + +=========================================+ + + (if FLG.FCOMMENT set) + + +===================================+ + |...file comment, zero-terminated...| (more-->) + +===================================+ + + (if FLG.FHCRC set) + + +---+---+ + | CRC16 | + +---+---+ + + +=======================+ + |...compressed blocks...| (more-->) + +=======================+ + + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | CRC32 | ISIZE | + +---+---+---+---+---+---+---+---+ + + + + +Deutsch Informational [Page 5] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.3.1. Member header and trailer + + ID1 (IDentification 1) + ID2 (IDentification 2) + These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139 + (0x8b, \213), to identify the file as being in gzip format. + + CM (Compression Method) + This identifies the compression method used in the file. CM + = 0-7 are reserved. CM = 8 denotes the "deflate" + compression method, which is the one customarily used by + gzip and which is documented elsewhere. + + FLG (FLaGs) + This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + + If FTEXT is set, the file is probably ASCII text. This is + an optional indication, which the compressor may set by + checking a small amount of the input data to see whether any + non-ASCII characters are present. In case of doubt, FTEXT + is cleared, indicating binary data. For systems which have + different file formats for ascii text and binary data, the + decompressor can use FTEXT to choose the appropriate format. + We deliberately do not specify the algorithm used to set + this bit, since a compressor always has the option of + leaving it cleared and a decompressor always has the option + of ignoring it and letting some other program handle issues + of data conversion. + + If FHCRC is set, a CRC16 for the gzip header is present, + immediately before the compressed data. The CRC16 consists + of the two least significant bytes of the CRC32 for all + bytes of the gzip header up to and not including the CRC16. + [The FHCRC bit was never set by versions of gzip up to + 1.2.4, even though it was documented with a different + meaning in gzip 1.2.4.] + + If FEXTRA is set, optional extra fields are present, as + described in a following section. + + + +Deutsch Informational [Page 6] + +RFC 1952 GZIP File Format Specification May 1996 + + + If FNAME is set, an original file name is present, + terminated by a zero byte. The name must consist of ISO + 8859-1 (LATIN-1) characters; on operating systems using + EBCDIC or any other character set for file names, the name + must be translated to the ISO LATIN-1 character set. This + is the original name of the file being compressed, with any + directory components removed, and, if the file being + compressed is on a file system with case insensitive names, + forced to lower case. There is no original file name if the + data was compressed from a source other than a named file; + for example, if the source was stdin on a Unix system, there + is no file name. + + If FCOMMENT is set, a zero-terminated file comment is + present. This comment is not interpreted; it is only + intended for human consumption. The comment must consist of + ISO 8859-1 (LATIN-1) characters. Line breaks should be + denoted by a single line feed character (10 decimal). + + Reserved FLG bits must be zero. + + MTIME (Modification TIME) + This gives the most recent modification time of the original + file being compressed. The time is in Unix format, i.e., + seconds since 00:00:00 GMT, Jan. 1, 1970. (Note that this + may cause problems for MS-DOS and other systems that use + local rather than Universal time.) If the compressed data + did not come from a file, MTIME is set to the time at which + compression started. MTIME = 0 means no time stamp is + available. + + XFL (eXtra FLags) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + XFL = 2 - compressor used maximum compression, + slowest algorithm + XFL = 4 - compressor used fastest algorithm + + OS (Operating System) + This identifies the type of file system on which compression + took place. This may be useful in determining end-of-line + convention for text files. The currently defined values are + as follows: + + + + + + +Deutsch Informational [Page 7] + +RFC 1952 GZIP File Format Specification May 1996 + + + 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32) + 1 - Amiga + 2 - VMS (or OpenVMS) + 3 - Unix + 4 - VM/CMS + 5 - Atari TOS + 6 - HPFS filesystem (OS/2, NT) + 7 - Macintosh + 8 - Z-System + 9 - CP/M + 10 - TOPS-20 + 11 - NTFS filesystem (NT) + 12 - QDOS + 13 - Acorn RISCOS + 255 - unknown + + XLEN (eXtra LENgth) + If FLG.FEXTRA is set, this gives the length of the optional + extra field. See below for details. + + CRC32 (CRC-32) + This contains a Cyclic Redundancy Check value of the + uncompressed data computed according to CRC-32 algorithm + used in the ISO 3309 standard and in section 8.1.1.6.2 of + ITU-T recommendation V.42. (See http://www.iso.ch for + ordering ISO documents. See gopher://info.itu.ch for an + online version of ITU-T V.42.) + + ISIZE (Input SIZE) + This contains the size of the original (uncompressed) input + data modulo 2^32. + + 2.3.1.1. Extra field + + If the FLG.FEXTRA bit is set, an "extra field" is present in + the header, with total length XLEN bytes. It consists of a + series of subfields, each of the form: + + +---+---+---+---+==================================+ + |SI1|SI2| LEN |... LEN bytes of subfield data ...| + +---+---+---+---+==================================+ + + SI1 and SI2 provide a subfield ID, typically two ASCII letters + with some mnemonic value. Jean-Loup Gailly + is maintaining a registry of subfield + IDs; please send him any subfield ID you wish to use. Subfield + IDs with SI2 = 0 are reserved for future use. The following + IDs are currently defined: + + + +Deutsch Informational [Page 8] + +RFC 1952 GZIP File Format Specification May 1996 + + + SI1 SI2 Data + ---------- ---------- ---- + 0x41 ('A') 0x70 ('P') Apollo file type information + + LEN gives the length of the subfield data, excluding the 4 + initial bytes. + + 2.3.1.2. Compliance + + A compliant compressor must produce files with correct ID1, + ID2, CM, CRC32, and ISIZE, but may set all the other fields in + the fixed-length part of the header to default values (255 for + OS, 0 for all others). The compressor must set all reserved + bits to zero. + + A compliant decompressor must check ID1, ID2, and CM, and + provide an error indication if any of these have incorrect + values. It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC + at least so it can skip over the optional fields if they are + present. It need not examine any other part of the header or + trailer; in particular, a decompressor may ignore FTEXT and OS + and always produce binary output, and still be compliant. A + compliant decompressor must give an error indication if any + reserved bit is non-zero, since such a bit could indicate the + presence of a new field that would cause subsequent data to be + interpreted incorrectly. + +3. References + + [1] "Information Processing - 8-bit single-byte coded graphic + character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987). + The ISO 8859-1 (Latin-1) character set is a superset of 7-bit + ASCII. Files defining this character set are available as + iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/ + + [2] ISO 3309 + + [3] ITU-T recommendation V.42 + + [4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in + ftp://prep.ai.mit.edu/pub/gnu/ + + [6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table + Look-Up", Communications of the ACM, 31(8), pp.1008-1013. + + + + +Deutsch Informational [Page 9] + +RFC 1952 GZIP File Format Specification May 1996 + + + [7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal, + pp.118-133. + + [8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt, + describing the CRC concept. + +4. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data, such as by + setting and checking the CRC-32 check value. + +5. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler, + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +6. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + +Deutsch Informational [Page 10] + +RFC 1952 GZIP File Format Specification May 1996 + + +7. Appendix: Jean-Loup Gailly's gzip utility + + The most widely used implementation of gzip compression, and the + original documentation on which this specification is based, were + created by Jean-Loup Gailly . Since this + implementation is a de facto standard, we mention some more of its + features here. Again, the material in this section is not part of + the specification per se, and implementations need not follow it to + be compliant. + + When compressing or decompressing a file, gzip preserves the + protection, ownership, and modification time attributes on the local + file system, since there is no provision for representing protection + attributes in the gzip file format itself. Since the file format + includes a modification time, the gzip decompressor provides a + command line switch that assigns the modification time from the file, + rather than the local modification time of the compressed input, to + the decompressed output. + +8. Appendix: Sample CRC Code + + The following sample code represents a practical implementation of + the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42 + for a formal specification.) + + The sample code is in the ANSI C programming language. Non C users + may find it easier to read with these hints: + + & Bitwise AND operator. + ^ Bitwise exclusive-OR operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero + bit(s) at the left. + ! Logical NOT operator. + ++ "n++" increments the variable n. + 0xNNN 0x introduces a hexadecimal (base 16) constant. + Suffix L indicates a long value (at least 32 bits). + + /* Table of CRCs of all 8-bit messages. */ + unsigned long crc_table[256]; + + /* Flag: has the table been computed? Initially false. */ + int crc_table_computed = 0; + + /* Make the table for a fast CRC. */ + void make_crc_table(void) + { + unsigned long c; + + + +Deutsch Informational [Page 11] + +RFC 1952 GZIP File Format Specification May 1996 + + + int n, k; + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) { + c = 0xedb88320L ^ (c >> 1); + } else { + c = c >> 1; + } + } + crc_table[n] = c; + } + crc_table_computed = 1; + } + + /* + Update a running crc with the bytes buf[0..len-1] and return + the updated crc. The crc should be initialized to zero. Pre- and + post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the caller. Usage example: + + unsigned long crc = 0L; + + while (read_buffer(buffer, length) != EOF) { + crc = update_crc(crc, buffer, length); + } + if (crc != original_crc) error(); + */ + unsigned long update_crc(unsigned long crc, + unsigned char *buf, int len) + { + unsigned long c = crc ^ 0xffffffffL; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; + } + + /* Return the CRC of the bytes buf[0..len-1]. */ + unsigned long crc(unsigned char *buf, int len) + { + return update_crc(0L, buf, len); + } + + + + +Deutsch Informational [Page 12] + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/txtvsbin.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/txtvsbin.txt new file mode 100644 index 00000000..3d0f0634 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/doc/txtvsbin.txt @@ -0,0 +1,107 @@ +A Fast Method for Identifying Plain Text Files +============================================== + + +Introduction +------------ + +Given a file coming from an unknown source, it is sometimes desirable +to find out whether the format of that file is plain text. Although +this may appear like a simple task, a fully accurate detection of the +file type requires heavy-duty semantic analysis on the file contents. +It is, however, possible to obtain satisfactory results by employing +various heuristics. + +Previous versions of PKZip and other zip-compatible compression tools +were using a crude detection scheme: if more than 80% (4/5) of the bytes +found in a certain buffer are within the range [7..127], the file is +labeled as plain text, otherwise it is labeled as binary. A prominent +limitation of this scheme is the restriction to Latin-based alphabets. +Other alphabets, like Greek, Cyrillic or Asian, make extensive use of +the bytes within the range [128..255], and texts using these alphabets +are most often misidentified by this scheme; in other words, the rate +of false negatives is sometimes too high, which means that the recall +is low. Another weakness of this scheme is a reduced precision, due to +the false positives that may occur when binary files containing large +amounts of textual characters are misidentified as plain text. + +In this article we propose a new, simple detection scheme that features +a much increased precision and a near-100% recall. This scheme is +designed to work on ASCII, Unicode and other ASCII-derived alphabets, +and it handles single-byte encodings (ISO-8859, MacRoman, KOI8, etc.) +and variable-sized encodings (ISO-2022, UTF-8, etc.). Wider encodings +(UCS-2/UTF-16 and UCS-4/UTF-32) are not handled, however. + + +The Algorithm +------------- + +The algorithm works by dividing the set of bytecodes [0..255] into three +categories: +- The white list of textual bytecodes: + 9 (TAB), 10 (LF), 13 (CR), 32 (SPACE) to 255. +- The gray list of tolerated bytecodes: + 7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC). +- The black list of undesired, non-textual bytecodes: + 0 (NUL) to 6, 14 to 31. + +If a file contains at least one byte that belongs to the white list and +no byte that belongs to the black list, then the file is categorized as +plain text; otherwise, it is categorized as binary. (The boundary case, +when the file is empty, automatically falls into the latter category.) + + +Rationale +--------- + +The idea behind this algorithm relies on two observations. + +The first observation is that, although the full range of 7-bit codes +[0..127] is properly specified by the ASCII standard, most control +characters in the range [0..31] are not used in practice. The only +widely-used, almost universally-portable control codes are 9 (TAB), +10 (LF) and 13 (CR). There are a few more control codes that are +recognized on a reduced range of platforms and text viewers/editors: +7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB) and 27 (ESC); but these +codes are rarely (if ever) used alone, without being accompanied by +some printable text. Even the newer, portable text formats such as +XML avoid using control characters outside the list mentioned here. + +The second observation is that most of the binary files tend to contain +control characters, especially 0 (NUL). Even though the older text +detection schemes observe the presence of non-ASCII codes from the range +[128..255], the precision rarely has to suffer if this upper range is +labeled as textual, because the files that are genuinely binary tend to +contain both control characters and codes from the upper range. On the +other hand, the upper range needs to be labeled as textual, because it +is used by virtually all ASCII extensions. In particular, this range is +used for encoding non-Latin scripts. + +Since there is no counting involved, other than simply observing the +presence or the absence of some byte values, the algorithm produces +consistent results, regardless what alphabet encoding is being used. +(If counting were involved, it could be possible to obtain different +results on a text encoded, say, using ISO-8859-16 versus UTF-8.) + +There is an extra category of plain text files that are "polluted" with +one or more black-listed codes, either by mistake or by peculiar design +considerations. In such cases, a scheme that tolerates a small fraction +of black-listed codes would provide an increased recall (i.e. more true +positives). This, however, incurs a reduced precision overall, since +false positives are more likely to appear in binary files that contain +large chunks of textual data. Furthermore, "polluted" plain text should +be regarded as binary by general-purpose text detection schemes, because +general-purpose text processing algorithms might not be applicable. +Under this premise, it is safe to say that our detection method provides +a near-100% recall. + +Experiments have been run on many files coming from various platforms +and applications. We tried plain text files, system logs, source code, +formatted office documents, compiled object code, etc. The results +confirm the optimistic assumptions about the capabilities of this +algorithm. + + +-- +Cosmin Truta +Last updated: 2006-May-28 diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/example.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/example.c new file mode 100644 index 00000000..442b6020 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2006 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: example.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/README.examples b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/README.examples new file mode 100644 index 00000000..56a31714 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/README.examples @@ -0,0 +1,49 @@ +This directory contains examples of the use of zlib and other relevant +programs and documentation. + +enough.c + calculation and justification of ENOUGH parameter in inftrees.h + - calculates the maximum table space used in inflate tree + construction over all possible Huffman codes + +fitblk.c + compress just enough input to nearly fill a requested output size + - zlib isn't designed to do this, but fitblk does it anyway + +gun.c + uncompress a gzip file + - illustrates the use of inflateBack() for high speed file-to-file + decompression using call-back functions + - is approximately twice as fast as gzip -d + - also provides Unix uncompress functionality, again twice as fast + +gzappend.c + append to a gzip file + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of deflatePrime() to start at any bit + +gzjoin.c + join gzip files without recalculating the crc or recompressing + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of crc32_combine() + +gzlog.c +gzlog.h + efficiently and robustly maintain a message log file in gzip format + - illustrates use of raw deflate, Z_PARTIAL_FLUSH, deflatePrime(), + and deflateSetDictionary() + - illustrates use of a gzip header extra field + +zlib_how.html + painfully comprehensive description of zpipe.c (see below) + - describes in excruciating detail the use of deflate() and inflate() + +zpipe.c + reads and writes zlib streams from stdin to stdout + - illustrates the proper use of deflate() and inflate() + - deeply commented in zlib_how.html (see above) + +zran.c + index a zlib or gzip stream and randomly access it + - illustrates the use of Z_BLOCK, inflatePrime(), and + inflateSetDictionary() to provide random access diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/enough.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/enough.c new file mode 100644 index 00000000..c40410ba --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/enough.c @@ -0,0 +1,569 @@ +/* enough.c -- determine the maximum size of inflate's Huffman code tables over + * all possible valid and complete Huffman codes, subject to a length limit. + * Copyright (C) 2007, 2008 Mark Adler + * Version 1.3 17 February 2008 Mark Adler + */ + +/* Version history: + 1.0 3 Jan 2007 First version (derived from codecount.c version 1.4) + 1.1 4 Jan 2007 Use faster incremental table usage computation + Prune examine() search on previously visited states + 1.2 5 Jan 2007 Comments clean up + As inflate does, decrease root for short codes + Refuse cases where inflate would increase root + 1.3 17 Feb 2008 Add argument for initial root table size + Fix bug for initial root table size == max - 1 + Use a macro to compute the history index + */ + +/* + Examine all possible Huffman codes for a given number of symbols and a + maximum code length in bits to determine the maximum table size for zilb's + inflate. Only complete Huffman codes are counted. + + Two codes are considered distinct if the vectors of the number of codes per + length are not identical. So permutations of the symbol assignments result + in the same code for the counting, as do permutations of the assignments of + the bit values to the codes (i.e. only canonical codes are counted). + + We build a code from shorter to longer lengths, determining how many symbols + are coded at each length. At each step, we have how many symbols remain to + be coded, what the last code length used was, and how many bit patterns of + that length remain unused. Then we add one to the code length and double the + number of unused patterns to graduate to the next code length. We then + assign all portions of the remaining symbols to that code length that + preserve the properties of a correct and eventually complete code. Those + properties are: we cannot use more bit patterns than are available; and when + all the symbols are used, there are exactly zero possible bit patterns + remaining. + + The inflate Huffman decoding algorithm uses two-level lookup tables for + speed. There is a single first-level table to decode codes up to root bits + in length (root == 9 in the current inflate implementation). The table + has 1 << root entries and is indexed by the next root bits of input. Codes + shorter than root bits have replicated table entries, so that the correct + entry is pointed to regardless of the bits that follow the short code. If + the code is longer than root bits, then the table entry points to a second- + level table. The size of that table is determined by the longest code with + that root-bit prefix. If that longest code has length len, then the table + has size 1 << (len - root), to index the remaining bits in that set of + codes. Each subsequent root-bit prefix then has its own sub-table. The + total number of table entries required by the code is calculated + incrementally as the number of codes at each bit length is populated. When + all of the codes are shorter than root bits, then root is reduced to the + longest code length, resulting in a single, smaller, one-level table. + + The inflate algorithm also provides for small values of root (relative to + the log2 of the number of symbols), where the shortest code has more bits + than root. In that case, root is increased to the length of the shortest + code. This program, by design, does not handle that case, so it is verified + that the number of symbols is less than 2^(root + 1). + + In order to speed up the examination (by about ten orders of magnitude for + the default arguments), the intermediate states in the build-up of a code + are remembered and previously visited branches are pruned. The memory + required for this will increase rapidly with the total number of symbols and + the maximum code length in bits. However this is a very small price to pay + for the vast speedup. + + First, all of the possible Huffman codes are counted, and reachable + intermediate states are noted by a non-zero count in a saved-results array. + Second, the intermediate states that lead to (root + 1) bit or longer codes + are used to look at all sub-codes from those junctures for their inflate + memory usage. (The amount of memory used is not affected by the number of + codes of root bits or less in length.) Third, the visited states in the + construction of those sub-codes and the associated calculation of the table + size is recalled in order to avoid recalculating from the same juncture. + Beginning the code examination at (root + 1) bit codes, which is enabled by + identifying the reachable nodes, accounts for about six of the orders of + magnitude of improvement for the default arguments. About another four + orders of magnitude come from not revisiting previous states. Out of + approximately 2x10^16 possible Huffman codes, only about 2x10^6 sub-codes + need to be examined to cover all of the possible table memory usage cases + for the default arguments of 286 symbols limited to 15-bit codes. + + Note that an unsigned long long type is used for counting. It is quite easy + to exceed the capacity of an eight-byte integer with a large number of + symbols and a large maximum code length, so multiple-precision arithmetic + would need to replace the unsigned long long arithmetic in that case. This + program will abort if an overflow occurs. The big_t type identifies where + the counting takes place. + + An unsigned long long type is also used for calculating the number of + possible codes remaining at the maximum length. This limits the maximum + code length to the number of bits in a long long minus the number of bits + needed to represent the symbols in a flat code. The code_t type identifies + where the bit pattern counting takes place. + */ + +#include +#include +#include +#include + +#define local static + +/* special data types */ +typedef unsigned long long big_t; /* type for code counting */ +typedef unsigned long long code_t; /* type for bit pattern counting */ +struct tab { /* type for been here check */ + size_t len; /* length of bit vector in char's */ + char *vec; /* allocated bit vector */ +}; + +/* The array for saving results, num[], is indexed with this triplet: + + syms: number of symbols remaining to code + left: number of available bit patterns at length len + len: number of bits in the codes currently being assigned + + Those indices are constrained thusly when saving results: + + syms: 3..totsym (totsym == total symbols to code) + left: 2..syms - 1, but only the evens (so syms == 8 -> 2, 4, 6) + len: 1..max - 1 (max == maximum code length in bits) + + syms == 2 is not saved since that immediately leads to a single code. left + must be even, since it represents the number of available bit patterns at + the current length, which is double the number at the previous length. + left ends at syms-1 since left == syms immediately results in a single code. + (left > sym is not allowed since that would result in an incomplete code.) + len is less than max, since the code completes immediately when len == max. + + The offset into the array is calculated for the three indices with the + first one (syms) being outermost, and the last one (len) being innermost. + We build the array with length max-1 lists for the len index, with syms-3 + of those for each symbol. There are totsym-2 of those, with each one + varying in length as a function of sym. See the calculation of index in + count() for the index, and the calculation of size in main() for the size + of the array. + + For the deflate example of 286 symbols limited to 15-bit codes, the array + has 284,284 entries, taking up 2.17 MB for an 8-byte big_t. More than + half of the space allocated for saved results is actually used -- not all + possible triplets are reached in the generation of valid Huffman codes. + */ + +/* The array for tracking visited states, done[], is itself indexed identically + to the num[] array as described above for the (syms, left, len) triplet. + Each element in the array is further indexed by the (mem, rem) doublet, + where mem is the amount of inflate table space used so far, and rem is the + remaining unused entries in the current inflate sub-table. Each indexed + element is simply one bit indicating whether the state has been visited or + not. Since the ranges for mem and rem are not known a priori, each bit + vector is of a variable size, and grows as needed to accommodate the visited + states. mem and rem are used to calculate a single index in a triangular + array. Since the range of mem is expected in the default case to be about + ten times larger than the range of rem, the array is skewed to reduce the + memory usage, with eight times the range for mem than for rem. See the + calculations for offset and bit in beenhere() for the details. + + For the deflate example of 286 symbols limited to 15-bit codes, the bit + vectors grow to total approximately 21 MB, in addition to the 4.3 MB done[] + array itself. + */ + +/* Globals to avoid propagating constants or constant pointers recursively */ +local int max; /* maximum allowed bit length for the codes */ +local int root; /* size of base code table in bits */ +local int large; /* largest code table so far */ +local size_t size; /* number of elements in num and done */ +local int *code; /* number of symbols assigned to each bit length */ +local big_t *num; /* saved results array for code counting */ +local struct tab *done; /* states already evaluated array */ + +/* Index function for num[] and done[] */ +#define INDEX(i,j,k) (((size_t)((i-1)>>1)*((i-2)>>1)+(j>>1)-1)*(max-1)+k-1) + +/* Free allocated space. Uses globals code, num, and done. */ +local void cleanup(void) +{ + size_t n; + + if (done != NULL) { + for (n = 0; n < size; n++) + if (done[n].len) + free(done[n].vec); + free(done); + } + if (num != NULL) + free(num); + if (code != NULL) + free(code); +} + +/* Return the number of possible Huffman codes using bit patterns of lengths + len through max inclusive, coding syms symbols, with left bit patterns of + length len unused -- return -1 if there is an overflow in the counting. + Keep a record of previous results in num to prevent repeating the same + calculation. Uses the globals max and num. */ +local big_t count(int syms, int len, int left) +{ + big_t sum; /* number of possible codes from this juncture */ + big_t got; /* value returned from count() */ + int least; /* least number of syms to use at this juncture */ + int most; /* most number of syms to use at this juncture */ + int use; /* number of bit patterns to use in next call */ + size_t index; /* index of this case in *num */ + + /* see if only one possible code */ + if (syms == left) + return 1; + + /* note and verify the expected state */ + assert(syms > left && left > 0 && len < max); + + /* see if we've done this one already */ + index = INDEX(syms, left, len); + got = num[index]; + if (got) + return got; /* we have -- return the saved result */ + + /* we need to use at least this many bit patterns so that the code won't be + incomplete at the next length (more bit patterns than symbols) */ + least = (left << 1) - syms; + if (least < 0) + least = 0; + + /* we can use at most this many bit patterns, lest there not be enough + available for the remaining symbols at the maximum length (if there were + no limit to the code length, this would become: most = left - 1) */ + most = (((code_t)left << (max - len)) - syms) / + (((code_t)1 << (max - len)) - 1); + + /* count all possible codes from this juncture and add them up */ + sum = 0; + for (use = least; use <= most; use++) { + got = count(syms - use, len + 1, (left - use) << 1); + sum += got; + if (got == -1 || sum < got) /* overflow */ + return -1; + } + + /* verify that all recursive calls are productive */ + assert(sum != 0); + + /* save the result and return it */ + num[index] = sum; + return sum; +} + +/* Return true if we've been here before, set to true if not. Set a bit in a + bit vector to indicate visiting this state. Each (syms,len,left) state + has a variable size bit vector indexed by (mem,rem). The bit vector is + lengthened if needed to allow setting the (mem,rem) bit. */ +local int beenhere(int syms, int len, int left, int mem, int rem) +{ + size_t index; /* index for this state's bit vector */ + size_t offset; /* offset in this state's bit vector */ + int bit; /* mask for this state's bit */ + size_t length; /* length of the bit vector in bytes */ + char *vector; /* new or enlarged bit vector */ + + /* point to vector for (syms,left,len), bit in vector for (mem,rem) */ + index = INDEX(syms, left, len); + mem -= 1 << root; + offset = (mem >> 3) + rem; + offset = ((offset * (offset + 1)) >> 1) + rem; + bit = 1 << (mem & 7); + + /* see if we've been here */ + length = done[index].len; + if (offset < length && (done[index].vec[offset] & bit) != 0) + return 1; /* done this! */ + + /* we haven't been here before -- set the bit to show we have now */ + + /* see if we need to lengthen the vector in order to set the bit */ + if (length <= offset) { + /* if we have one already, enlarge it, zero out the appended space */ + if (length) { + do { + length <<= 1; + } while (length <= offset); + vector = realloc(done[index].vec, length); + if (vector != NULL) + memset(vector + done[index].len, 0, length - done[index].len); + } + + /* otherwise we need to make a new vector and zero it out */ + else { + length = 1 << (len - root); + while (length <= offset) + length <<= 1; + vector = calloc(length, sizeof(char)); + } + + /* in either case, bail if we can't get the memory */ + if (vector == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + exit(1); + } + + /* install the new vector */ + done[index].len = length; + done[index].vec = vector; + } + + /* set the bit */ + done[index].vec[offset] |= bit; + return 0; +} + +/* Examine all possible codes from the given node (syms, len, left). Compute + the amount of memory required to build inflate's decoding tables, where the + number of code structures used so far is mem, and the number remaining in + the current sub-table is rem. Uses the globals max, code, root, large, and + done. */ +local void examine(int syms, int len, int left, int mem, int rem) +{ + int least; /* least number of syms to use at this juncture */ + int most; /* most number of syms to use at this juncture */ + int use; /* number of bit patterns to use in next call */ + + /* see if we have a complete code */ + if (syms == left) { + /* set the last code entry */ + code[len] = left; + + /* complete computation of memory used by this code */ + while (rem < left) { + left -= rem; + rem = 1 << (len - root); + mem += rem; + } + assert(rem == left); + + /* if this is a new maximum, show the entries used and the sub-code */ + if (mem > large) { + large = mem; + printf("max %d: ", mem); + for (use = root + 1; use <= max; use++) + if (code[use]) + printf("%d[%d] ", code[use], use); + putchar('\n'); + fflush(stdout); + } + + /* remove entries as we drop back down in the recursion */ + code[len] = 0; + return; + } + + /* prune the tree if we can */ + if (beenhere(syms, len, left, mem, rem)) + return; + + /* we need to use at least this many bit patterns so that the code won't be + incomplete at the next length (more bit patterns than symbols) */ + least = (left << 1) - syms; + if (least < 0) + least = 0; + + /* we can use at most this many bit patterns, lest there not be enough + available for the remaining symbols at the maximum length (if there were + no limit to the code length, this would become: most = left - 1) */ + most = (((code_t)left << (max - len)) - syms) / + (((code_t)1 << (max - len)) - 1); + + /* occupy least table spaces, creating new sub-tables as needed */ + use = least; + while (rem < use) { + use -= rem; + rem = 1 << (len - root); + mem += rem; + } + rem -= use; + + /* examine codes from here, updating table space as we go */ + for (use = least; use <= most; use++) { + code[len] = use; + examine(syms - use, len + 1, (left - use) << 1, + mem + (rem ? 1 << (len - root) : 0), rem << 1); + if (rem == 0) { + rem = 1 << (len - root); + mem += rem; + } + rem--; + } + + /* remove entries as we drop back down in the recursion */ + code[len] = 0; +} + +/* Look at all sub-codes starting with root + 1 bits. Look at only the valid + intermediate code states (syms, left, len). For each completed code, + calculate the amount of memory required by inflate to build the decoding + tables. Find the maximum amount of memory required and show the code that + requires that maximum. Uses the globals max, root, and num. */ +local void enough(int syms) +{ + int n; /* number of remaing symbols for this node */ + int left; /* number of unused bit patterns at this length */ + size_t index; /* index of this case in *num */ + + /* clear code */ + for (n = 0; n <= max; n++) + code[n] = 0; + + /* look at all (root + 1) bit and longer codes */ + large = 1 << root; /* base table */ + if (root < max) /* otherwise, there's only a base table */ + for (n = 3; n <= syms; n++) + for (left = 2; left < n; left += 2) + { + /* look at all reachable (root + 1) bit nodes, and the + resulting codes (complete at root + 2 or more) */ + index = INDEX(n, left, root + 1); + if (root + 1 < max && num[index]) /* reachable node */ + examine(n, root + 1, left, 1 << root, 0); + + /* also look at root bit codes with completions at root + 1 + bits (not saved in num, since complete), just in case */ + if (num[index - 1] && n <= left << 1) + examine((n - left) << 1, root + 1, (n - left) << 1, + 1 << root, 0); + } + + /* done */ + printf("done: maximum of %d table entries\n", large); +} + +/* + Examine and show the total number of possible Huffman codes for a given + maximum number of symbols, initial root table size, and maximum code length + in bits -- those are the command arguments in that order. The default + values are 286, 9, and 15 respectively, for the deflate literal/length code. + The possible codes are counted for each number of coded symbols from two to + the maximum. The counts for each of those and the total number of codes are + shown. The maximum number of inflate table entires is then calculated + across all possible codes. Each new maximum number of table entries and the + associated sub-code (starting at root + 1 == 10 bits) is shown. + + To count and examine Huffman codes that are not length-limited, provide a + maximum length equal to the number of symbols minus one. + + For the deflate literal/length code, use "enough". For the deflate distance + code, use "enough 30 6". + + This uses the %llu printf format to print big_t numbers, which assumes that + big_t is an unsigned long long. If the big_t type is changed (for example + to a multiple precision type), the method of printing will also need to be + updated. + */ +int main(int argc, char **argv) +{ + int syms; /* total number of symbols to code */ + int n; /* number of symbols to code for this run */ + big_t got; /* return value of count() */ + big_t sum; /* accumulated number of codes over n */ + + /* set up globals for cleanup() */ + code = NULL; + num = NULL; + done = NULL; + + /* get arguments -- default to the deflate literal/length code */ + syms = 286; + root = 9; + max = 15; + if (argc > 1) { + syms = atoi(argv[1]); + if (argc > 2) { + root = atoi(argv[2]); + if (argc > 3) + max = atoi(argv[3]); + } + } + if (argc > 4 || syms < 2 || root < 1 || max < 1) { + fputs("invalid arguments, need: [sym >= 2 [root >= 1 [max >= 1]]]\n", + stderr); + return 1; + } + + /* if not restricting the code length, the longest is syms - 1 */ + if (max > syms - 1) + max = syms - 1; + + /* determine the number of bits in a code_t */ + n = 0; + while (((code_t)1 << n) != 0) + n++; + + /* make sure that the calculation of most will not overflow */ + if (max > n || syms - 2 >= (((code_t)0 - 1) >> (max - 1))) { + fputs("abort: code length too long for internal types\n", stderr); + return 1; + } + + /* reject impossible code requests */ + if (syms - 1 > ((code_t)1 << max) - 1) { + fprintf(stderr, "%d symbols cannot be coded in %d bits\n", + syms, max); + return 1; + } + + /* allocate code vector */ + code = calloc(max + 1, sizeof(int)); + if (code == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + return 1; + } + + /* determine size of saved results array, checking for overflows, + allocate and clear the array (set all to zero with calloc()) */ + if (syms == 2) /* iff max == 1 */ + num = NULL; /* won't be saving any results */ + else { + size = syms >> 1; + if (size > ((size_t)0 - 1) / (n = (syms - 1) >> 1) || + (size *= n, size > ((size_t)0 - 1) / (n = max - 1)) || + (size *= n, size > ((size_t)0 - 1) / sizeof(big_t)) || + (num = calloc(size, sizeof(big_t))) == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + return 1; + } + } + + /* count possible codes for all numbers of symbols, add up counts */ + sum = 0; + for (n = 2; n <= syms; n++) { + got = count(n, 1, 2); + sum += got; + if (got == -1 || sum < got) { /* overflow */ + fputs("abort: can't count that high!\n", stderr); + cleanup(); + return 1; + } + printf("%llu %d-codes\n", got, n); + } + printf("%llu total codes for 2 to %d symbols", sum, syms); + if (max < syms - 1) + printf(" (%d-bit length limit)\n", max); + else + puts(" (no length limit)"); + + /* allocate and clear done array for beenhere() */ + if (syms == 2) + done = NULL; + else if (size > ((size_t)0 - 1) / sizeof(struct tab) || + (done = calloc(size, sizeof(struct tab))) == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + return 1; + } + + /* find and show maximum inflate table usage */ + if (root > max) /* reduce root to max length */ + root = max; + if (syms < ((code_t)1 << (root + 1))) + enough(syms); + else + puts("cannot handle minimum code lengths > root"); + + /* done */ + cleanup(); + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/fitblk.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/fitblk.c new file mode 100644 index 00000000..c61de5c9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/fitblk.c @@ -0,0 +1,233 @@ +/* fitblk.c: example of fitting compressed output to a specified size + Not copyrighted -- provided to the public domain + Version 1.1 25 November 2004 Mark Adler */ + +/* Version history: + 1.0 24 Nov 2004 First version + 1.1 25 Nov 2004 Change deflateInit2() to deflateInit() + Use fixed-size, stack-allocated raw buffers + Simplify code moving compression to subroutines + Use assert() for internal errors + Add detailed description of approach + */ + +/* Approach to just fitting a requested compressed size: + + fitblk performs three compression passes on a portion of the input + data in order to determine how much of that input will compress to + nearly the requested output block size. The first pass generates + enough deflate blocks to produce output to fill the requested + output size plus a specfied excess amount (see the EXCESS define + below). The last deflate block may go quite a bit past that, but + is discarded. The second pass decompresses and recompresses just + the compressed data that fit in the requested plus excess sized + buffer. The deflate process is terminated after that amount of + input, which is less than the amount consumed on the first pass. + The last deflate block of the result will be of a comparable size + to the final product, so that the header for that deflate block and + the compression ratio for that block will be about the same as in + the final product. The third compression pass decompresses the + result of the second step, but only the compressed data up to the + requested size minus an amount to allow the compressed stream to + complete (see the MARGIN define below). That will result in a + final compressed stream whose length is less than or equal to the + requested size. Assuming sufficient input and a requested size + greater than a few hundred bytes, the shortfall will typically be + less than ten bytes. + + If the input is short enough that the first compression completes + before filling the requested output size, then that compressed + stream is return with no recompression. + + EXCESS is chosen to be just greater than the shortfall seen in a + two pass approach similar to the above. That shortfall is due to + the last deflate block compressing more efficiently with a smaller + header on the second pass. EXCESS is set to be large enough so + that there is enough uncompressed data for the second pass to fill + out the requested size, and small enough so that the final deflate + block of the second pass will be close in size to the final deflate + block of the third and final pass. MARGIN is chosen to be just + large enough to assure that the final compression has enough room + to complete in all cases. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +/* print nastygram and leave */ +local void quit(char *why) +{ + fprintf(stderr, "fitblk abort: %s\n", why); + exit(1); +} + +#define RAWLEN 4096 /* intermediate uncompressed buffer size */ + +/* compress from file to def until provided buffer is full or end of + input reached; return last deflate() return value, or Z_ERRNO if + there was read error on the file */ +local int partcompress(FILE *in, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + def->avail_in = fread(raw, 1, RAWLEN, in); + if (ferror(in)) + return Z_ERRNO; + def->next_in = raw; + if (feof(in)) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + return ret; +} + +/* recompress from inf's input to def's output; the input for inf and + the output for def are set in those structures before calling; + return last deflate() return value, or Z_MEM_ERROR if inflate() + was not able to allocate enough memory when it needed to */ +local int recompress(z_streamp inf, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + /* decompress */ + inf->avail_out = RAWLEN; + inf->next_out = raw; + ret = inflate(inf, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && + ret != Z_NEED_DICT); + if (ret == Z_MEM_ERROR) + return ret; + + /* compress what was decompresed until done or no room */ + def->avail_in = RAWLEN - inf->avail_out; + def->next_in = raw; + if (inf->avail_out != 0) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (ret != Z_STREAM_END && def->avail_out != 0); + return ret; +} + +#define EXCESS 256 /* empirically determined stream overage */ +#define MARGIN 8 /* amount to back off for completion */ + +/* compress from stdin to fixed-size block on stdout */ +int main(int argc, char **argv) +{ + int ret; /* return code */ + unsigned size; /* requested fixed output block size */ + unsigned have; /* bytes written by deflate() call */ + unsigned char *blk; /* intermediate and final stream */ + unsigned char *tmp; /* close to desired size stream */ + z_stream def, inf; /* zlib deflate and inflate states */ + + /* get requested output size */ + if (argc != 2) + quit("need one argument: size of output block"); + ret = strtol(argv[1], argv + 1, 10); + if (argv[1][0] != 0) + quit("argument must be a number"); + if (ret < 8) /* 8 is minimum zlib stream size */ + quit("need positive size of 8 or greater"); + size = (unsigned)ret; + + /* allocate memory for buffers and compression engine */ + blk = malloc(size + EXCESS); + def.zalloc = Z_NULL; + def.zfree = Z_NULL; + def.opaque = Z_NULL; + ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK || blk == NULL) + quit("out of memory"); + + /* compress from stdin until output full, or no more input */ + def.avail_out = size + EXCESS; + def.next_out = blk; + ret = partcompress(stdin, &def); + if (ret == Z_ERRNO) + quit("error reading input"); + + /* if it all fit, then size was undersubscribed -- done! */ + if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { + /* write block to stdout */ + have = size + EXCESS - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (all input)\n", + size - have, size); + return 0; + } + + /* it didn't all fit -- set up for recompression */ + inf.zalloc = Z_NULL; + inf.zfree = Z_NULL; + inf.opaque = Z_NULL; + inf.avail_in = 0; + inf.next_in = Z_NULL; + ret = inflateInit(&inf); + tmp = malloc(size + EXCESS); + if (ret != Z_OK || tmp == NULL) + quit("out of memory"); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do first recompression close to the right amount */ + inf.avail_in = size + EXCESS; + inf.next_in = blk; + def.avail_out = size + EXCESS; + def.next_out = tmp; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + + /* set up for next reocmpression */ + ret = inflateReset(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do second and final recompression (third compression) */ + inf.avail_in = size - MARGIN; /* assure stream will complete */ + inf.next_in = tmp; + def.avail_out = size; + def.next_out = blk; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ + + /* done -- write block to stdout */ + have = size - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + free(tmp); + ret = inflateEnd(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (%lu input)\n", + size - have, size, def.total_in); + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gun.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gun.c new file mode 100644 index 00000000..72b0882a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gun.c @@ -0,0 +1,701 @@ +/* gun.c -- simple gunzip to give an example of the use of inflateBack() + * Copyright (C) 2003, 2005, 2008, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.6 17 January 2010 Mark Adler */ + +/* Version history: + 1.0 16 Feb 2003 First version for testing of inflateBack() + 1.1 21 Feb 2005 Decompress concatenated gzip streams + Remove use of "this" variable (C++ keyword) + Fix return value for in() + Improve allocation failure checking + Add typecasting for void * structures + Add -h option for command version and usage + Add a bunch of comments + 1.2 20 Mar 2005 Add Unix compress (LZW) decompression + Copy file attributes from input file to output file + 1.3 12 Jun 2005 Add casts for error messages [Oberhumer] + 1.4 8 Dec 2006 LZW decompression speed improvements + 1.5 9 Feb 2008 Avoid warning in latest version of gcc + 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings + */ + +/* + gun [ -t ] [ name ... ] + + decompresses the data in the named gzip files. If no arguments are given, + gun will decompress from stdin to stdout. The names must end in .gz, -gz, + .z, -z, _z, or .Z. The uncompressed data will be written to a file name + with the suffix stripped. On success, the original file is deleted. On + failure, the output file is deleted. For most failures, the command will + continue to process the remaining names on the command line. A memory + allocation failure will abort the command. If -t is specified, then the + listed files or stdin will be tested as gzip files for integrity (without + checking for a proper suffix), no output will be written, and no files + will be deleted. + + Like gzip, gun allows concatenated gzip streams and will decompress them, + writing all of the uncompressed data to the output. Unlike gzip, gun allows + an empty file on input, and will produce no error writing an empty output + file. + + gun will also decompress files made by Unix compress, which uses LZW + compression. These files are automatically detected by virtue of their + magic header bytes. Since the end of Unix compress stream is marked by the + end-of-file, they cannot be concantenated. If a Unix compress stream is + encountered in an input file, it is the last stream in that file. + + Like gunzip and uncompress, the file attributes of the orignal compressed + file are maintained in the final uncompressed file, to the extent that the + user permissions allow it. + + On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version + 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the + LZW decompression provided by gun is about twice as fast as the standard + Unix uncompress command. + */ + +/* external functions and related types and constants */ +#include /* fprintf() */ +#include /* malloc(), free() */ +#include /* strerror(), strcmp(), strlen(), memcpy() */ +#include /* errno */ +#include /* open() */ +#include /* read(), write(), close(), chown(), unlink() */ +#include +#include /* stat(), chmod() */ +#include /* utime() */ +#include "zlib.h" /* inflateBackInit(), inflateBack(), */ + /* inflateBackEnd(), crc32() */ + +/* function declaration */ +#define local static + +/* buffer constants */ +#define SIZE 32768U /* input and output buffer sizes */ +#define PIECE 16384 /* limits i/o chunks for 16-bit int case */ + +/* structure for infback() to pass to input function in() -- it maintains the + input file and a buffer of size SIZE */ +struct ind { + int infile; + unsigned char *inbuf; +}; + +/* Load input buffer, assumed to be empty, and return bytes loaded and a + pointer to them. read() is called until the buffer is full, or until it + returns end-of-file or error. Return 0 on error. */ +local unsigned in(void *in_desc, unsigned char **buf) +{ + int ret; + unsigned len; + unsigned char *next; + struct ind *me = (struct ind *)in_desc; + + next = me->inbuf; + *buf = next; + len = 0; + do { + ret = PIECE; + if ((unsigned)ret > SIZE - len) + ret = (int)(SIZE - len); + ret = (int)read(me->infile, next, ret); + if (ret == -1) { + len = 0; + break; + } + next += ret; + len += ret; + } while (ret != 0 && len < SIZE); + return len; +} + +/* structure for infback() to pass to output function out() -- it maintains the + output file, a running CRC-32 check on the output and the total number of + bytes output, both for checking against the gzip trailer. (The length in + the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and + the output is greater than 4 GB.) */ +struct outd { + int outfile; + int check; /* true if checking crc and total */ + unsigned long crc; + unsigned long total; +}; + +/* Write output buffer and update the CRC-32 and total bytes written. write() + is called until all of the output is written or an error is encountered. + On success out() returns 0. For a write failure, out() returns 1. If the + output file descriptor is -1, then nothing is written. + */ +local int out(void *out_desc, unsigned char *buf, unsigned len) +{ + int ret; + struct outd *me = (struct outd *)out_desc; + + if (me->check) { + me->crc = crc32(me->crc, buf, len); + me->total += len; + } + if (me->outfile != -1) + do { + ret = PIECE; + if ((unsigned)ret > len) + ret = (int)len; + ret = (int)write(me->outfile, buf, ret); + if (ret == -1) + return 1; + buf += ret; + len -= ret; + } while (len != 0); + return 0; +} + +/* next input byte macro for use inside lunpipe() and gunpipe() */ +#define NEXT() (have ? 0 : (have = in(indp, &next)), \ + last = have ? (have--, (int)(*next++)) : -1) + +/* memory for gunpipe() and lunpipe() -- + the first 256 entries of prefix[] and suffix[] are never used, could + have offset the index, but it's faster to waste the memory */ +unsigned char inbuf[SIZE]; /* input buffer */ +unsigned char outbuf[SIZE]; /* output buffer */ +unsigned short prefix[65536]; /* index to LZW prefix string */ +unsigned char suffix[65536]; /* one-character LZW suffix */ +unsigned char match[65280 + 2]; /* buffer for reversed match or gzip + 32K sliding window */ + +/* throw out what's left in the current bits byte buffer (this is a vestigial + aspect of the compressed data format derived from an implementation that + made use of a special VAX machine instruction!) */ +#define FLUSHCODE() \ + do { \ + left = 0; \ + rem = 0; \ + if (chunk > have) { \ + chunk -= have; \ + have = 0; \ + if (NEXT() == -1) \ + break; \ + chunk--; \ + if (chunk > have) { \ + chunk = have = 0; \ + break; \ + } \ + } \ + have -= chunk; \ + next += chunk; \ + chunk = 0; \ + } while (0) + +/* Decompress a compress (LZW) file from indp to outfile. The compress magic + header (two bytes) has already been read and verified. There are have bytes + of buffered input at next. strm is used for passing error information back + to gunpipe(). + + lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of + file, read error, or write error (a write error indicated by strm->next_in + not equal to Z_NULL), or Z_DATA_ERROR for invalid input. + */ +local int lunpipe(unsigned have, unsigned char *next, struct ind *indp, + int outfile, z_stream *strm) +{ + int last; /* last byte read by NEXT(), or -1 if EOF */ + unsigned chunk; /* bytes left in current chunk */ + int left; /* bits left in rem */ + unsigned rem; /* unused bits from input */ + int bits; /* current bits per code */ + unsigned code; /* code, table traversal index */ + unsigned mask; /* mask for current bits codes */ + int max; /* maximum bits per code for this stream */ + unsigned flags; /* compress flags, then block compress flag */ + unsigned end; /* last valid entry in prefix/suffix tables */ + unsigned temp; /* current code */ + unsigned prev; /* previous code */ + unsigned final; /* last character written for previous code */ + unsigned stack; /* next position for reversed string */ + unsigned outcnt; /* bytes in output buffer */ + struct outd outd; /* output structure */ + unsigned char *p; + + /* set up output */ + outd.outfile = outfile; + outd.check = 0; + + /* process remainder of compress header -- a flags byte */ + flags = NEXT(); + if (last == -1) + return Z_BUF_ERROR; + if (flags & 0x60) { + strm->msg = (char *)"unknown lzw flags set"; + return Z_DATA_ERROR; + } + max = flags & 0x1f; + if (max < 9 || max > 16) { + strm->msg = (char *)"lzw bits out of range"; + return Z_DATA_ERROR; + } + if (max == 9) /* 9 doesn't really mean 9 */ + max = 10; + flags &= 0x80; /* true if block compress */ + + /* clear table */ + bits = 9; + mask = 0x1ff; + end = flags ? 256 : 255; + + /* set up: get first 9-bit code, which is the first decompressed byte, but + don't create a table entry until the next code */ + if (NEXT() == -1) /* no compressed data is ok */ + return Z_OK; + final = prev = (unsigned)last; /* low 8 bits of code */ + if (NEXT() == -1) /* missing a bit */ + return Z_BUF_ERROR; + if (last & 1) { /* code must be < 256 */ + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + rem = (unsigned)last >> 1; /* remaining 7 bits */ + left = 7; + chunk = bits - 2; /* 7 bytes left in this chunk */ + outbuf[0] = (unsigned char)final; /* write first decompressed byte */ + outcnt = 1; + + /* decode codes */ + stack = 0; + for (;;) { + /* if the table will be full after this, increment the code size */ + if (end >= mask && bits < max) { + FLUSHCODE(); + bits++; + mask <<= 1; + mask++; + } + + /* get a code of length bits */ + if (chunk == 0) /* decrement chunk modulo bits */ + chunk = bits; + code = rem; /* low bits of code */ + if (NEXT() == -1) { /* EOF is end of compressed data */ + /* write remaining buffered output */ + if (outcnt && out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + return Z_OK; + } + code += (unsigned)last << left; /* middle (or high) bits of code */ + left += 8; + chunk--; + if (bits > left) { /* need more bits */ + if (NEXT() == -1) /* can't end in middle of code */ + return Z_BUF_ERROR; + code += (unsigned)last << left; /* high bits of code */ + left += 8; + chunk--; + } + code &= mask; /* mask to current code length */ + left -= bits; /* number of unused bits */ + rem = (unsigned)last >> (8 - left); /* unused bits from last byte */ + + /* process clear code (256) */ + if (code == 256 && flags) { + FLUSHCODE(); + bits = 9; /* initialize bits and mask */ + mask = 0x1ff; + end = 255; /* empty table */ + continue; /* get next code */ + } + + /* special code to reuse last match */ + temp = code; /* save the current code */ + if (code > end) { + /* Be picky on the allowed code here, and make sure that the code + we drop through (prev) will be a valid index so that random + input does not cause an exception. The code != end + 1 check is + empirically derived, and not checked in the original uncompress + code. If this ever causes a problem, that check could be safely + removed. Leaving this check in greatly improves gun's ability + to detect random or corrupted input after a compress header. + In any case, the prev > end check must be retained. */ + if (code != end + 1 || prev > end) { + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + match[stack++] = (unsigned char)final; + code = prev; + } + + /* walk through linked list to generate output in reverse order */ + p = match + stack; + while (code >= 256) { + *p++ = suffix[code]; + code = prefix[code]; + } + stack = p - match; + match[stack++] = (unsigned char)code; + final = code; + + /* link new table entry */ + if (end < mask) { + end++; + prefix[end] = (unsigned short)prev; + suffix[end] = (unsigned char)final; + } + + /* set previous code for next iteration */ + prev = temp; + + /* write output in forward order */ + while (stack > SIZE - outcnt) { + while (outcnt < SIZE) + outbuf[outcnt++] = match[--stack]; + if (out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + outcnt = 0; + } + p = match + stack; + do { + outbuf[outcnt++] = *--p; + } while (p > match); + stack = 0; + + /* loop for next code with final and prev as the last match, rem and + left provide the first 0..7 bits of the next code, end is the last + valid table entry */ + } +} + +/* Decompress a gzip file from infile to outfile. strm is assumed to have been + successfully initialized with inflateBackInit(). The input file may consist + of a series of gzip streams, in which case all of them will be decompressed + to the output file. If outfile is -1, then the gzip stream(s) integrity is + checked and nothing is written. + + The return value is a zlib error code: Z_MEM_ERROR if out of memory, + Z_DATA_ERROR if the header or the compressed data is invalid, or if the + trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends + prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip + stream) follows a valid gzip stream. + */ +local int gunpipe(z_stream *strm, int infile, int outfile) +{ + int ret, first, last; + unsigned have, flags, len; + unsigned char *next = NULL; + struct ind ind, *indp; + struct outd outd; + + /* setup input buffer */ + ind.infile = infile; + ind.inbuf = inbuf; + indp = &ind; + + /* decompress concatenated gzip streams */ + have = 0; /* no input data read in yet */ + first = 1; /* looking for first gzip header */ + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + for (;;) { + /* look for the two magic header bytes for a gzip stream */ + if (NEXT() == -1) { + ret = Z_OK; + break; /* empty gzip stream is ok */ + } + if (last != 31 || (NEXT() != 139 && last != 157)) { + strm->msg = (char *)"incorrect header check"; + ret = first ? Z_DATA_ERROR : Z_ERRNO; + break; /* not a gzip or compress header */ + } + first = 0; /* next non-header is junk */ + + /* process a compress (LZW) file -- can't be concatenated after this */ + if (last == 157) { + ret = lunpipe(have, next, indp, outfile, strm); + break; + } + + /* process remainder of gzip header */ + ret = Z_BUF_ERROR; + if (NEXT() != 8) { /* only deflate method allowed */ + if (last == -1) break; + strm->msg = (char *)"unknown compression method"; + ret = Z_DATA_ERROR; + break; + } + flags = NEXT(); /* header flags */ + NEXT(); /* discard mod time, xflgs, os */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); + NEXT(); + if (last == -1) break; + if (flags & 0xe0) { + strm->msg = (char *)"unknown header flags set"; + ret = Z_DATA_ERROR; + break; + } + if (flags & 4) { /* extra field */ + len = NEXT(); + len += (unsigned)(NEXT()) << 8; + if (last == -1) break; + while (len > have) { + len -= have; + have = 0; + if (NEXT() == -1) break; + len--; + } + if (last == -1) break; + have -= len; + next += len; + } + if (flags & 8) /* file name */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 16) /* comment */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + if (last == -1) break; + + /* set up output */ + outd.outfile = outfile; + outd.check = 1; + outd.crc = crc32(0L, Z_NULL, 0); + outd.total = 0; + + /* decompress data to output */ + strm->next_in = next; + strm->avail_in = have; + ret = inflateBack(strm, in, indp, out, &outd); + if (ret != Z_STREAM_END) break; + next = strm->next_in; + have = strm->avail_in; + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + + /* check trailer */ + ret = Z_BUF_ERROR; + if (NEXT() != (int)(outd.crc & 0xff) || + NEXT() != (int)((outd.crc >> 8) & 0xff) || + NEXT() != (int)((outd.crc >> 16) & 0xff) || + NEXT() != (int)((outd.crc >> 24) & 0xff)) { + /* crc error */ + if (last != -1) { + strm->msg = (char *)"incorrect data check"; + ret = Z_DATA_ERROR; + } + break; + } + if (NEXT() != (int)(outd.total & 0xff) || + NEXT() != (int)((outd.total >> 8) & 0xff) || + NEXT() != (int)((outd.total >> 16) & 0xff) || + NEXT() != (int)((outd.total >> 24) & 0xff)) { + /* length error */ + if (last != -1) { + strm->msg = (char *)"incorrect length check"; + ret = Z_DATA_ERROR; + } + break; + } + + /* go back and look for another gzip stream */ + } + + /* clean up and return */ + return ret; +} + +/* Copy file attributes, from -> to, as best we can. This is best effort, so + no errors are reported. The mode bits, including suid, sgid, and the sticky + bit are copied (if allowed), the owner's user id and group id are copied + (again if allowed), and the access and modify times are copied. */ +local void copymeta(char *from, char *to) +{ + struct stat was; + struct utimbuf when; + + /* get all of from's Unix meta data, return if not a regular file */ + if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG) + return; + + /* set to's mode bits, ignore errors */ + (void)chmod(to, was.st_mode & 07777); + + /* copy owner's user and group, ignore errors */ + (void)chown(to, was.st_uid, was.st_gid); + + /* copy access and modify times, ignore errors */ + when.actime = was.st_atime; + when.modtime = was.st_mtime; + (void)utime(to, &when); +} + +/* Decompress the file inname to the file outnname, of if test is true, just + decompress without writing and check the gzip trailer for integrity. If + inname is NULL or an empty string, read from stdin. If outname is NULL or + an empty string, write to stdout. strm is a pre-initialized inflateBack + structure. When appropriate, copy the file attributes from inname to + outname. + + gunzip() returns 1 if there is an out-of-memory error or an unexpected + return code from gunpipe(). Otherwise it returns 0. + */ +local int gunzip(z_stream *strm, char *inname, char *outname, int test) +{ + int ret; + int infile, outfile; + + /* open files */ + if (inname == NULL || *inname == 0) { + inname = "-"; + infile = 0; /* stdin */ + } + else { + infile = open(inname, O_RDONLY, 0); + if (infile == -1) { + fprintf(stderr, "gun cannot open %s\n", inname); + return 0; + } + } + if (test) + outfile = -1; + else if (outname == NULL || *outname == 0) { + outname = "-"; + outfile = 1; /* stdout */ + } + else { + outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (outfile == -1) { + close(infile); + fprintf(stderr, "gun cannot create %s\n", outname); + return 0; + } + } + errno = 0; + + /* decompress */ + ret = gunpipe(strm, infile, outfile); + if (outfile > 2) close(outfile); + if (infile > 2) close(infile); + + /* interpret result */ + switch (ret) { + case Z_OK: + case Z_ERRNO: + if (infile > 2 && outfile > 2) { + copymeta(inname, outname); /* copy attributes */ + unlink(inname); + } + if (ret == Z_ERRNO) + fprintf(stderr, "gun warning: trailing garbage ignored in %s\n", + inname); + break; + case Z_DATA_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg); + break; + case Z_MEM_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + case Z_BUF_ERROR: + if (outfile > 2) unlink(outname); + if (strm->next_in != Z_NULL) { + fprintf(stderr, "gun write error on %s: %s\n", + outname, strerror(errno)); + } + else if (errno) { + fprintf(stderr, "gun read error on %s: %s\n", + inname, strerror(errno)); + } + else { + fprintf(stderr, "gun unexpected end of file on %s\n", + inname); + } + break; + default: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun internal error--aborting\n"); + return 1; + } + return 0; +} + +/* Process the gun command line arguments. See the command syntax near the + beginning of this source file. */ +int main(int argc, char **argv) +{ + int ret, len, test; + char *outname; + unsigned char *window; + z_stream strm; + + /* initialize inflateBack state for repeated use */ + window = match; /* reuse LZW match buffer */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = inflateBackInit(&strm, 15, window); + if (ret != Z_OK) { + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + } + + /* decompress each file to the same name with the suffix removed */ + argc--; + argv++; + test = 0; + if (argc && strcmp(*argv, "-h") == 0) { + fprintf(stderr, "gun 1.6 (17 Jan 2010)\n"); + fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n"); + fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n"); + return 0; + } + if (argc && strcmp(*argv, "-t") == 0) { + test = 1; + argc--; + argv++; + } + if (argc) + do { + if (test) + outname = NULL; + else { + len = (int)strlen(*argv); + if (strcmp(*argv + len - 3, ".gz") == 0 || + strcmp(*argv + len - 3, "-gz") == 0) + len -= 3; + else if (strcmp(*argv + len - 2, ".z") == 0 || + strcmp(*argv + len - 2, "-z") == 0 || + strcmp(*argv + len - 2, "_z") == 0 || + strcmp(*argv + len - 2, ".Z") == 0) + len -= 2; + else { + fprintf(stderr, "gun error: no gz type on %s--skipping\n", + *argv); + continue; + } + outname = malloc(len + 1); + if (outname == NULL) { + fprintf(stderr, "gun out of memory error--aborting\n"); + ret = 1; + break; + } + memcpy(outname, *argv, len); + outname[len] = 0; + } + ret = gunzip(&strm, *argv, outname, test); + if (outname != NULL) free(outname); + if (ret) break; + } while (argv++, --argc); + else + ret = gunzip(&strm, NULL, NULL, test); + + /* clean up */ + inflateBackEnd(&strm); + return ret; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzappend.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzappend.c new file mode 100644 index 00000000..e9e878e1 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzappend.c @@ -0,0 +1,500 @@ +/* gzappend -- command to append to a gzip file + + Copyright (C) 2003 Mark Adler, all rights reserved + version 1.1, 4 Nov 2003 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 19 Oct 2003 - First version + * 1.1 4 Nov 2003 - Expand and clarify some comments and notes + * - Add version and copyright to help + * - Send help to stdout instead of stderr + * - Add some preemptive typecasts + * - Add L to constants in lseek() calls + * - Remove some debugging information in error messages + * - Use new data_type definition for zlib 1.2.1 + * - Simplfy and unify file operations + * - Finish off gzip file in gztack() + * - Use deflatePrime() instead of adding empty blocks + * - Keep gzip file clean on appended file read errors + * - Use in-place rotate instead of auxiliary buffer + * (Why you ask? Because it was fun to write!) + */ + +/* + gzappend takes a gzip file and appends to it, compressing files from the + command line or data from stdin. The gzip file is written to directly, to + avoid copying that file, in case it's large. Note that this results in the + unfriendly behavior that if gzappend fails, the gzip file is corrupted. + + This program was written to illustrate the use of the new Z_BLOCK option of + zlib 1.2.x's inflate() function. This option returns from inflate() at each + block boundary to facilitate locating and modifying the last block bit at + the start of the final deflate block. Also whether using Z_BLOCK or not, + another required feature of zlib 1.2.x is that inflate() now provides the + number of unusued bits in the last input byte used. gzappend will not work + with versions of zlib earlier than 1.2.1. + + gzappend first decompresses the gzip file internally, discarding all but + the last 32K of uncompressed data, and noting the location of the last block + bit and the number of unused bits in the last byte of the compressed data. + The gzip trailer containing the CRC-32 and length of the uncompressed data + is verified. This trailer will be later overwritten. + + Then the last block bit is cleared by seeking back in the file and rewriting + the byte that contains it. Seeking forward, the last byte of the compressed + data is saved along with the number of unused bits to initialize deflate. + + A deflate process is initialized, using the last 32K of the uncompressed + data from the gzip file to initialize the dictionary. If the total + uncompressed data was less than 32K, then all of it is used to initialize + the dictionary. The deflate output bit buffer is also initialized with the + last bits from the original deflate stream. From here on, the data to + append is simply compressed using deflate, and written to the gzip file. + When that is complete, the new CRC-32 and uncompressed length are written + as the trailer of the gzip file. + */ + +#include +#include +#include +#include +#include +#include "zlib.h" + +#define local static +#define LGCHUNK 14 +#define CHUNK (1U << LGCHUNK) +#define DSIZE 32768U + +/* print an error message and terminate with extreme prejudice */ +local void bye(char *msg1, char *msg2) +{ + fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2); + exit(1); +} + +/* return the greatest common divisor of a and b using Euclid's algorithm, + modified to be fast when one argument much greater than the other, and + coded to avoid unnecessary swapping */ +local unsigned gcd(unsigned a, unsigned b) +{ + unsigned c; + + while (a && b) + if (a > b) { + c = b; + while (a - c >= c) + c <<= 1; + a -= c; + } + else { + c = a; + while (b - c >= c) + c <<= 1; + b -= c; + } + return a + b; +} + +/* rotate list[0..len-1] left by rot positions, in place */ +local void rotate(unsigned char *list, unsigned len, unsigned rot) +{ + unsigned char tmp; + unsigned cycles; + unsigned char *start, *last, *to, *from; + + /* normalize rot and handle degenerate cases */ + if (len < 2) return; + if (rot >= len) rot %= len; + if (rot == 0) return; + + /* pointer to last entry in list */ + last = list + (len - 1); + + /* do simple left shift by one */ + if (rot == 1) { + tmp = *list; + memcpy(list, list + 1, len - 1); + *last = tmp; + return; + } + + /* do simple right shift by one */ + if (rot == len - 1) { + tmp = *last; + memmove(list + 1, list, len - 1); + *list = tmp; + return; + } + + /* otherwise do rotate as a set of cycles in place */ + cycles = gcd(len, rot); /* number of cycles */ + do { + start = from = list + cycles; /* start index is arbitrary */ + tmp = *from; /* save entry to be overwritten */ + for (;;) { + to = from; /* next step in cycle */ + from += rot; /* go right rot positions */ + if (from > last) from -= len; /* (pointer better not wrap) */ + if (from == start) break; /* all but one shifted */ + *to = *from; /* shift left */ + } + *to = tmp; /* complete the circle */ + } while (--cycles); +} + +/* structure for gzip file read operations */ +typedef struct { + int fd; /* file descriptor */ + int size; /* 1 << size is bytes in buf */ + unsigned left; /* bytes available at next */ + unsigned char *buf; /* buffer */ + unsigned char *next; /* next byte in buffer */ + char *name; /* file name for error messages */ +} file; + +/* reload buffer */ +local int readin(file *in) +{ + int len; + + len = read(in->fd, in->buf, 1 << in->size); + if (len == -1) bye("error reading ", in->name); + in->left = (unsigned)len; + in->next = in->buf; + return len; +} + +/* read from file in, exit if end-of-file */ +local int readmore(file *in) +{ + if (readin(in) == 0) bye("unexpected end of ", in->name); + return 0; +} + +#define read1(in) (in->left == 0 ? readmore(in) : 0, \ + in->left--, *(in->next)++) + +/* skip over n bytes of in */ +local void skip(file *in, unsigned n) +{ + unsigned bypass; + + if (n > in->left) { + n -= in->left; + bypass = n & ~((1U << in->size) - 1); + if (bypass) { + if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1) + bye("seeking ", in->name); + n -= bypass; + } + readmore(in); + if (n > in->left) + bye("unexpected end of ", in->name); + } + in->left -= n; + in->next += n; +} + +/* read a four-byte unsigned integer, little-endian, from in */ +unsigned long read4(file *in) +{ + unsigned long val; + + val = read1(in); + val += (unsigned)read1(in) << 8; + val += (unsigned long)read1(in) << 16; + val += (unsigned long)read1(in) << 24; + return val; +} + +/* skip over gzip header */ +local void gzheader(file *in) +{ + int flags; + unsigned n; + + if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file"); + if (read1(in) != 8) bye("unknown compression method in", in->name); + flags = read1(in); + if (flags & 0xe0) bye("unknown header flags set in", in->name); + skip(in, 6); + if (flags & 4) { + n = read1(in); + n += (unsigned)(read1(in)) << 8; + skip(in, n); + } + if (flags & 8) while (read1(in) != 0) ; + if (flags & 16) while (read1(in) != 0) ; + if (flags & 2) skip(in, 2); +} + +/* decompress gzip file "name", return strm with a deflate stream ready to + continue compression of the data in the gzip file, and return a file + descriptor pointing to where to write the compressed data -- the deflate + stream is initialized to compress using level "level" */ +local int gzscan(char *name, z_stream *strm, int level) +{ + int ret, lastbit, left, full; + unsigned have; + unsigned long crc, tot; + unsigned char *window; + off_t lastoff, end; + file gz; + + /* open gzip file */ + gz.name = name; + gz.fd = open(name, O_RDWR, 0); + if (gz.fd == -1) bye("cannot open ", name); + gz.buf = malloc(CHUNK); + if (gz.buf == NULL) bye("out of memory", ""); + gz.size = LGCHUNK; + gz.left = 0; + + /* skip gzip header */ + gzheader(&gz); + + /* prepare to decompress */ + window = malloc(DSIZE); + if (window == NULL) bye("out of memory", ""); + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = inflateInit2(strm, -15); + if (ret != Z_OK) bye("out of memory", " or library mismatch"); + + /* decompress the deflate stream, saving append information */ + lastbit = 0; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + left = 0; + strm->avail_in = gz.left; + strm->next_in = gz.next; + crc = crc32(0L, Z_NULL, 0); + have = full = 0; + do { + /* if needed, get more input */ + if (strm->avail_in == 0) { + readmore(&gz); + strm->avail_in = gz.left; + strm->next_in = gz.next; + } + + /* set up output to next available section of sliding window */ + strm->avail_out = DSIZE - have; + strm->next_out = window + have; + + /* inflate and check for errors */ + ret = inflate(strm, Z_BLOCK); + if (ret == Z_STREAM_ERROR) bye("internal stream error!", ""); + if (ret == Z_MEM_ERROR) bye("out of memory", ""); + if (ret == Z_DATA_ERROR) + bye("invalid compressed data--format violated in", name); + + /* update crc and sliding window pointer */ + crc = crc32(crc, window + have, DSIZE - have - strm->avail_out); + if (strm->avail_out) + have = DSIZE - strm->avail_out; + else { + have = 0; + full = 1; + } + + /* process end of block */ + if (strm->data_type & 128) { + if (strm->data_type & 64) + left = strm->data_type & 0x1f; + else { + lastbit = strm->data_type & 0x1f; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in; + } + } + } while (ret != Z_STREAM_END); + inflateEnd(strm); + gz.left = strm->avail_in; + gz.next = strm->next_in; + + /* save the location of the end of the compressed data */ + end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + + /* check gzip trailer and save total for deflate */ + if (crc != read4(&gz)) + bye("invalid compressed data--crc mismatch in ", name); + tot = strm->total_out; + if ((tot & 0xffffffffUL) != read4(&gz)) + bye("invalid compressed data--length mismatch in", name); + + /* if not at end of file, warn */ + if (gz.left || readin(&gz)) + fprintf(stderr, + "gzappend warning: junk at end of gzip file overwritten\n"); + + /* clear last block bit */ + lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7))); + lseek(gz.fd, -1L, SEEK_CUR); + if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name); + + /* if window wrapped, build dictionary from window by rotating */ + if (full) { + rotate(window, DSIZE, have); + have = DSIZE; + } + + /* set up deflate stream with window, crc, total_in, and leftover bits */ + ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) bye("out of memory", ""); + deflateSetDictionary(strm, window, have); + strm->adler = crc; + strm->total_in = tot; + if (left) { + lseek(gz.fd, --end, SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + deflatePrime(strm, 8 - left, *gz.buf); + } + lseek(gz.fd, end, SEEK_SET); + + /* clean up and return */ + free(window); + free(gz.buf); + return gz.fd; +} + +/* append file "name" to gzip file gd using deflate stream strm -- if last + is true, then finish off the deflate stream at the end */ +local void gztack(char *name, int gd, z_stream *strm, int last) +{ + int fd, len, ret; + unsigned left; + unsigned char *in, *out; + + /* open file to compress and append */ + fd = 0; + if (name != NULL) { + fd = open(name, O_RDONLY, 0); + if (fd == -1) + fprintf(stderr, "gzappend warning: %s not found, skipping ...\n", + name); + } + + /* allocate buffers */ + in = fd == -1 ? NULL : malloc(CHUNK); + out = malloc(CHUNK); + if (out == NULL) bye("out of memory", ""); + + /* compress input file and append to gzip file */ + do { + /* get more input */ + len = fd == -1 ? 0 : read(fd, in, CHUNK); + if (len == -1) { + fprintf(stderr, + "gzappend warning: error reading %s, skipping rest ...\n", + name); + len = 0; + } + strm->avail_in = (unsigned)len; + strm->next_in = in; + if (len) strm->adler = crc32(strm->adler, in, (unsigned)len); + + /* compress and write all available output */ + do { + strm->avail_out = CHUNK; + strm->next_out = out; + ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH); + left = CHUNK - strm->avail_out; + while (left) { + len = write(gd, out + CHUNK - strm->avail_out - left, left); + if (len == -1) bye("writing gzip file", ""); + left -= (unsigned)len; + } + } while (strm->avail_out == 0 && ret != Z_STREAM_END); + } while (len != 0); + + /* write trailer after last entry */ + if (last) { + deflateEnd(strm); + out[0] = (unsigned char)(strm->adler); + out[1] = (unsigned char)(strm->adler >> 8); + out[2] = (unsigned char)(strm->adler >> 16); + out[3] = (unsigned char)(strm->adler >> 24); + out[4] = (unsigned char)(strm->total_in); + out[5] = (unsigned char)(strm->total_in >> 8); + out[6] = (unsigned char)(strm->total_in >> 16); + out[7] = (unsigned char)(strm->total_in >> 24); + len = 8; + do { + ret = write(gd, out + 8 - len, len); + if (ret == -1) bye("writing gzip file", ""); + len -= ret; + } while (len); + close(gd); + } + + /* clean up and return */ + free(out); + if (in != NULL) free(in); + if (fd > 0) close(fd); +} + +/* process the compression level option if present, scan the gzip file, and + append the specified files, or append the data from stdin if no other file + names are provided on the command line -- the gzip file must be writable + and seekable */ +int main(int argc, char **argv) +{ + int gd, level; + z_stream strm; + + /* ignore command name */ + argv++; + + /* provide usage if no arguments */ + if (*argv == NULL) { + printf("gzappend 1.1 (4 Nov 2003) Copyright (C) 2003 Mark Adler\n"); + printf( + "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n"); + return 0; + } + + /* set compression level */ + level = Z_DEFAULT_COMPRESSION; + if (argv[0][0] == '-') { + if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0) + bye("invalid compression level", ""); + level = argv[0][1] - '0'; + if (*++argv == NULL) bye("no gzip file name after options", ""); + } + + /* prepare to append to gzip file */ + gd = gzscan(*argv++, &strm, level); + + /* append files on command line, or from stdin if none */ + if (*argv == NULL) + gztack(NULL, gd, &strm, 1); + else + do { + gztack(*argv, gd, &strm, argv[1] == NULL); + } while (*++argv != NULL); + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzjoin.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzjoin.c new file mode 100644 index 00000000..129347ce --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzjoin.c @@ -0,0 +1,448 @@ +/* gzjoin -- command to join gzip files into one gzip file + + Copyright (C) 2004 Mark Adler, all rights reserved + version 1.0, 11 Dec 2004 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 11 Dec 2004 - First version + * 1.1 12 Jun 2005 - Changed ssize_t to long for portability + */ + +/* + gzjoin takes one or more gzip files on the command line and writes out a + single gzip file that will uncompress to the concatenation of the + uncompressed data from the individual gzip files. gzjoin does this without + having to recompress any of the data and without having to calculate a new + crc32 for the concatenated uncompressed data. gzjoin does however have to + decompress all of the input data in order to find the bits in the compressed + data that need to be modified to concatenate the streams. + + gzjoin does not do an integrity check on the input gzip files other than + checking the gzip header and decompressing the compressed data. They are + otherwise assumed to be complete and correct. + + Each joint between gzip files removes at least 18 bytes of previous trailer + and subsequent header, and inserts an average of about three bytes to the + compressed data in order to connect the streams. The output gzip file + has a minimal ten-byte gzip header with no file name or modification time. + + This program was written to illustrate the use of the Z_BLOCK option of + inflate() and the crc32_combine() function. gzjoin will not compile with + versions of zlib earlier than 1.2.3. + */ + +#include /* fputs(), fprintf(), fwrite(), putc() */ +#include /* exit(), malloc(), free() */ +#include /* open() */ +#include /* close(), read(), lseek() */ +#include "zlib.h" + /* crc32(), crc32_combine(), inflateInit2(), inflate(), inflateEnd() */ + +#define local static + +/* exit with an error (return a value to allow use in an expression) */ +local int bail(char *why1, char *why2) +{ + fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2); + exit(1); + return 0; +} + +/* -- simple buffered file input with access to the buffer -- */ + +#define CHUNK 32768 /* must be a power of two and fit in unsigned */ + +/* bin buffered input file type */ +typedef struct { + char *name; /* name of file for error messages */ + int fd; /* file descriptor */ + unsigned left; /* bytes remaining at next */ + unsigned char *next; /* next byte to read */ + unsigned char *buf; /* allocated buffer of length CHUNK */ +} bin; + +/* close a buffered file and free allocated memory */ +local void bclose(bin *in) +{ + if (in != NULL) { + if (in->fd != -1) + close(in->fd); + if (in->buf != NULL) + free(in->buf); + free(in); + } +} + +/* open a buffered file for input, return a pointer to type bin, or NULL on + failure */ +local bin *bopen(char *name) +{ + bin *in; + + in = malloc(sizeof(bin)); + if (in == NULL) + return NULL; + in->buf = malloc(CHUNK); + in->fd = open(name, O_RDONLY, 0); + if (in->buf == NULL || in->fd == -1) { + bclose(in); + return NULL; + } + in->left = 0; + in->next = in->buf; + in->name = name; + return in; +} + +/* load buffer from file, return -1 on read error, 0 or 1 on success, with + 1 indicating that end-of-file was reached */ +local int bload(bin *in) +{ + long len; + + if (in == NULL) + return -1; + if (in->left != 0) + return 0; + in->next = in->buf; + do { + len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left); + if (len < 0) + return -1; + in->left += (unsigned)len; + } while (len != 0 && in->left < CHUNK); + return len == 0 ? 1 : 0; +} + +/* get a byte from the file, bail if end of file */ +#define bget(in) (in->left ? 0 : bload(in), \ + in->left ? (in->left--, *(in->next)++) : \ + bail("unexpected end of file on ", in->name)) + +/* get a four-byte little-endian unsigned integer from file */ +local unsigned long bget4(bin *in) +{ + unsigned long val; + + val = bget(in); + val += (unsigned long)(bget(in)) << 8; + val += (unsigned long)(bget(in)) << 16; + val += (unsigned long)(bget(in)) << 24; + return val; +} + +/* skip bytes in file */ +local void bskip(bin *in, unsigned skip) +{ + /* check pointer */ + if (in == NULL) + return; + + /* easy case -- skip bytes in buffer */ + if (skip <= in->left) { + in->left -= skip; + in->next += skip; + return; + } + + /* skip what's in buffer, discard buffer contents */ + skip -= in->left; + in->left = 0; + + /* seek past multiples of CHUNK bytes */ + if (skip > CHUNK) { + unsigned left; + + left = skip & (CHUNK - 1); + if (left == 0) { + /* exact number of chunks: seek all the way minus one byte to check + for end-of-file with a read */ + lseek(in->fd, skip - 1, SEEK_CUR); + if (read(in->fd, in->buf, 1) != 1) + bail("unexpected end of file on ", in->name); + return; + } + + /* skip the integral chunks, update skip with remainder */ + lseek(in->fd, skip - left, SEEK_CUR); + skip = left; + } + + /* read more input and skip remainder */ + bload(in); + if (skip > in->left) + bail("unexpected end of file on ", in->name); + in->left -= skip; + in->next += skip; +} + +/* -- end of buffered input functions -- */ + +/* skip the gzip header from file in */ +local void gzhead(bin *in) +{ + int flags; + + /* verify gzip magic header and compression method */ + if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8) + bail(in->name, " is not a valid gzip file"); + + /* get and verify flags */ + flags = bget(in); + if ((flags & 0xe0) != 0) + bail("unknown reserved bits set in ", in->name); + + /* skip modification time, extra flags, and os */ + bskip(in, 6); + + /* skip extra field if present */ + if (flags & 4) { + unsigned len; + + len = bget(in); + len += (unsigned)(bget(in)) << 8; + bskip(in, len); + } + + /* skip file name if present */ + if (flags & 8) + while (bget(in) != 0) + ; + + /* skip comment if present */ + if (flags & 16) + while (bget(in) != 0) + ; + + /* skip header crc if present */ + if (flags & 2) + bskip(in, 2); +} + +/* write a four-byte little-endian unsigned integer to out */ +local void put4(unsigned long val, FILE *out) +{ + putc(val & 0xff, out); + putc((val >> 8) & 0xff, out); + putc((val >> 16) & 0xff, out); + putc((val >> 24) & 0xff, out); +} + +/* Load up zlib stream from buffered input, bail if end of file */ +local void zpull(z_streamp strm, bin *in) +{ + if (in->left == 0) + bload(in); + if (in->left == 0) + bail("unexpected end of file on ", in->name); + strm->avail_in = in->left; + strm->next_in = in->next; +} + +/* Write header for gzip file to out and initialize trailer. */ +local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out) +{ + fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out); + *crc = crc32(0L, Z_NULL, 0); + *tot = 0; +} + +/* Copy the compressed data from name, zeroing the last block bit of the last + block if clr is true, and adding empty blocks as needed to get to a byte + boundary. If clr is false, then the last block becomes the last block of + the output, and the gzip trailer is written. crc and tot maintains the + crc and length (modulo 2^32) of the output for the trailer. The resulting + gzip file is written to out. gzinit() must be called before the first call + of gzcopy() to write the gzip header and to initialize crc and tot. */ +local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot, + FILE *out) +{ + int ret; /* return value from zlib functions */ + int pos; /* where the "last block" bit is in byte */ + int last; /* true if processing the last block */ + bin *in; /* buffered input file */ + unsigned char *start; /* start of compressed data in buffer */ + unsigned char *junk; /* buffer for uncompressed data -- discarded */ + z_off_t len; /* length of uncompressed data (support > 4 GB) */ + z_stream strm; /* zlib inflate stream */ + + /* open gzip file and skip header */ + in = bopen(name); + if (in == NULL) + bail("could not open ", name); + gzhead(in); + + /* allocate buffer for uncompressed data and initialize raw inflate + stream */ + junk = malloc(CHUNK); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); + if (junk == NULL || ret != Z_OK) + bail("out of memory", ""); + + /* inflate and copy compressed data, clear last-block bit if requested */ + len = 0; + zpull(&strm, in); + start = strm.next_in; + last = start[0] & 1; + if (last && clr) + start[0] &= ~1; + strm.avail_out = 0; + for (;;) { + /* if input used and output done, write used input and get more */ + if (strm.avail_in == 0 && strm.avail_out != 0) { + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + + /* decompress -- return early when end-of-block reached */ + strm.avail_out = CHUNK; + strm.next_out = junk; + ret = inflate(&strm, Z_BLOCK); + switch (ret) { + case Z_MEM_ERROR: + bail("out of memory", ""); + case Z_DATA_ERROR: + bail("invalid compressed data in ", in->name); + } + + /* update length of uncompressed data */ + len += CHUNK - strm.avail_out; + + /* check for block boundary (only get this when block copied out) */ + if (strm.data_type & 128) { + /* if that was the last block, then done */ + if (last) + break; + + /* number of unused bits in last byte */ + pos = strm.data_type & 7; + + /* find the next last-block bit */ + if (pos != 0) { + /* next last-block bit is in last used byte */ + pos = 0x100 >> pos; + last = strm.next_in[-1] & pos; + if (last && clr) + strm.next_in[-1] &= ~pos; + } + else { + /* next last-block bit is in next unused byte */ + if (strm.avail_in == 0) { + /* don't have that byte yet -- get it */ + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + last = strm.next_in[0] & 1; + if (last && clr) + strm.next_in[0] &= ~1; + } + } + } + + /* update buffer with unused input */ + in->left = strm.avail_in; + in->next = strm.next_in; + + /* copy used input, write empty blocks to get to byte boundary */ + pos = strm.data_type & 7; + fwrite(start, 1, in->next - start - 1, out); + last = in->next[-1]; + if (pos == 0 || !clr) + /* already at byte boundary, or last file: write last byte */ + putc(last, out); + else { + /* append empty blocks to last byte */ + last &= ((0x100 >> pos) - 1); /* assure unused bits are zero */ + if (pos & 1) { + /* odd -- append an empty stored block */ + putc(last, out); + if (pos == 1) + putc(0, out); /* two more bits in block header */ + fwrite("\0\0\xff\xff", 1, 4, out); + } + else { + /* even -- append 1, 2, or 3 empty fixed blocks */ + switch (pos) { + case 6: + putc(last | 8, out); + last = 0; + case 4: + putc(last | 0x20, out); + last = 0; + case 2: + putc(last | 0x80, out); + putc(0, out); + } + } + } + + /* update crc and tot */ + *crc = crc32_combine(*crc, bget4(in), len); + *tot += (unsigned long)len; + + /* clean up */ + inflateEnd(&strm); + free(junk); + bclose(in); + + /* write trailer if this is the last gzip file */ + if (!clr) { + put4(*crc, out); + put4(*tot, out); + } +} + +/* join the gzip files on the command line, write result to stdout */ +int main(int argc, char **argv) +{ + unsigned long crc, tot; /* running crc and total uncompressed length */ + + /* skip command name */ + argc--; + argv++; + + /* show usage if no arguments */ + if (argc == 0) { + fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n", + stderr); + return 0; + } + + /* join gzip files on command line and write to stdout */ + gzinit(&crc, &tot, stdout); + while (argc--) + gzcopy(*argv++, argc, &crc, &tot, stdout); + + /* done */ + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzlog.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzlog.c new file mode 100644 index 00000000..d70aacab --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzlog.c @@ -0,0 +1,1058 @@ +/* + * gzlog.c + * Copyright (C) 2004, 2008 Mark Adler, all rights reserved + * For conditions of distribution and use, see copyright notice in gzlog.h + * version 2.0, 25 Apr 2008 + */ + +/* + gzlog provides a mechanism for frequently appending short strings to a gzip + file that is efficient both in execution time and compression ratio. The + strategy is to write the short strings in an uncompressed form to the end of + the gzip file, only compressing when the amount of uncompressed data has + reached a given threshold. + + gzlog also provides protection against interruptions in the process due to + system crashes. The status of the operation is recorded in an extra field + in the gzip file, and is only updated once the gzip file is brought to a + valid state. The last data to be appended or compressed is saved in an + auxiliary file, so that if the operation is interrupted, it can be completed + the next time an append operation is attempted. + + gzlog maintains another auxiliary file with the last 32K of data from the + compressed portion, which is preloaded for the compression of the subsequent + data. This minimizes the impact to the compression ratio of appending. + */ + +/* + Operations Concept: + + Files (log name "foo"): + foo.gz -- gzip file with the complete log + foo.add -- last message to append or last data to compress + foo.dict -- dictionary of the last 32K of data for next compression + foo.temp -- temporary dictionary file for compression after this one + foo.lock -- lock file for reading and writing the other files + foo.repairs -- log file for log file recovery operations (not compressed) + + gzip file structure: + - fixed-length (no file name) header with extra field (see below) + - compressed data ending initially with empty stored block + - uncompressed data filling out originally empty stored block and + subsequent stored blocks as needed (16K max each) + - gzip trailer + - no junk at end (no other gzip streams) + + When appending data, the information in the first three items above plus the + foo.add file are sufficient to recover an interrupted append operation. The + extra field has the necessary information to restore the start of the last + stored block and determine where to append the data in the foo.add file, as + well as the crc and length of the gzip data before the append operation. + + The foo.add file is created before the gzip file is marked for append, and + deleted after the gzip file is marked as complete. So if the append + operation is interrupted, the data to add will still be there. If due to + some external force, the foo.add file gets deleted between when the append + operation was interrupted and when recovery is attempted, the gzip file will + still be restored, but without the appended data. + + When compressing data, the information in the first two items above plus the + foo.add file are sufficient to recover an interrupted compress operation. + The extra field has the necessary information to find the end of the + compressed data, and contains both the crc and length of just the compressed + data and of the complete set of data including the contents of the foo.add + file. + + Again, the foo.add file is maintained during the compress operation in case + of an interruption. If in the unlikely event the foo.add file with the data + to be compressed is missing due to some external force, a gzip file with + just the previous compressed data will be reconstructed. In this case, all + of the data that was to be compressed is lost (approximately one megabyte). + This will not occur if all that happened was an interruption of the compress + operation. + + The third state that is marked is the replacement of the old dictionary with + the new dictionary after a compress operation. Once compression is + complete, the gzip file is marked as being in the replace state. This + completes the gzip file, so an interrupt after being so marked does not + result in recompression. Then the dictionary file is replaced, and the gzip + file is marked as completed. This state prevents the possibility of + restarting compression with the wrong dictionary file. + + All three operations are wrapped by a lock/unlock procedure. In order to + gain exclusive access to the log files, first a foo.lock file must be + exclusively created. When all operations are complete, the lock is + released by deleting the foo.lock file. If when attempting to create the + lock file, it already exists and the modify time of the lock file is more + than five minutes old (set by the PATIENCE define below), then the old + lock file is considered stale and deleted, and the exclusive creation of + the lock file is retried. To assure that there are no false assessments + of the staleness of the lock file, the operations periodically touch the + lock file to update the modified date. + + Following is the definition of the extra field with all of the information + required to enable the above append and compress operations and their + recovery if interrupted. Multi-byte values are stored little endian + (consistent with the gzip format). File pointers are eight bytes long. + The crc's and lengths for the gzip trailer are four bytes long. (Note that + the length at the end of a gzip file is used for error checking only, and + for large files is actually the length modulo 2^32.) The stored block + length is two bytes long. The gzip extra field two-byte identification is + "ap" for append. It is assumed that writing the extra field to the file is + an "atomic" operation. That is, either all of the extra field is written + to the file, or none of it is, if the operation is interrupted right at the + point of updating the extra field. This is a reasonable assumption, since + the extra field is within the first 52 bytes of the file, which is smaller + than any expected block size for a mass storage device (usually 512 bytes or + larger). + + Extra field (35 bytes): + - Pointer to first stored block length -- this points to the two-byte length + of the first stored block, which is followed by the two-byte, one's + complement of that length. The stored block length is preceded by the + three-bit header of the stored block, which is the actual start of the + stored block in the deflate format. See the bit offset field below. + - Pointer to the last stored block length. This is the same as above, but + for the last stored block of the uncompressed data in the gzip file. + Initially this is the same as the first stored block length pointer. + When the stored block gets to 16K (see the MAX_STORE define), then a new + stored block as added, at which point the last stored block length pointer + is different from the first stored block length pointer. When they are + different, the first bit of the last stored block header is eight bits, or + one byte back from the block length. + - Compressed data crc and length. This is the crc and length of the data + that is in the compressed portion of the deflate stream. These are used + only in the event that the foo.add file containing the data to compress is + lost after a compress operation is interrupted. + - Total data crc and length. This is the crc and length of all of the data + stored in the gzip file, compressed and uncompressed. It is used to + reconstruct the gzip trailer when compressing, as well as when recovering + interrupted operations. + - Final stored block length. This is used to quickly find where to append, + and allows the restoration of the original final stored block state when + an append operation is interrupted. + - First stored block start as the number of bits back from the final stored + block first length byte. This value is in the range of 3..10, and is + stored as the low three bits of the final byte of the extra field after + subtracting three (0..7). This allows the last-block bit of the stored + block header to be updated when a new stored block is added, for the case + when the first stored block and the last stored block are the same. (When + they are different, the numbers of bits back is known to be eight.) This + also allows for new compressed data to be appended to the old compressed + data in the compress operation, overwriting the previous first stored + block, or for the compressed data to be terminated and a valid gzip file + reconstructed on the off chance that a compression operation was + interrupted and the data to compress in the foo.add file was deleted. + - The operation in process. This is the next two bits in the last byte (the + bits under the mask 0x18). The are interpreted as 0: nothing in process, + 1: append in process, 2: compress in process, 3: replace in process. + - The top three bits of the last byte in the extra field are reserved and + are currently set to zero. + + Main procedure: + - Exclusively create the foo.lock file using the O_CREAT and O_EXCL modes of + the system open() call. If the modify time of an existing lock file is + more than PATIENCE seconds old, then the lock file is deleted and the + exclusive create is retried. + - Load the extra field from the foo.gz file, and see if an operation was in + progress but not completed. If so, apply the recovery procedure below. + - Perform the append procedure with the provided data. + - If the uncompressed data in the foo.gz file is 1MB or more, apply the + compress procedure. + - Delete the foo.lock file. + + Append procedure: + - Put what to append in the foo.add file so that the operation can be + restarted if this procedure is interrupted. + - Mark the foo.gz extra field with the append operation in progress. + + Restore the original last-block bit and stored block length of the last + stored block from the information in the extra field, in case a previous + append operation was interrupted. + - Append the provided data to the last stored block, creating new stored + blocks as needed and updating the stored blocks last-block bits and + lengths. + - Update the crc and length with the new data, and write the gzip trailer. + - Write over the extra field (with a single write operation) with the new + pointers, lengths, and crc's, and mark the gzip file as not in process. + Though there is still a foo.add file, it will be ignored since nothing + is in process. If a foo.add file is leftover from a previously + completed operation, it is truncated when writing new data to it. + - Delete the foo.add file. + + Compress and replace procedures: + - Read all of the uncompressed data in the stored blocks in foo.gz and write + it to foo.add. Also write foo.temp with the last 32K of that data to + provide a dictionary for the next invocation of this procedure. + - Rewrite the extra field marking foo.gz with a compression in process. + * If there is no data provided to compress (due to a missing foo.add file + when recovering), reconstruct and truncate the foo.gz file to contain + only the previous compressed data and proceed to the step after the next + one. Otherwise ... + - Compress the data with the dictionary in foo.dict, and write to the + foo.gz file starting at the bit immediately following the last previously + compressed block. If there is no foo.dict, proceed anyway with the + compression at slightly reduced efficiency. (For the foo.dict file to be + missing requires some external failure beyond simply the interruption of + a compress operation.) During this process, the foo.lock file is + periodically touched to assure that that file is not considered stale by + another process before we're done. The deflation is terminated with a + non-last empty static block (10 bits long), that is then located and + written over by a last-bit-set empty stored block. + - Append the crc and length of the data in the gzip file (previously + calculated during the append operations). + - Write over the extra field with the updated stored block offsets, bits + back, crc's, and lengths, and mark foo.gz as in process for a replacement + of the dictionary. + @ Delete the foo.add file. + - Replace foo.dict with foo.temp. + - Write over the extra field, marking foo.gz as complete. + + Recovery procedure: + - If not a replace recovery, read in the foo.add file, and provide that data + to the appropriate recovery below. If there is no foo.add file, provide + a zero data length to the recovery. In that case, the append recovery + restores the foo.gz to the previous compressed + uncompressed data state. + For the the compress recovery, a missing foo.add file results in foo.gz + being restored to the previous compressed-only data state. + - Append recovery: + - Pick up append at + step above + - Compress recovery: + - Pick up compress at * step above + - Replace recovery: + - Pick up compress at @ step above + - Log the repair with a date stamp in foo.repairs + */ + +#include +#include /* rename, fopen, fprintf, fclose */ +#include /* malloc, free */ +#include /* strlen, strrchr, strcpy, strncpy, strcmp */ +#include /* open */ +#include /* lseek, read, write, close, unlink, sleep, */ + /* ftruncate, fsync */ +#include /* errno */ +#include /* time, ctime */ +#include /* stat */ +#include /* utimes */ +#include "zlib.h" /* crc32 */ + +#include "gzlog.h" /* header for external access */ + +#define local static +typedef unsigned int uint; +typedef unsigned long ulong; + +/* Macro for debugging to deterministically force recovery operations */ +#ifdef DEBUG + #include /* longjmp */ + jmp_buf gzlog_jump; /* where to go back to */ + int gzlog_bail = 0; /* which point to bail at (1..8) */ + int gzlog_count = -1; /* number of times through to wait */ +# define BAIL(n) do { if (n == gzlog_bail && gzlog_count-- == 0) \ + longjmp(gzlog_jump, gzlog_bail); } while (0) +#else +# define BAIL(n) +#endif + +/* how old the lock file can be in seconds before considering it stale */ +#define PATIENCE 300 + +/* maximum stored block size in Kbytes -- must be in 1..63 */ +#define MAX_STORE 16 + +/* number of stored Kbytes to trigger compression (must be >= 32 to allow + dictionary construction, and <= 204 * MAX_STORE, in order for >> 10 to + discard the stored block headers contribution of five bytes each) */ +#define TRIGGER 1024 + +/* size of a deflate dictionary (this cannot be changed) */ +#define DICT 32768U + +/* values for the operation (2 bits) */ +#define NO_OP 0 +#define APPEND_OP 1 +#define COMPRESS_OP 2 +#define REPLACE_OP 3 + +/* macros to extract little-endian integers from an unsigned byte buffer */ +#define PULL2(p) ((p)[0]+((uint)((p)[1])<<8)) +#define PULL4(p) (PULL2(p)+((ulong)PULL2(p+2)<<16)) +#define PULL8(p) (PULL4(p)+((off_t)PULL4(p+4)<<32)) + +/* macros to store integers into a byte buffer in little-endian order */ +#define PUT2(p,a) do {(p)[0]=a;(p)[1]=(a)>>8;} while(0) +#define PUT4(p,a) do {PUT2(p,a);PUT2(p+2,a>>16);} while(0) +#define PUT8(p,a) do {PUT4(p,a);PUT4(p+4,a>>32);} while(0) + +/* internal structure for log information */ +#define LOGID "\106\035\172" /* should be three non-zero characters */ +struct log { + char id[4]; /* contains LOGID to detect inadvertent overwrites */ + int fd; /* file descriptor for .gz file, opened read/write */ + char *path; /* allocated path, e.g. "/var/log/foo" or "foo" */ + char *end; /* end of path, for appending suffices such as ".gz" */ + off_t first; /* offset of first stored block first length byte */ + int back; /* location of first block id in bits back from first */ + uint stored; /* bytes currently in last stored block */ + off_t last; /* offset of last stored block first length byte */ + ulong ccrc; /* crc of compressed data */ + ulong clen; /* length (modulo 2^32) of compressed data */ + ulong tcrc; /* crc of total data */ + ulong tlen; /* length (modulo 2^32) of total data */ + time_t lock; /* last modify time of our lock file */ +}; + +/* gzip header for gzlog */ +local unsigned char log_gzhead[] = { + 0x1f, 0x8b, /* magic gzip id */ + 8, /* compression method is deflate */ + 4, /* there is an extra field (no file name) */ + 0, 0, 0, 0, /* no modification time provided */ + 0, 0xff, /* no extra flags, no OS specified */ + 39, 0, 'a', 'p', 35, 0 /* extra field with "ap" subfield */ + /* 35 is EXTRA, 39 is EXTRA + 4 */ +}; + +#define HEAD sizeof(log_gzhead) /* should be 16 */ + +/* initial gzip extra field content (52 == HEAD + EXTRA + 1) */ +local unsigned char log_gzext[] = { + 52, 0, 0, 0, 0, 0, 0, 0, /* offset of first stored block length */ + 52, 0, 0, 0, 0, 0, 0, 0, /* offset of last stored block length */ + 0, 0, 0, 0, 0, 0, 0, 0, /* compressed data crc and length */ + 0, 0, 0, 0, 0, 0, 0, 0, /* total data crc and length */ + 0, 0, /* final stored block data length */ + 5 /* op is NO_OP, last bit 8 bits back */ +}; + +#define EXTRA sizeof(log_gzext) /* should be 35 */ + +/* initial gzip data and trailer */ +local unsigned char log_gzbody[] = { + 1, 0, 0, 0xff, 0xff, /* empty stored block (last) */ + 0, 0, 0, 0, /* crc */ + 0, 0, 0, 0 /* uncompressed length */ +}; + +#define BODY sizeof(log_gzbody) + +/* Exclusively create foo.lock in order to negotiate exclusive access to the + foo.* files. If the modify time of an existing lock file is greater than + PATIENCE seconds in the past, then consider the lock file to have been + abandoned, delete it, and try the exclusive create again. Save the lock + file modify time for verification of ownership. Return 0 on success, or -1 + on failure, usually due to an access restriction or invalid path. Note that + if stat() or unlink() fails, it may be due to another process noticing the + abandoned lock file a smidge sooner and deleting it, so those are not + flagged as an error. */ +local int log_lock(struct log *log) +{ + int fd; + struct stat st; + + strcpy(log->end, ".lock"); + while ((fd = open(log->path, O_CREAT | O_EXCL, 0644)) < 0) { + if (errno != EEXIST) + return -1; + if (stat(log->path, &st) == 0 && time(NULL) - st.st_mtime > PATIENCE) { + unlink(log->path); + continue; + } + sleep(2); /* relinquish the CPU for two seconds while waiting */ + } + close(fd); + if (stat(log->path, &st) == 0) + log->lock = st.st_mtime; + return 0; +} + +/* Update the modify time of the lock file to now, in order to prevent another + task from thinking that the lock is stale. Save the lock file modify time + for verification of ownership. */ +local void log_touch(struct log *log) +{ + struct stat st; + + strcpy(log->end, ".lock"); + utimes(log->path, NULL); + if (stat(log->path, &st) == 0) + log->lock = st.st_mtime; +} + +/* Check the log file modify time against what is expected. Return true if + this is not our lock. If it is our lock, touch it to keep it. */ +local int log_check(struct log *log) +{ + struct stat st; + + strcpy(log->end, ".lock"); + if (stat(log->path, &st) || st.st_mtime != log->lock) + return 1; + log_touch(log); + return 0; +} + +/* Unlock a previously acquired lock, but only if it's ours. */ +local void log_unlock(struct log *log) +{ + if (log_check(log)) + return; + strcpy(log->end, ".lock"); + unlink(log->path); + log->lock = 0; +} + +/* Check the gzip header and read in the extra field, filling in the values in + the log structure. Return op on success or -1 if the gzip header was not as + expected. op is the current operation in progress last written to the extra + field. This assumes that the gzip file has already been opened, with the + file descriptor log->fd. */ +local int log_head(struct log *log) +{ + int op; + unsigned char buf[HEAD + EXTRA]; + + if (lseek(log->fd, 0, SEEK_SET) < 0 || + read(log->fd, buf, HEAD + EXTRA) != HEAD + EXTRA || + memcmp(buf, log_gzhead, HEAD)) { + return -1; + } + log->first = PULL8(buf + HEAD); + log->last = PULL8(buf + HEAD + 8); + log->ccrc = PULL4(buf + HEAD + 16); + log->clen = PULL4(buf + HEAD + 20); + log->tcrc = PULL4(buf + HEAD + 24); + log->tlen = PULL4(buf + HEAD + 28); + log->stored = PULL2(buf + HEAD + 32); + log->back = 3 + (buf[HEAD + 34] & 7); + op = (buf[HEAD + 34] >> 3) & 3; + return op; +} + +/* Write over the extra field contents, marking the operation as op. Use fsync + to assure that the device is written to, and in the requested order. This + operation, and only this operation, is assumed to be atomic in order to + assure that the log is recoverable in the event of an interruption at any + point in the process. Return -1 if the write to foo.gz failed. */ +local int log_mark(struct log *log, int op) +{ + int ret; + unsigned char ext[EXTRA]; + + PUT8(ext, log->first); + PUT8(ext + 8, log->last); + PUT4(ext + 16, log->ccrc); + PUT4(ext + 20, log->clen); + PUT4(ext + 24, log->tcrc); + PUT4(ext + 28, log->tlen); + PUT2(ext + 32, log->stored); + ext[34] = log->back - 3 + (op << 3); + fsync(log->fd); + ret = lseek(log->fd, HEAD, SEEK_SET) < 0 || + write(log->fd, ext, EXTRA) != EXTRA ? -1 : 0; + fsync(log->fd); + return ret; +} + +/* Rewrite the last block header bits and subsequent zero bits to get to a byte + boundary, setting the last block bit if last is true, and then write the + remainder of the stored block header (length and one's complement). Leave + the file pointer after the end of the last stored block data. Return -1 if + there is a read or write failure on the foo.gz file */ +local int log_last(struct log *log, int last) +{ + int back, len, mask; + unsigned char buf[6]; + + /* determine the locations of the bytes and bits to modify */ + back = log->last == log->first ? log->back : 8; + len = back > 8 ? 2 : 1; /* bytes back from log->last */ + mask = 0x80 >> ((back - 1) & 7); /* mask for block last-bit */ + + /* get the byte to modify (one or two back) into buf[0] -- don't need to + read the byte if the last-bit is eight bits back, since in that case + the entire byte will be modified */ + buf[0] = 0; + if (back != 8 && (lseek(log->fd, log->last - len, SEEK_SET) < 0 || + read(log->fd, buf, 1) != 1)) + return -1; + + /* change the last-bit of the last stored block as requested -- note + that all bits above the last-bit are set to zero, per the type bits + of a stored block being 00 and per the convention that the bits to + bring the stream to a byte boundary are also zeros */ + buf[1] = 0; + buf[2 - len] = (*buf & (mask - 1)) + (last ? mask : 0); + + /* write the modified stored block header and lengths, move the file + pointer to after the last stored block data */ + PUT2(buf + 2, log->stored); + PUT2(buf + 4, log->stored ^ 0xffff); + return lseek(log->fd, log->last - len, SEEK_SET) < 0 || + write(log->fd, buf + 2 - len, len + 4) != len + 4 || + lseek(log->fd, log->stored, SEEK_CUR) < 0 ? -1 : 0; +} + +/* Append len bytes from data to the locked and open log file. len may be zero + if recovering and no .add file was found. In that case, the previous state + of the foo.gz file is restored. The data is appended uncompressed in + deflate stored blocks. Return -1 if there was an error reading or writing + the foo.gz file. */ +local int log_append(struct log *log, unsigned char *data, size_t len) +{ + uint put; + off_t end; + unsigned char buf[8]; + + /* set the last block last-bit and length, in case recovering an + interrupted append, then position the file pointer to append to the + block */ + if (log_last(log, 1)) + return -1; + + /* append, adding stored blocks and updating the offset of the last stored + block as needed, and update the total crc and length */ + while (len) { + /* append as much as we can to the last block */ + put = (MAX_STORE << 10) - log->stored; + if (put > len) + put = (uint)len; + if (put) { + if (write(log->fd, data, put) != put) + return -1; + BAIL(1); + log->tcrc = crc32(log->tcrc, data, put); + log->tlen += put; + log->stored += put; + data += put; + len -= put; + } + + /* if we need to, add a new empty stored block */ + if (len) { + /* mark current block as not last */ + if (log_last(log, 0)) + return -1; + + /* point to new, empty stored block */ + log->last += 4 + log->stored + 1; + log->stored = 0; + } + + /* mark last block as last, update its length */ + if (log_last(log, 1)) + return -1; + BAIL(2); + } + + /* write the new crc and length trailer, and truncate just in case (could + be recovering from partial append with a missing foo.add file) */ + PUT4(buf, log->tcrc); + PUT4(buf + 4, log->tlen); + if (write(log->fd, buf, 8) != 8 || + (end = lseek(log->fd, 0, SEEK_CUR)) < 0 || ftruncate(log->fd, end)) + return -1; + + /* write the extra field, marking the log file as done, delete .add file */ + if (log_mark(log, NO_OP)) + return -1; + strcpy(log->end, ".add"); + unlink(log->path); /* ignore error, since may not exist */ + return 0; +} + +/* Replace the foo.dict file with the foo.temp file. Also delete the foo.add + file, since the compress operation may have been interrupted before that was + done. Returns 1 if memory could not be allocated, or -1 if reading or + writing foo.gz fails, or if the rename fails for some reason other than + foo.temp not existing. foo.temp not existing is a permitted error, since + the replace operation may have been interrupted after the rename is done, + but before foo.gz is marked as complete. */ +local int log_replace(struct log *log) +{ + int ret; + char *dest; + + /* delete foo.add file */ + strcpy(log->end, ".add"); + unlink(log->path); /* ignore error, since may not exist */ + BAIL(3); + + /* rename foo.name to foo.dict, replacing foo.dict if it exists */ + strcpy(log->end, ".dict"); + dest = malloc(strlen(log->path) + 1); + if (dest == NULL) + return -2; + strcpy(dest, log->path); + strcpy(log->end, ".temp"); + ret = rename(log->path, dest); + free(dest); + if (ret && errno != ENOENT) + return -1; + BAIL(4); + + /* mark the foo.gz file as done */ + return log_mark(log, NO_OP); +} + +/* Compress the len bytes at data and append the compressed data to the + foo.gz deflate data immediately after the previous compressed data. This + overwrites the previous uncompressed data, which was stored in foo.add + and is the data provided in data[0..len-1]. If this operation is + interrupted, it picks up at the start of this routine, with the foo.add + file read in again. If there is no data to compress (len == 0), then we + simply terminate the foo.gz file after the previously compressed data, + appending a final empty stored block and the gzip trailer. Return -1 if + reading or writing the log.gz file failed, or -2 if there was a memory + allocation failure. */ +local int log_compress(struct log *log, unsigned char *data, size_t len) +{ + int fd; + uint got, max; + ssize_t dict; + off_t end; + z_stream strm; + unsigned char buf[DICT]; + + /* compress and append compressed data */ + if (len) { + /* set up for deflate, allocating memory */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY) != Z_OK) + return -2; + + /* read in dictionary (last 32K of data that was compressed) */ + strcpy(log->end, ".dict"); + fd = open(log->path, O_RDONLY, 0); + if (fd >= 0) { + dict = read(fd, buf, DICT); + close(fd); + if (dict < 0) { + deflateEnd(&strm); + return -1; + } + if (dict) + deflateSetDictionary(&strm, buf, (uint)dict); + } + log_touch(log); + + /* prime deflate with last bits of previous block, position write + pointer to write those bits and overwrite what follows */ + if (lseek(log->fd, log->first - (log->back > 8 ? 2 : 1), + SEEK_SET) < 0 || + read(log->fd, buf, 1) != 1 || lseek(log->fd, -1, SEEK_CUR) < 0) { + deflateEnd(&strm); + return -1; + } + deflatePrime(&strm, (8 - log->back) & 7, *buf); + + /* compress, finishing with a partial non-last empty static block */ + strm.next_in = data; + max = (((uint)0 - 1) >> 1) + 1; /* in case int smaller than size_t */ + do { + strm.avail_in = len > max ? max : (uint)len; + len -= strm.avail_in; + do { + strm.avail_out = DICT; + strm.next_out = buf; + deflate(&strm, len ? Z_NO_FLUSH : Z_PARTIAL_FLUSH); + got = DICT - strm.avail_out; + if (got && write(log->fd, buf, got) != got) { + deflateEnd(&strm); + return -1; + } + log_touch(log); + } while (strm.avail_out == 0); + } while (len); + deflateEnd(&strm); + BAIL(5); + + /* find start of empty static block -- scanning backwards the first one + bit is the second bit of the block, if the last byte is zero, then + we know the byte before that has a one in the top bit, since an + empty static block is ten bits long */ + if ((log->first = lseek(log->fd, -1, SEEK_CUR)) < 0 || + read(log->fd, buf, 1) != 1) + return -1; + log->first++; + if (*buf) { + log->back = 1; + while ((*buf & ((uint)1 << (8 - log->back++))) == 0) + ; /* guaranteed to terminate, since *buf != 0 */ + } + else + log->back = 10; + + /* update compressed crc and length */ + log->ccrc = log->tcrc; + log->clen = log->tlen; + } + else { + /* no data to compress -- fix up existing gzip stream */ + log->tcrc = log->ccrc; + log->tlen = log->clen; + } + + /* complete and truncate gzip stream */ + log->last = log->first; + log->stored = 0; + PUT4(buf, log->tcrc); + PUT4(buf + 4, log->tlen); + if (log_last(log, 1) || write(log->fd, buf, 8) != 8 || + (end = lseek(log->fd, 0, SEEK_CUR)) < 0 || ftruncate(log->fd, end)) + return -1; + BAIL(6); + + /* mark as being in the replace operation */ + if (log_mark(log, REPLACE_OP)) + return -1; + + /* execute the replace operation and mark the file as done */ + return log_replace(log); +} + +/* log a repair record to the .repairs file */ +local void log_log(struct log *log, int op, char *record) +{ + time_t now; + FILE *rec; + + now = time(NULL); + strcpy(log->end, ".repairs"); + rec = fopen(log->path, "a"); + if (rec == NULL) + return; + fprintf(rec, "%.24s %s recovery: %s\n", ctime(&now), op == APPEND_OP ? + "append" : (op == COMPRESS_OP ? "compress" : "replace"), record); + fclose(rec); + return; +} + +/* Recover the interrupted operation op. First read foo.add for recovering an + append or compress operation. Return -1 if there was an error reading or + writing foo.gz or reading an existing foo.add, or -2 if there was a memory + allocation failure. */ +local int log_recover(struct log *log, int op) +{ + int fd, ret = 0; + unsigned char *data = NULL; + size_t len = 0; + struct stat st; + + /* log recovery */ + log_log(log, op, "start"); + + /* load foo.add file if expected and present */ + if (op == APPEND_OP || op == COMPRESS_OP) { + strcpy(log->end, ".add"); + if (stat(log->path, &st) == 0 && st.st_size) { + len = (size_t)(st.st_size); + if (len != st.st_size || (data = malloc(st.st_size)) == NULL) { + log_log(log, op, "allocation failure"); + return -2; + } + if ((fd = open(log->path, O_RDONLY, 0)) < 0) { + log_log(log, op, ".add file read failure"); + return -1; + } + ret = read(fd, data, len) != len; + close(fd); + if (ret) { + log_log(log, op, ".add file read failure"); + return -1; + } + log_log(log, op, "loaded .add file"); + } + else + log_log(log, op, "missing .add file!"); + } + + /* recover the interrupted operation */ + switch (op) { + case APPEND_OP: + ret = log_append(log, data, len); + break; + case COMPRESS_OP: + ret = log_compress(log, data, len); + break; + case REPLACE_OP: + ret = log_replace(log); + } + + /* log status */ + log_log(log, op, ret ? "failure" : "complete"); + + /* clean up */ + if (data != NULL) + free(data); + return ret; +} + +/* Close the foo.gz file (if open) and release the lock. */ +local void log_close(struct log *log) +{ + if (log->fd >= 0) + close(log->fd); + log->fd = -1; + log_unlock(log); +} + +/* Open foo.gz, verify the header, and load the extra field contents, after + first creating the foo.lock file to gain exclusive access to the foo.* + files. If foo.gz does not exist or is empty, then write the initial header, + extra, and body content of an empty foo.gz log file. If there is an error + creating the lock file due to access restrictions, or an error reading or + writing the foo.gz file, or if the foo.gz file is not a proper log file for + this object (e.g. not a gzip file or does not contain the expected extra + field), then return true. If there is an error, the lock is released. + Otherwise, the lock is left in place. */ +local int log_open(struct log *log) +{ + int op; + + /* release open file resource if left over -- can occur if lock lost + between gzlog_open() and gzlog_write() */ + if (log->fd >= 0) + close(log->fd); + log->fd = -1; + + /* negotiate exclusive access */ + if (log_lock(log) < 0) + return -1; + + /* open the log file, foo.gz */ + strcpy(log->end, ".gz"); + log->fd = open(log->path, O_RDWR | O_CREAT, 0644); + if (log->fd < 0) { + log_close(log); + return -1; + } + + /* if new, initialize foo.gz with an empty log, delete old dictionary */ + if (lseek(log->fd, 0, SEEK_END) == 0) { + if (write(log->fd, log_gzhead, HEAD) != HEAD || + write(log->fd, log_gzext, EXTRA) != EXTRA || + write(log->fd, log_gzbody, BODY) != BODY) { + log_close(log); + return -1; + } + strcpy(log->end, ".dict"); + unlink(log->path); + } + + /* verify log file and load extra field information */ + if ((op = log_head(log)) < 0) { + log_close(log); + return -1; + } + + /* check for interrupted process and if so, recover */ + if (op != NO_OP && log_recover(log, op)) { + log_close(log); + return -1; + } + + /* touch the lock file to prevent another process from grabbing it */ + log_touch(log); + return 0; +} + +/* See gzlog.h for the description of the external methods below */ +gzlog *gzlog_open(char *path) +{ + size_t n; + struct log *log; + + /* check arguments */ + if (path == NULL || *path == 0) + return NULL; + + /* allocate and initialize log structure */ + log = malloc(sizeof(struct log)); + if (log == NULL) + return NULL; + strcpy(log->id, LOGID); + log->fd = -1; + + /* save path and end of path for name construction */ + n = strlen(path); + log->path = malloc(n + 9); /* allow for ".repairs" */ + if (log->path == NULL) { + free(log); + return NULL; + } + strcpy(log->path, path); + log->end = log->path + n; + + /* gain exclusive access and verify log file -- may perform a + recovery operation if needed */ + if (log_open(log)) { + free(log->path); + free(log); + return NULL; + } + + /* return pointer to log structure */ + return log; +} + +/* gzlog_compress() return values: + 0: all good + -1: file i/o error (usually access issue) + -2: memory allocation failure + -3: invalid log pointer argument */ +int gzlog_compress(gzlog *logd) +{ + int fd, ret; + uint block; + size_t len, next; + unsigned char *data, buf[5]; + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID) || len < 0) + return -3; + + /* see if we lost the lock -- if so get it again and reload the extra + field information (it probably changed), recover last operation if + necessary */ + if (log_check(log) && log_open(log)) + return -1; + + /* create space for uncompressed data */ + len = ((size_t)(log->last - log->first) & ~(((size_t)1 << 10) - 1)) + + log->stored; + if ((data = malloc(len)) == NULL) + return -2; + + /* do statement here is just a cheap trick for error handling */ + do { + /* read in the uncompressed data */ + if (lseek(log->fd, log->first - 1, SEEK_SET) < 0) + break; + next = 0; + while (next < len) { + if (read(log->fd, buf, 5) != 5) + break; + block = PULL2(buf + 1); + if (next + block > len || + read(log->fd, (char *)data + next, block) != block) + break; + next += block; + } + if (lseek(log->fd, 0, SEEK_CUR) != log->last + 4 + log->stored) + break; + log_touch(log); + + /* write the uncompressed data to the .add file */ + strcpy(log->end, ".add"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + break; + ret = write(fd, data, len) != len; + if (ret | close(fd)) + break; + log_touch(log); + + /* write the dictionary for the next compress to the .temp file */ + strcpy(log->end, ".temp"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + break; + next = DICT > len ? len : DICT; + ret = write(fd, (char *)data + len - next, next) != next; + if (ret | close(fd)) + break; + log_touch(log); + + /* roll back to compressed data, mark the compress in progress */ + log->last = log->first; + log->stored = 0; + if (log_mark(log, COMPRESS_OP)) + break; + BAIL(7); + + /* compress and append the data (clears mark) */ + ret = log_compress(log, data, len); + free(data); + return ret; + } while (0); + + /* broke out of do above on i/o error */ + free(data); + return -1; +} + +/* gzlog_write() return values: + 0: all good + -1: file i/o error (usually access issue) + -2: memory allocation failure + -3: invalid log pointer argument */ +int gzlog_write(gzlog *logd, void *data, size_t len) +{ + int fd, ret; + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID) || len < 0) + return -3; + if (data == NULL || len == 0) + return 0; + + /* see if we lost the lock -- if so get it again and reload the extra + field information (it probably changed), recover last operation if + necessary */ + if (log_check(log) && log_open(log)) + return -1; + + /* create and write .add file */ + strcpy(log->end, ".add"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + return -1; + ret = write(fd, data, len) != len; + if (ret | close(fd)) + return -1; + log_touch(log); + + /* mark log file with append in progress */ + if (log_mark(log, APPEND_OP)) + return -1; + BAIL(8); + + /* append data (clears mark) */ + if (log_append(log, data, len)) + return -1; + + /* check to see if it's time to compress -- if not, then done */ + if (((log->last - log->first) >> 10) + (log->stored >> 10) < TRIGGER) + return 0; + + /* time to compress */ + return gzlog_compress(log); +} + +/* gzlog_close() return values: + 0: ok + -3: invalid log pointer argument */ +int gzlog_close(gzlog *logd) +{ + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + + /* close the log file and release the lock */ + log_close(log); + + /* free structure and return */ + if (log->path != NULL) + free(log->path); + strcpy(log->id, "bad"); + free(log); + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzlog.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzlog.h new file mode 100644 index 00000000..c4614267 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/gzlog.h @@ -0,0 +1,89 @@ +/* gzlog.h + Copyright (C) 2004, 2008 Mark Adler, all rights reserved + version 2.0, 25 Apr 2008 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* Version History: + 1.0 26 Nov 2004 First version + 2.0 25 Apr 2008 Complete redesign for recovery of interrupted operations + Interface changed slightly in that now path is a prefix + Compression now occurs as needed during gzlog_write() + gzlog_write() now always leaves the log file as valid gzip + */ + +/* + The gzlog object allows writing short messages to a gzipped log file, + opening the log file locked for small bursts, and then closing it. The log + object works by appending stored (uncompressed) data to the gzip file until + 1 MB has been accumulated. At that time, the stored data is compressed, and + replaces the uncompressed data in the file. The log file is truncated to + its new size at that time. After each write operation, the log file is a + valid gzip file that can decompressed to recover what was written. + + The gzlog operations can be interupted at any point due to an application or + system crash, and the log file will be recovered the next time the log is + opened with gzlog_open(). + */ + +#ifndef GZLOG_H +#define GZLOG_H + +/* gzlog object type */ +typedef void gzlog; + +/* Open a gzlog object, creating the log file if it does not exist. Return + NULL on error. Note that gzlog_open() could take a while to complete if it + has to wait to verify that a lock is stale (possibly for five minutes), or + if there is significant contention with other instantiations of this object + when locking the resource. path is the prefix of the file names created by + this object. If path is "foo", then the log file will be "foo.gz", and + other auxiliary files will be created and destroyed during the process: + "foo.dict" for a compression dictionary, "foo.temp" for a temporary (next) + dictionary, "foo.add" for data being added or compressed, "foo.lock" for the + lock file, and "foo.repairs" to log recovery operations performed due to + interrupted gzlog operations. A gzlog_open() followed by a gzlog_close() + will recover a previously interrupted operation, if any. */ +gzlog *gzlog_open(char *path); + +/* Write to a gzlog object. Return zero on success, -1 if there is a file i/o + error on any of the gzlog files (this should not happen if gzlog_open() + succeeded, unless the device has run out of space or leftover auxiliary + files have permissions or ownership that prevent their use), -2 if there is + a memory allocation failure, or -3 if the log argument is invalid (e.g. if + it was not created by gzlog_open()). This function will write data to the + file uncompressed, until 1 MB has been accumulated, at which time that data + will be compressed. The log file will be a valid gzip file upon successful + return. */ +int gzlog_write(gzlog *log, void *data, size_t len); + +/* Force compression of any uncompressed data in the log. This should be used + sparingly, if at all. The main application would be when a log file will + not be appended to again. If this is used to compress frequently while + appending, it will both significantly increase the execution time and + reduce the compression ratio. The return codes are the same as for + gzlog_write(). */ +int gzlog_compress(gzlog *log); + +/* Close a gzlog object. Return zero on success, -3 if the log argument is + invalid. The log object is freed, and so cannot be referenced again. */ +int gzlog_close(gzlog *log); + +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zlib_how.html b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zlib_how.html new file mode 100644 index 00000000..444ff1c9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zlib_how.html @@ -0,0 +1,545 @@ + + + + +zlib Usage Example + + + +

zlib Usage Example

+We often get questions about how the deflate() and inflate() functions should be used. +Users wonder when they should provide more input, when they should use more output, +what to do with a Z_BUF_ERROR, how to make sure the process terminates properly, and +so on. So for those who have read zlib.h (a few times), and +would like further edification, below is an annotated example in C of simple routines to compress and decompress +from an input file to an output file using deflate() and inflate() respectively. The +annotations are interspersed between lines of the code. So please read between the lines. +We hope this helps explain some of the intricacies of zlib. +

+Without further adieu, here is the program zpipe.c: +


+/* zpipe.c: example of proper use of zlib's inflate() and deflate()
+   Not copyrighted -- provided to the public domain
+   Version 1.4  11 December 2005  Mark Adler */
+
+/* Version history:
+   1.0  30 Oct 2004  First version
+   1.1   8 Nov 2004  Add void casting for unused return values
+                     Use switch statement for inflate() return values
+   1.2   9 Nov 2004  Add assertions to document zlib guarantees
+   1.3   6 Apr 2005  Remove incorrect assertion in inf()
+   1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
+                     Avoid some compiler warnings for input and output buffers
+ */
+
+We now include the header files for the required definitions. From +stdio.h we use fopen(), fread(), fwrite(), +feof(), ferror(), and fclose() for file i/o, and +fputs() for error messages. From string.h we use +strcmp() for command line argument processing. +From assert.h we use the assert() macro. +From zlib.h +we use the basic compression functions deflateInit(), +deflate(), and deflateEnd(), and the basic decompression +functions inflateInit(), inflate(), and +inflateEnd(). +

+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "zlib.h"
+
+This is an ugly hack required to avoid corruption of the input and output data on +Windows/MS-DOS systems. Without this, those systems would assume that the input and output +files are text, and try to convert the end-of-line characters from one standard to +another. That would corrupt binary data, and in particular would render the compressed data unusable. +This sets the input and output to binary which suppresses the end-of-line conversions. +SET_BINARY_MODE() will be used later on stdin and stdout, at the beginning of main(). +

+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+#  include <fcntl.h>
+#  include <io.h>
+#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+#  define SET_BINARY_MODE(file)
+#endif
+
+CHUNK is simply the buffer size for feeding data to and pulling data +from the zlib routines. Larger buffer sizes would be more efficient, +especially for inflate(). If the memory is available, buffers sizes +on the order of 128K or 256K bytes should be used. +

+#define CHUNK 16384
+
+The def() routine compresses data from an input file to an output file. The output data +will be in the zlib format, which is different from the gzip or zip +formats. The zlib format has a very small header of only two bytes to identify it as +a zlib stream and to provide decoding information, and a four-byte trailer with a fast +check value to verify the integrity of the uncompressed data after decoding. +

+/* Compress from file source to file dest until EOF on source.
+   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+   allocated for processing, Z_STREAM_ERROR if an invalid compression
+   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
+   version of the library linked do not match, or Z_ERRNO if there is
+   an error reading or writing the files. */
+int def(FILE *source, FILE *dest, int level)
+{
+
+Here are the local variables for def(). ret will be used for zlib +return codes. flush will keep track of the current flushing state for deflate(), +which is either no flushing, or flush to completion after the end of the input file is reached. +have is the amount of data returned from deflate(). The strm structure +is used to pass information to and from the zlib routines, and to maintain the +deflate() state. in and out are the input and output buffers for +deflate(). +

+    int ret, flush;
+    unsigned have;
+    z_stream strm;
+    unsigned char in[CHUNK];
+    unsigned char out[CHUNK];
+
+The first thing we do is to initialize the zlib state for compression using +deflateInit(). This must be done before the first use of deflate(). +The zalloc, zfree, and opaque fields in the strm +structure must be initialized before calling deflateInit(). Here they are +set to the zlib constant Z_NULL to request that zlib use +the default memory allocation routines. An application may also choose to provide +custom memory allocation routines here. deflateInit() will allocate on the +order of 256K bytes for the internal state. +(See zlib Technical Details.) +

+deflateInit() is called with a pointer to the structure to be initialized and +the compression level, which is an integer in the range of -1 to 9. Lower compression +levels result in faster execution, but less compression. Higher levels result in +greater compression, but slower execution. The zlib constant Z_DEFAULT_COMPRESSION, +equal to -1, +provides a good compromise between compression and speed and is equivalent to level 6. +Level 0 actually does no compression at all, and in fact expands the data slightly to produce +the zlib format (it is not a byte-for-byte copy of the input). +More advanced applications of zlib +may use deflateInit2() here instead. Such an application may want to reduce how +much memory will be used, at some price in compression. Or it may need to request a +gzip header and trailer instead of a zlib header and trailer, or raw +encoding with no header or trailer at all. +

+We must check the return value of deflateInit() against the zlib constant +Z_OK to make sure that it was able to +allocate memory for the internal state, and that the provided arguments were valid. +deflateInit() will also check that the version of zlib that the zlib.h +file came from matches the version of zlib actually linked with the program. This +is especially important for environments in which zlib is a shared library. +

+Note that an application can initialize multiple, independent zlib streams, which can +operate in parallel. The state information maintained in the structure allows the zlib +routines to be reentrant. +


+    /* allocate deflate state */
+    strm.zalloc = Z_NULL;
+    strm.zfree = Z_NULL;
+    strm.opaque = Z_NULL;
+    ret = deflateInit(&strm, level);
+    if (ret != Z_OK)
+        return ret;
+
+With the pleasantries out of the way, now we can get down to business. The outer do-loop +reads all of the input file and exits at the bottom of the loop once end-of-file is reached. +This loop contains the only call of deflate(). So we must make sure that all of the +input data has been processed and that all of the output data has been generated and consumed +before we fall out of the loop at the bottom. +

+    /* compress until end of file */
+    do {
+
+We start off by reading data from the input file. The number of bytes read is put directly +into avail_in, and a pointer to those bytes is put into next_in. We also +check to see if end-of-file on the input has been reached. If we are at the end of file, then flush is set to the +zlib constant Z_FINISH, which is later passed to deflate() to +indicate that this is the last chunk of input data to compress. We need to use feof() +to check for end-of-file as opposed to seeing if fewer than CHUNK bytes have been read. The +reason is that if the input file length is an exact multiple of CHUNK, we will miss +the fact that we got to the end-of-file, and not know to tell deflate() to finish +up the compressed stream. If we are not yet at the end of the input, then the zlib +constant Z_NO_FLUSH will be passed to deflate to indicate that we are still +in the middle of the uncompressed data. +

+If there is an error in reading from the input file, the process is aborted with +deflateEnd() being called to free the allocated zlib state before returning +the error. We wouldn't want a memory leak, now would we? deflateEnd() can be called +at any time after the state has been initialized. Once that's done, deflateInit() (or +deflateInit2()) would have to be called to start a new compression process. There is +no point here in checking the deflateEnd() return code. The deallocation can't fail. +


+        strm.avail_in = fread(in, 1, CHUNK, source);
+        if (ferror(source)) {
+            (void)deflateEnd(&strm);
+            return Z_ERRNO;
+        }
+        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
+        strm.next_in = in;
+
+The inner do-loop passes our chunk of input data to deflate(), and then +keeps calling deflate() until it is done producing output. Once there is no more +new output, deflate() is guaranteed to have consumed all of the input, i.e., +avail_in will be zero. +

+        /* run deflate() on input until output buffer not full, finish
+           compression if all of source has been read in */
+        do {
+
+Output space is provided to deflate() by setting avail_out to the number +of available output bytes and next_out to a pointer to that space. +

+            strm.avail_out = CHUNK;
+            strm.next_out = out;
+
+Now we call the compression engine itself, deflate(). It takes as many of the +avail_in bytes at next_in as it can process, and writes as many as +avail_out bytes to next_out. Those counters and pointers are then +updated past the input data consumed and the output data written. It is the amount of +output space available that may limit how much input is consumed. +Hence the inner loop to make sure that +all of the input is consumed by providing more output space each time. Since avail_in +and next_in are updated by deflate(), we don't have to mess with those +between deflate() calls until it's all used up. +

+The parameters to deflate() are a pointer to the strm structure containing +the input and output information and the internal compression engine state, and a parameter +indicating whether and how to flush data to the output. Normally deflate will consume +several K bytes of input data before producing any output (except for the header), in order +to accumulate statistics on the data for optimum compression. It will then put out a burst of +compressed data, and proceed to consume more input before the next burst. Eventually, +deflate() +must be told to terminate the stream, complete the compression with provided input data, and +write out the trailer check value. deflate() will continue to compress normally as long +as the flush parameter is Z_NO_FLUSH. Once the Z_FINISH parameter is provided, +deflate() will begin to complete the compressed output stream. However depending on how +much output space is provided, deflate() may have to be called several times until it +has provided the complete compressed stream, even after it has consumed all of the input. The flush +parameter must continue to be Z_FINISH for those subsequent calls. +

+There are other values of the flush parameter that are used in more advanced applications. You can +force deflate() to produce a burst of output that encodes all of the input data provided +so far, even if it wouldn't have otherwise, for example to control data latency on a link with +compressed data. You can also ask that deflate() do that as well as erase any history up to +that point so that what follows can be decompressed independently, for example for random access +applications. Both requests will degrade compression by an amount depending on how often such +requests are made. +

+deflate() has a return value that can indicate errors, yet we do not check it here. Why +not? Well, it turns out that deflate() can do no wrong here. Let's go through +deflate()'s return values and dispense with them one by one. The possible values are +Z_OK, Z_STREAM_END, Z_STREAM_ERROR, or Z_BUF_ERROR. Z_OK +is, well, ok. Z_STREAM_END is also ok and will be returned for the last call of +deflate(). This is already guaranteed by calling deflate() with Z_FINISH +until it has no more output. Z_STREAM_ERROR is only possible if the stream is not +initialized properly, but we did initialize it properly. There is no harm in checking for +Z_STREAM_ERROR here, for example to check for the possibility that some +other part of the application inadvertently clobbered the memory containing the zlib state. +Z_BUF_ERROR will be explained further below, but +suffice it to say that this is simply an indication that deflate() could not consume +more input or produce more output. deflate() can be called again with more output space +or more available input, which it will be in this code. +


+            ret = deflate(&strm, flush);    /* no bad return value */
+            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
+
+Now we compute how much output deflate() provided on the last call, which is the +difference between how much space was provided before the call, and how much output space +is still available after the call. Then that data, if any, is written to the output file. +We can then reuse the output buffer for the next call of deflate(). Again if there +is a file i/o error, we call deflateEnd() before returning to avoid a memory leak. +

+            have = CHUNK - strm.avail_out;
+            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+                (void)deflateEnd(&strm);
+                return Z_ERRNO;
+            }
+
+The inner do-loop is repeated until the last deflate() call fails to fill the +provided output buffer. Then we know that deflate() has done as much as it can with +the provided input, and that all of that input has been consumed. We can then fall out of this +loop and reuse the input buffer. +

+The way we tell that deflate() has no more output is by seeing that it did not fill +the output buffer, leaving avail_out greater than zero. However suppose that +deflate() has no more output, but just so happened to exactly fill the output buffer! +avail_out is zero, and we can't tell that deflate() has done all it can. +As far as we know, deflate() +has more output for us. So we call it again. But now deflate() produces no output +at all, and avail_out remains unchanged as CHUNK. That deflate() call +wasn't able to do anything, either consume input or produce output, and so it returns +Z_BUF_ERROR. (See, I told you I'd cover this later.) However this is not a problem at +all. Now we finally have the desired indication that deflate() is really done, +and so we drop out of the inner loop to provide more input to deflate(). +

+With flush set to Z_FINISH, this final set of deflate() calls will +complete the output stream. Once that is done, subsequent calls of deflate() would return +Z_STREAM_ERROR if the flush parameter is not Z_FINISH, and do no more processing +until the state is reinitialized. +

+Some applications of zlib have two loops that call deflate() +instead of the single inner loop we have here. The first loop would call +without flushing and feed all of the data to deflate(). The second loop would call +deflate() with no more +data and the Z_FINISH parameter to complete the process. As you can see from this +example, that can be avoided by simply keeping track of the current flush state. +


+        } while (strm.avail_out == 0);
+        assert(strm.avail_in == 0);     /* all input will be used */
+
+Now we check to see if we have already processed all of the input file. That information was +saved in the flush variable, so we see if that was set to Z_FINISH. If so, +then we're done and we fall out of the outer loop. We're guaranteed to get Z_STREAM_END +from the last deflate() call, since we ran it until the last chunk of input was +consumed and all of the output was generated. +

+        /* done when last data in file processed */
+    } while (flush != Z_FINISH);
+    assert(ret == Z_STREAM_END);        /* stream will be complete */
+
+The process is complete, but we still need to deallocate the state to avoid a memory leak +(or rather more like a memory hemorrhage if you didn't do this). Then +finally we can return with a happy return value. +

+    /* clean up and return */
+    (void)deflateEnd(&strm);
+    return Z_OK;
+}
+
+Now we do the same thing for decompression in the inf() routine. inf() +decompresses what is hopefully a valid zlib stream from the input file and writes the +uncompressed data to the output file. Much of the discussion above for def() +applies to inf() as well, so the discussion here will focus on the differences between +the two. +

+/* Decompress from file source to file dest until stream ends or EOF.
+   inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+   allocated for processing, Z_DATA_ERROR if the deflate data is
+   invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
+   the version of the library linked do not match, or Z_ERRNO if there
+   is an error reading or writing the files. */
+int inf(FILE *source, FILE *dest)
+{
+
+The local variables have the same functionality as they do for def(). The +only difference is that there is no flush variable, since inflate() +can tell from the zlib stream itself when the stream is complete. +

+    int ret;
+    unsigned have;
+    z_stream strm;
+    unsigned char in[CHUNK];
+    unsigned char out[CHUNK];
+
+The initialization of the state is the same, except that there is no compression level, +of course, and two more elements of the structure are initialized. avail_in +and next_in must be initialized before calling inflateInit(). This +is because the application has the option to provide the start of the zlib stream in +order for inflateInit() to have access to information about the compression +method to aid in memory allocation. In the current implementation of zlib +(up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of +inflate() anyway. However those fields must be initialized since later versions +of zlib that provide more compression methods may take advantage of this interface. +In any case, no decompression is performed by inflateInit(), so the +avail_out and next_out fields do not need to be initialized before calling. +

+Here avail_in is set to zero and next_in is set to Z_NULL to +indicate that no input data is being provided. +


+    /* allocate inflate state */
+    strm.zalloc = Z_NULL;
+    strm.zfree = Z_NULL;
+    strm.opaque = Z_NULL;
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit(&strm);
+    if (ret != Z_OK)
+        return ret;
+
+The outer do-loop decompresses input until inflate() indicates +that it has reached the end of the compressed data and has produced all of the uncompressed +output. This is in contrast to def() which processes all of the input file. +If end-of-file is reached before the compressed data self-terminates, then the compressed +data is incomplete and an error is returned. +

+    /* decompress until deflate stream ends or end of file */
+    do {
+
+We read input data and set the strm structure accordingly. If we've reached the +end of the input file, then we leave the outer loop and report an error, since the +compressed data is incomplete. Note that we may read more data than is eventually consumed +by inflate(), if the input file continues past the zlib stream. +For applications where zlib streams are embedded in other data, this routine would +need to be modified to return the unused data, or at least indicate how much of the input +data was not used, so the application would know where to pick up after the zlib stream. +

+        strm.avail_in = fread(in, 1, CHUNK, source);
+        if (ferror(source)) {
+            (void)inflateEnd(&strm);
+            return Z_ERRNO;
+        }
+        if (strm.avail_in == 0)
+            break;
+        strm.next_in = in;
+
+The inner do-loop has the same function it did in def(), which is to +keep calling inflate() until has generated all of the output it can with the +provided input. +

+        /* run inflate() on input until output buffer not full */
+        do {
+
+Just like in def(), the same output space is provided for each call of inflate(). +

+            strm.avail_out = CHUNK;
+            strm.next_out = out;
+
+Now we run the decompression engine itself. There is no need to adjust the flush parameter, since +the zlib format is self-terminating. The main difference here is that there are +return values that we need to pay attention to. Z_DATA_ERROR +indicates that inflate() detected an error in the zlib compressed data format, +which means that either the data is not a zlib stream to begin with, or that the data was +corrupted somewhere along the way since it was compressed. The other error to be processed is +Z_MEM_ERROR, which can occur since memory allocation is deferred until inflate() +needs it, unlike deflate(), whose memory is allocated at the start by deflateInit(). +

+Advanced applications may use +deflateSetDictionary() to prime deflate() with a set of likely data to improve the +first 32K or so of compression. This is noted in the zlib header, so inflate() +requests that that dictionary be provided before it can start to decompress. Without the dictionary, +correct decompression is not possible. For this routine, we have no idea what the dictionary is, +so the Z_NEED_DICT indication is converted to a Z_DATA_ERROR. +

+inflate() can also return Z_STREAM_ERROR, which should not be possible here, +but could be checked for as noted above for def(). Z_BUF_ERROR does not need to be +checked for here, for the same reasons noted for def(). Z_STREAM_END will be +checked for later. +


+            ret = inflate(&strm, Z_NO_FLUSH);
+            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
+            switch (ret) {
+            case Z_NEED_DICT:
+                ret = Z_DATA_ERROR;     /* and fall through */
+            case Z_DATA_ERROR:
+            case Z_MEM_ERROR:
+                (void)inflateEnd(&strm);
+                return ret;
+            }
+
+The output of inflate() is handled identically to that of deflate(). +

+            have = CHUNK - strm.avail_out;
+            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+                (void)inflateEnd(&strm);
+                return Z_ERRNO;
+            }
+
+The inner do-loop ends when inflate() has no more output as indicated +by not filling the output buffer, just as for deflate(). In this case, we cannot +assert that strm.avail_in will be zero, since the deflate stream may end before the file +does. +

+        } while (strm.avail_out == 0);
+
+The outer do-loop ends when inflate() reports that it has reached the +end of the input zlib stream, has completed the decompression and integrity +check, and has provided all of the output. This is indicated by the inflate() +return value Z_STREAM_END. The inner loop is guaranteed to leave ret +equal to Z_STREAM_END if the last chunk of the input file read contained the end +of the zlib stream. So if the return value is not Z_STREAM_END, the +loop continues to read more input. +

+        /* done when inflate() says it's done */
+    } while (ret != Z_STREAM_END);
+
+At this point, decompression successfully completed, or we broke out of the loop due to no +more data being available from the input file. If the last inflate() return value +is not Z_STREAM_END, then the zlib stream was incomplete and a data error +is returned. Otherwise, we return with a happy return value. Of course, inflateEnd() +is called first to avoid a memory leak. +

+    /* clean up and return */
+    (void)inflateEnd(&strm);
+    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+That ends the routines that directly use zlib. The following routines make this +a command-line program by running data through the above routines from stdin to +stdout, and handling any errors reported by def() or inf(). +

+zerr() is used to interpret the possible error codes from def() +and inf(), as detailed in their comments above, and print out an error message. +Note that these are only a subset of the possible return values from deflate() +and inflate(). +


+/* report a zlib or i/o error */
+void zerr(int ret)
+{
+    fputs("zpipe: ", stderr);
+    switch (ret) {
+    case Z_ERRNO:
+        if (ferror(stdin))
+            fputs("error reading stdin\n", stderr);
+        if (ferror(stdout))
+            fputs("error writing stdout\n", stderr);
+        break;
+    case Z_STREAM_ERROR:
+        fputs("invalid compression level\n", stderr);
+        break;
+    case Z_DATA_ERROR:
+        fputs("invalid or incomplete deflate data\n", stderr);
+        break;
+    case Z_MEM_ERROR:
+        fputs("out of memory\n", stderr);
+        break;
+    case Z_VERSION_ERROR:
+        fputs("zlib version mismatch!\n", stderr);
+    }
+}
+
+Here is the main() routine used to test def() and inf(). The +zpipe command is simply a compression pipe from stdin to stdout, if +no arguments are given, or it is a decompression pipe if zpipe -d is used. If any other +arguments are provided, no compression or decompression is performed. Instead a usage +message is displayed. Examples are zpipe < foo.txt > foo.txt.z to compress, and +zpipe -d < foo.txt.z > foo.txt to decompress. +

+/* compress or decompress from stdin to stdout */
+int main(int argc, char **argv)
+{
+    int ret;
+
+    /* avoid end-of-line conversions */
+    SET_BINARY_MODE(stdin);
+    SET_BINARY_MODE(stdout);
+
+    /* do compression if no arguments */
+    if (argc == 1) {
+        ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
+        if (ret != Z_OK)
+            zerr(ret);
+        return ret;
+    }
+
+    /* do decompression if -d specified */
+    else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
+        ret = inf(stdin, stdout);
+        if (ret != Z_OK)
+            zerr(ret);
+        return ret;
+    }
+
+    /* otherwise, report usage */
+    else {
+        fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
+        return 1;
+    }
+}
+
+
+Copyright (c) 2004, 2005 by Mark Adler
Last modified 11 December 2005
+ + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zpipe.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zpipe.c new file mode 100644 index 00000000..83535d16 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zpipe.c @@ -0,0 +1,205 @@ +/* zpipe.c: example of proper use of zlib's inflate() and deflate() + Not copyrighted -- provided to the public domain + Version 1.4 11 December 2005 Mark Adler */ + +/* Version history: + 1.0 30 Oct 2004 First version + 1.1 8 Nov 2004 Add void casting for unused return values + Use switch statement for inflate() return values + 1.2 9 Nov 2004 Add assertions to document zlib guarantees + 1.3 6 Apr 2005 Remove incorrect assertion in inf() + 1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions + Avoid some compiler warnings for input and output buffers + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#define CHUNK 16384 + +/* Compress from file source to file dest until EOF on source. + def() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_STREAM_ERROR if an invalid compression + level is supplied, Z_VERSION_ERROR if the version of zlib.h and the + version of the library linked do not match, or Z_ERRNO if there is + an error reading or writing the files. */ +int def(FILE *source, FILE *dest, int level) +{ + int ret, flush; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, level); + if (ret != Z_OK) + return ret; + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = deflate(&strm, flush); /* no bad return value */ + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input will be used */ + + /* done when last data in file processed */ + } while (flush != Z_FINISH); + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +int inf(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} + +/* compress or decompress from stdin to stdout */ +int main(int argc, char **argv) +{ + int ret; + + /* avoid end-of-line conversions */ + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + + /* do compression if no arguments */ + if (argc == 1) { + ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* do decompression if -d specified */ + else if (argc == 2 && strcmp(argv[1], "-d") == 0) { + ret = inf(stdin, stdout); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* otherwise, report usage */ + else { + fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); + return 1; + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zran.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zran.c new file mode 100644 index 00000000..617a1308 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/examples/zran.c @@ -0,0 +1,404 @@ +/* zran.c -- example of zlib/gzip stream indexing and random access + * Copyright (C) 2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.0 29 May 2005 Mark Adler */ + +/* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary() + for random access of a compressed file. A file containing a zlib or gzip + stream is provided on the command line. The compressed stream is decoded in + its entirety, and an index built with access points about every SPAN bytes + in the uncompressed output. The compressed file is left open, and can then + be read randomly, having to decompress on the average SPAN/2 uncompressed + bytes before getting to the desired block of data. + + An access point can be created at the start of any deflate block, by saving + the starting file offset and bit of that block, and the 32K bytes of + uncompressed data that precede that block. Also the uncompressed offset of + that block is saved to provide a referece for locating a desired starting + point in the uncompressed stream. build_index() works by decompressing the + input zlib or gzip stream a block at a time, and at the end of each block + deciding if enough uncompressed data has gone by to justify the creation of + a new access point. If so, that point is saved in a data structure that + grows as needed to accommodate the points. + + To use the index, an offset in the uncompressed data is provided, for which + the latest accees point at or preceding that offset is located in the index. + The input file is positioned to the specified location in the index, and if + necessary the first few bits of the compressed data is read from the file. + inflate is initialized with those bits and the 32K of uncompressed data, and + the decompression then proceeds until the desired offset in the file is + reached. Then the decompression continues to read the desired uncompressed + data from the file. + + Another approach would be to generate the index on demand. In that case, + requests for random access reads from the compressed data would try to use + the index, but if a read far enough past the end of the index is required, + then further index entries would be generated and added. + + There is some fair bit of overhead to starting inflation for the random + access, mainly copying the 32K byte dictionary. So if small pieces of the + file are being accessed, it would make sense to implement a cache to hold + some lookahead and avoid many calls to extract() for small lengths. + + Another way to build an index would be to use inflateCopy(). That would + not be constrained to have access points at block boundaries, but requires + more memory per access point, and also cannot be saved to file due to the + use of pointers in the state. The approach here allows for storage of the + index in a file. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +#define SPAN 1048576L /* desired distance between access points */ +#define WINSIZE 32768U /* sliding window size */ +#define CHUNK 16384 /* file input buffer size */ + +/* access point entry */ +struct point { + off_t out; /* corresponding offset in uncompressed data */ + off_t in; /* offset in input file of first full byte */ + int bits; /* number of bits (1-7) from byte at in - 1, or 0 */ + unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */ +}; + +/* access point list */ +struct access { + int have; /* number of list entries filled in */ + int size; /* number of list entries allocated */ + struct point *list; /* allocated list */ +}; + +/* Deallocate an index built by build_index() */ +local void free_index(struct access *index) +{ + if (index != NULL) { + free(index->list); + free(index); + } +} + +/* Add an entry to the access point list. If out of memory, deallocate the + existing list and return NULL. */ +local struct access *addpoint(struct access *index, int bits, + off_t in, off_t out, unsigned left, unsigned char *window) +{ + struct point *next; + + /* if list is empty, create it (start with eight points) */ + if (index == NULL) { + index = malloc(sizeof(struct access)); + if (index == NULL) return NULL; + index->list = malloc(sizeof(struct point) << 3); + if (index->list == NULL) { + free(index); + return NULL; + } + index->size = 8; + index->have = 0; + } + + /* if list is full, make it bigger */ + else if (index->have == index->size) { + index->size <<= 1; + next = realloc(index->list, sizeof(struct point) * index->size); + if (next == NULL) { + free_index(index); + return NULL; + } + index->list = next; + } + + /* fill in entry and increment how many we have */ + next = index->list + index->have; + next->bits = bits; + next->in = in; + next->out = out; + if (left) + memcpy(next->window, window + WINSIZE - left, left); + if (left < WINSIZE) + memcpy(next->window + left, window, WINSIZE - left); + index->have++; + + /* return list, possibly reallocated */ + return index; +} + +/* Make one entire pass through the compressed stream and build an index, with + access points about every span bytes of uncompressed output -- span is + chosen to balance the speed of random access against the memory requirements + of the list, about 32K bytes per access point. Note that data after the end + of the first zlib or gzip stream in the file is ignored. build_index() + returns the number of access points on success (>= 1), Z_MEM_ERROR for out + of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a + file read error. On success, *built points to the resulting index. */ +local int build_index(FILE *in, off_t span, struct access **built) +{ + int ret; + off_t totin, totout; /* our own total counters to avoid 4GB limit */ + off_t last; /* totout value of last access point */ + struct access *index; /* access points being generated */ + z_stream strm; + unsigned char input[CHUNK]; + unsigned char window[WINSIZE]; + + /* initialize inflate */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */ + if (ret != Z_OK) + return ret; + + /* inflate the input, maintain a sliding window, and build an index -- this + also validates the integrity of the compressed data using the check + information at the end of the gzip or zlib stream */ + totin = totout = last = 0; + index = NULL; /* will be allocated by first addpoint() */ + strm.avail_out = 0; + do { + /* get some compressed data from input file */ + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto build_index_error; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto build_index_error; + } + strm.next_in = input; + + /* process all of that, or until end of stream */ + do { + /* reset sliding window if necessary */ + if (strm.avail_out == 0) { + strm.avail_out = WINSIZE; + strm.next_out = window; + } + + /* inflate until out of input, output, or at end of block -- + update the total input and output counters */ + totin += strm.avail_in; + totout += strm.avail_out; + ret = inflate(&strm, Z_BLOCK); /* return at end of block */ + totin -= strm.avail_in; + totout -= strm.avail_out; + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto build_index_error; + if (ret == Z_STREAM_END) + break; + + /* if at end of block, consider adding an index entry (note that if + data_type indicates an end-of-block, then all of the + uncompressed data from that block has been delivered, and none + of the compressed data after that block has been consumed, + except for up to seven bits) -- the totout == 0 provides an + entry point after the zlib or gzip header, and assures that the + index always has at least one access point; we avoid creating an + access point after the last block by checking bit 6 of data_type + */ + if ((strm.data_type & 128) && !(strm.data_type & 64) && + (totout == 0 || totout - last > span)) { + index = addpoint(index, strm.data_type & 7, totin, + totout, strm.avail_out, window); + if (index == NULL) { + ret = Z_MEM_ERROR; + goto build_index_error; + } + last = totout; + } + } while (strm.avail_in != 0); + } while (ret != Z_STREAM_END); + + /* clean up and return index (release unused entries in list) */ + (void)inflateEnd(&strm); + index = realloc(index, sizeof(struct point) * index->have); + index->size = index->have; + *built = index; + return index->size; + + /* return error */ + build_index_error: + (void)inflateEnd(&strm); + if (index != NULL) + free_index(index); + return ret; +} + +/* Use the index to read len bytes from offset into buf, return bytes read or + negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past + the end of the uncompressed data, then extract() will return a value less + than len, indicating how much as actually read into buf. This function + should not return a data error unless the file was modified since the index + was generated. extract() may also return Z_ERRNO if there is an error on + reading or seeking the input file. */ +local int extract(FILE *in, struct access *index, off_t offset, + unsigned char *buf, int len) +{ + int ret, skip; + z_stream strm; + struct point *here; + unsigned char input[CHUNK]; + unsigned char discard[WINSIZE]; + + /* proceed only if something reasonable to do */ + if (len < 0) + return 0; + + /* find where in stream to start */ + here = index->list; + ret = index->have; + while (--ret && here[1].out <= offset) + here++; + + /* initialize file and inflate state to start there */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); /* raw inflate */ + if (ret != Z_OK) + return ret; + ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET); + if (ret == -1) + goto extract_ret; + if (here->bits) { + ret = getc(in); + if (ret == -1) { + ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR; + goto extract_ret; + } + (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits)); + } + (void)inflateSetDictionary(&strm, here->window, WINSIZE); + + /* skip uncompressed bytes until offset reached, then satisfy request */ + offset -= here->out; + strm.avail_in = 0; + skip = 1; /* while skipping to offset */ + do { + /* define where to put uncompressed data, and how much */ + if (offset == 0 && skip) { /* at offset now */ + strm.avail_out = len; + strm.next_out = buf; + skip = 0; /* only do this once */ + } + if (offset > WINSIZE) { /* skip WINSIZE bytes */ + strm.avail_out = WINSIZE; + strm.next_out = discard; + offset -= WINSIZE; + } + else if (offset != 0) { /* last skip */ + strm.avail_out = (unsigned)offset; + strm.next_out = discard; + offset = 0; + } + + /* uncompress until avail_out filled, or end of stream */ + do { + if (strm.avail_in == 0) { + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto extract_ret; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto extract_ret; + } + strm.next_in = input; + } + ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */ + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto extract_ret; + if (ret == Z_STREAM_END) + break; + } while (strm.avail_out != 0); + + /* if reach end of stream, then don't keep trying to get more */ + if (ret == Z_STREAM_END) + break; + + /* do until offset reached and requested data read, or stream ends */ + } while (skip); + + /* compute number of uncompressed bytes read after offset */ + ret = skip ? 0 : len - strm.avail_out; + + /* clean up and return bytes read or error */ + extract_ret: + (void)inflateEnd(&strm); + return ret; +} + +/* Demonstrate the use of build_index() and extract() by processing the file + provided on the command line, and the extracting 16K from about 2/3rds of + the way through the uncompressed output, and writing that to stdout. */ +int main(int argc, char **argv) +{ + int len; + off_t offset; + FILE *in; + struct access *index = NULL; + unsigned char buf[CHUNK]; + + /* open input file */ + if (argc != 2) { + fprintf(stderr, "usage: zran file.gz\n"); + return 1; + } + in = fopen(argv[1], "rb"); + if (in == NULL) { + fprintf(stderr, "zran: could not open %s for reading\n", argv[1]); + return 1; + } + + /* build index */ + len = build_index(in, SPAN, &index); + if (len < 0) { + fclose(in); + switch (len) { + case Z_MEM_ERROR: + fprintf(stderr, "zran: out of memory\n"); + break; + case Z_DATA_ERROR: + fprintf(stderr, "zran: compressed data error in %s\n", argv[1]); + break; + case Z_ERRNO: + fprintf(stderr, "zran: read error on %s\n", argv[1]); + break; + default: + fprintf(stderr, "zran: error %d while building index\n", len); + } + return 1; + } + fprintf(stderr, "zran: built index with %d access points\n", len); + + /* use index by reading some bytes from an arbitrary offset */ + offset = (index->list[index->have - 1].out << 1) / 3; + len = extract(in, index, offset, buf, CHUNK); + if (len < 0) + fprintf(stderr, "zran: extraction failed: %s error\n", + len == Z_MEM_ERROR ? "out of memory" : "input corrupted"); + else { + fwrite(buf, 1, len, stdout); + fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset); + } + + /* clean up and exit */ + free_index(index); + fclose(in); + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzclose.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzclose.c new file mode 100644 index 00000000..caeb99a3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzguts.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzguts.h new file mode 100644 index 00000000..0f8fb79f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzguts.h @@ -0,0 +1,132 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifdef _MSC_VER +# include +# define vsnprintf _vsnprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifdef STDC +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default i/o buffer size -- double this for output when reading */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + z_off64_t pos; /* current position in uncompressed data */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + unsigned char *next; /* next output data to deliver or write */ + /* just for reading */ + unsigned have; /* amount of output data unused at next */ + int eof; /* true if end of input file reached */ + z_off64_t start; /* where the gzip data started, for rewinding */ + z_off64_t raw; /* where the raw data started, for seeking */ + int how; /* 0: get header, 1: copy, 2: decompress */ + int direct; /* true if last read direct, false if gzip */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzlib.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzlib.c new file mode 100644 index 00000000..603e60ed --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzlib.c @@ -0,0 +1,537 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const char *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + if (state->mode == GZ_READ) { /* for reading ... */ + state->have = 0; /* no output data available */ + state->eof = 0; /* not at end of file */ + state->how = LOOK; /* look for gzip header */ + state->direct = 1; /* default for empty file */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const char *path; + int fd; + const char *mode; +{ + gz_statep state; + + /* allocate gzFile structure to return */ + state = malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* save the path name for error messages */ + state->path = malloc(strlen(path) + 1); + if (state->path == NULL) { + free(state); + return NULL; + } + strcpy(state->path, path); + + /* open the file with the appropriate mode (or just use fd) */ + state->fd = fd != -1 ? fd : + open(path, +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | ( + state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))), + 0666); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) + state->mode = GZ_WRITE; /* simplify later checks */ + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; + sprintf(path, "", fd); /* for debugging */ + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if (size == 0) + return -1; + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->pos + offset >= state->raw) { + ret = LSEEK(state->fd, offset - state->have, SEEK_CUR); + if (ret == -1) + return -1; + state->have = 0; + state->eof = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->pos += offset; + return state->pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->have) || (z_off64_t)state->have > offset ? + (unsigned)offset : state->have; + state->have -= n; + state->next += n; + state->pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? + (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->msg == NULL ? "" : state->msg; +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) + state->eof = 0; + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, save as static string */ + if (err == Z_MEM_ERROR) { + state->msg = (char *)msg; + return; + } + + /* construct error message with path */ + if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { + state->err = Z_MEM_ERROR; + state->msg = (char *)"out of memory"; + return; + } + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); + return; +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzread.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzread.c new file mode 100644 index 00000000..548201ab --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzread.c @@ -0,0 +1,653 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_next4 OF((gz_statep, unsigned long *)); +local int gz_head OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_make OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + + *have = 0; + do { + ret = read(state->fd, buf + *have, len - *have); + if (ret <= 0) + break; + *have += ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + gz_avail() assumes that strm->avail_in == 0. */ +local int gz_avail(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + if (state->err != Z_OK) + return -1; + if (state->eof == 0) { + if (gz_load(state, state->in, state->size, + (unsigned *)&(strm->avail_in)) == -1) + return -1; + strm->next_in = state->in; + } + return 0; +} + +/* Get next byte from input, or -1 if end or error. */ +#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \ + (strm->avail_in == 0 ? -1 : \ + (strm->avail_in--, *(strm->next_in)++))) + +/* Get a four-byte little-endian integer and return 0 on success and the value + in *ret. Otherwise -1 is returned and *ret is not modified. */ +local int gz_next4(state, ret) + gz_statep state; + unsigned long *ret; +{ + int ch; + unsigned long val; + z_streamp strm = &(state->strm); + + val = NEXT(); + val += (unsigned)NEXT() << 8; + val += (unsigned long)NEXT() << 16; + ch = NEXT(); + if (ch == -1) + return -1; + val += (unsigned long)ch << 24; + *ret = val; + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->have must be zero. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression, and the gzip header will be skipped so + that the next available input data is the raw deflate stream. If direct + copying, then leftover input data from the input buffer will be copied to + the output buffer. In that case, all further file reads will be directly to + either the output buffer or a user buffer. If decompressing, the inflate + state and the check value will be initialized. gz_head() will return 0 on + success or -1 on failure. Failures may include read errors or gzip header + errors. */ +local int gz_head(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + int flags; + unsigned len; + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = malloc(state->want); + state->out = malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get some data in the input buffer */ + if (strm->avail_in == 0) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for the gzip magic header bytes 31 and 139 */ + if (strm->next_in[0] == 31) { + strm->avail_in--; + strm->next_in++; + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in && strm->next_in[0] == 139) { + /* we have a gzip header, woo hoo! */ + strm->avail_in--; + strm->next_in++; + + /* skip rest of header */ + if (NEXT() != 8) { /* compression method */ + gz_error(state, Z_DATA_ERROR, "unknown compression method"); + return -1; + } + flags = NEXT(); + if (flags & 0xe0) { /* reserved flag bits */ + gz_error(state, Z_DATA_ERROR, "unknown header flags set"); + return -1; + } + NEXT(); /* modification time */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); /* extra flags */ + NEXT(); /* operating system */ + if (flags & 4) { /* extra field */ + len = (unsigned)NEXT(); + len += (unsigned)NEXT() << 8; + while (len--) + if (NEXT() < 0) + break; + } + if (flags & 8) /* file name */ + while (NEXT() > 0) + ; + if (flags & 16) /* comment */ + while (NEXT() > 0) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + /* an unexpected end of file is not checked for here -- it will be + noticed on the first request for uncompressed data */ + + /* set up for decompression */ + inflateReset(strm); + strm->adler = crc32(0L, Z_NULL, 0); + state->how = GZIP; + state->direct = 0; + return 0; + } + else { + /* not a gzip file -- save first byte (31) and fall to raw i/o */ + state->out[0] = 31; + state->have = 1; + } + } + + /* doing raw i/o, save start of raw data for seeking, copy any leftover + input to output -- this assumes that the output buffer is larger than + the input buffer, which also assures space for gzungetc() */ + state->raw = state->pos; + state->next = state->out; + if (strm->avail_in) { + memcpy(state->next + state->have, strm->next_in, strm->avail_in); + state->have += strm->avail_in; + strm->avail_in = 0; + } + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + If the end of the compressed data is reached, then verify the gzip trailer + check value and length (modulo 2^32). state->have and state->next are set + to point to the just decompressed data, and the crc is updated. If the + trailer is verified, state->how is reset to LOOK to look for the next gzip + stream or raw data, once state->have is depleted. Returns 0 on success, -1 + on failure. Failures may include invalid compressed data or a failed gzip + trailer verification. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret; + unsigned had; + unsigned long crc, len; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_DATA_ERROR, "unexpected end of file"); + return -1; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output and crc check value */ + state->have = had - strm->avail_out; + state->next = strm->next_out - state->have; + strm->adler = crc32(strm->adler, state->next, state->have); + + /* check gzip trailer if at end of deflate stream */ + if (ret == Z_STREAM_END) { + if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { + gz_error(state, Z_DATA_ERROR, "unexpected end of file"); + return -1; + } + if (crc != strm->adler) { + gz_error(state, Z_DATA_ERROR, "incorrect data check"); + return -1; + } + if (len != (strm->total_out & 0xffffffffL)) { + gz_error(state, Z_DATA_ERROR, "incorrect length check"); + return -1; + } + state->how = LOOK; /* ready for next stream, once have is 0 (leave + state->direct unchanged to remember how) */ + } + + /* good decompression */ + return 0; +} + +/* Make data and put in the output buffer. Assumes that state->have == 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for (and skipped if found) to determine wither to copy or decompress. + Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY + or GZIP unless the end of the input file has been reached and all data has + been processed. */ +local int gz_make(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + if (state->how == LOOK) { /* look for gzip header */ + if (gz_head(state) == -1) + return -1; + if (state->have) /* got some data from gz_head() */ + return 0; + } + if (state->how == COPY) { /* straight copy */ + if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1) + return -1; + state->next = state->out; + } + else if (state->how == GZIP) { /* decompress */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->have) { + n = GT_OFF(state->have) || (z_off64_t)state->have > len ? + (unsigned)len : state->have; + state->have -= n; + state->next += n; + state->pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_make(state) == -1) + return -1; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + unsigned got, n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + return -1; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* first just try copying data from the output buffer */ + if (state->have) { + n = state->have > len ? len : state->have; + memcpy(buf, state->next, n); + state->next += n; + state->have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && strm->avail_in == 0) + break; + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || len < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_make(state) == -1) + return -1; + continue; /* no progress yet -- go back to memcpy() above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, buf, len, &n) == -1) + return -1; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + strm->avail_out = len; + strm->next_out = buf; + if (gz_decomp(state) == -1) + return -1; + n = state->have; + state->have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->pos += n; + } while (len); + + /* return number of bytes read into user buffer (will fit in int) */ + return (int)got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->have) { + state->have--; + state->pos++; + return *(state->next)++; + } + + /* nothing there -- try gzread() */ + ret = gzread(file, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->have == 0) { + state->have = 1; + state->next = state->out + (state->size << 1) - 1; + state->next[0] = c; + state->pos--; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->have == (state->size << 1)) { + gz_error(state, Z_BUF_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->next == state->out) { + unsigned char *src = state->out + state->have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->next = dest; + } + state->have++; + state->next--; + state->next[0] = c; + state->pos--; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || state->err != Z_OK) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->have == 0) { + if (gz_make(state) == -1) + return NULL; /* error */ + if (state->have == 0) { /* end of file */ + if (buf == str) /* got bupkus */ + return NULL; + break; /* got something -- return it */ + } + } + + /* look for end-of-line in current output buffer */ + n = state->have > left ? left : state->have; + eol = memchr(state->next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->next, n); + state->have -= n; + state->next += n; + state->pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* found end-of-line or out of space -- terminate string and return it */ + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return 0; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->how == LOOK && state->have == 0) + (void)gz_head(state); + + /* return 1 if reading direct, 0 if decompressing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : Z_OK; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzwrite.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzwrite.c new file mode 100644 index 00000000..e8defc68 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/gzwrite.c @@ -0,0 +1,531 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on failure or 0 on success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input and output buffers */ + state->in = malloc(state->want); + state->out = malloc(state->want); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + 15 + 16, 8, state->strategy); + if (ret != Z_OK) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer */ + strm->avail_out = state->size; + strm->next_out = state->out; + state->next = strm->next_out; + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file, otherwise 0. + flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, + then the deflate() state is reset to start a new gzip stream. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, got; + unsigned have; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + have = (unsigned)(strm->next_out - state->next); + if (have && ((got = write(state->fd, state->next, have)) < 0 || + (unsigned)got != have)) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + } + state->next = strm->next_out; + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + deflateReset(strm); + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on error, 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + unsigned put = len; + unsigned n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); + return 0; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + if (strm->avail_in == 0) + strm->next_in = state->in; + n = state->size - strm->avail_in; + if (n > len) + n = len; + memcpy(strm->next_in + strm->avail_in, buf, n); + strm->avail_in += n; + state->pos += n; + buf = (char *)buf + n; + len -= n; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + strm->avail_in = len; + strm->next_in = (voidp)buf; + state->pos += len; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } + + /* input was all buffered or compressed (put will fit in int) */ + return (int)put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (strm->avail_in < state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + strm->next_in[strm->avail_in++] = c; + state->pos++; + return c; + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = c; + if (gzwrite(file, buf, 1) != 1) + return -1; + return c; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + unsigned len; + + /* write string */ + len = (unsigned)strlen(str); + ret = gzwrite(file, str, len); + return ret == 0 && len != 0 ? -1 : ret; +} + +#ifdef STDC +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) +{ + int size, len; + gz_statep state; + z_streamp strm; + va_list va; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(state->in, format, va); + va_end(va); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = vsprintf(state->in, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(state->in, size, format, va); + va_end(va); + len = strlen(state->in); +# else + len = vsnprintf((char *)(state->in), size, format, va); + va_end(va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->pos += len; + return len; +} + +#else /* !STDC */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(state->in); +# else + len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->pos += len; + return len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* compress remaining data with requested flush */ + gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = 0; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + ret += gz_zero(state, state->skip); + } + + /* flush, free memory, and close file */ + ret += gz_comp(state, Z_FINISH); + (void)deflateEnd(&(state->strm)); + free(state->out); + free(state->in); + gz_error(state, Z_OK, NULL); + free(state->path); + ret += close(state->fd); + free(state); + return ret ? Z_ERRNO : Z_OK; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/infback.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/infback.c new file mode 100644 index 00000000..af3a8c96 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/infback.c @@ -0,0 +1,632 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffast.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffast.c new file mode 100644 index 00000000..2f1d60b4 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffast.c @@ -0,0 +1,340 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2008, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + PUP(out) = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + PUP(out) = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + PUP(out) = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + PUP(out) = PUP(from); + } while (--len); + continue; + } +#endif + } + from = window - OFF; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffast.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffast.h new file mode 100644 index 00000000..e5c1aa4c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffixed.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffixed.h new file mode 100644 index 00000000..75ed4b59 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inflate.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inflate.c new file mode 100644 index 00000000..a8431abe --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inflate.c @@ -0,0 +1,1480 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->window = Z_NULL; + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + else if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->sane = !subvert; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + return Z_OK; +#else + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + state = (struct inflate_state FAR *)strm->state; + return ((long)(state->back) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inflate.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inflate.h new file mode 100644 index 00000000..95f4986d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inftrees.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inftrees.c new file mode 100644 index 00000000..11e9c52a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inftrees.c @@ -0,0 +1,330 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.5 Copyright 1995-2010 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + here.op = (unsigned char)(extra[work[sym]]); + here.val = base[work[sym]]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + here.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = here; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inftrees.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inftrees.h new file mode 100644 index 00000000..baa53a0b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/make_vms.com b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/make_vms.com new file mode 100644 index 00000000..6576490e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/make_vms.com @@ -0,0 +1,804 @@ +$! make libz under VMS written by +$! Martin P.J. Zinser +$! +$! In case of problems with the install you might contact me at +$! zinser@zinser.no-ip.info(preferred) or +$! zinser@sysdev.deutsche-boerse.com (work) +$! +$! Make procedure history for Zlib +$! +$!------------------------------------------------------------------------------ +$! Version history +$! 0.01 20060120 First version to receive a number +$! 0.02 20061008 Adapt to new Makefile.in +$! 0.03 20091224 Add support for large file check +$! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite +$! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in +$! +$ on error then goto err_exit +$ set proc/parse=ext +$! +$ true = 1 +$ false = 0 +$ tmpnam = "temp_" + f$getjpi("","pid") +$ tt = tmpnam + ".txt" +$ tc = tmpnam + ".c" +$ th = tmpnam + ".h" +$ define/nolog tconfig 'th' +$ its_decc = false +$ its_vaxc = false +$ its_gnuc = false +$ s_case = False +$! +$! Setup variables holding "config" information +$! +$ Make = "" +$ name = "Zlib" +$ version = "?.?.?" +$ v_string = "ZLIB_VERSION" +$ v_file = "zlib.h" +$ ccopt = "" +$ lopts = "" +$ dnsrl = "" +$ aconf_in_file = "zconf.h.in#zconf.h_in" +$ conf_check_string = "" +$ linkonly = false +$ optfile = name + ".opt" +$ libdefs = "" +$ axp = f$getsyi("HW_MODEL").ge.1024 .and. f$getsyi("HW_MODEL").lt.4096 +$! +$ whoami = f$parse(f$enviornment("Procedure"),,,,"NO_CONCEAL") +$ mydef = F$parse(whoami,,,"DEVICE") +$ mydir = f$parse(whoami,,,"DIRECTORY") - "][" +$ myproc = f$parse(whoami,,,"Name") + f$parse(whoami,,,"type") +$! +$! Check for MMK/MMS +$! +$ If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS" +$ If F$Type (MMK) .eqs. "STRING" Then Make = "MMK" +$! +$! +$ gosub find_version +$! +$ open/write topt tmp.opt +$ open/write optf 'optfile' +$! +$ gosub check_opts +$! +$! Look for the compiler used +$! +$ gosub check_compiler +$ close topt +$! +$ if its_decc +$ then +$ ccopt = "/prefix=all" + ccopt +$ if f$trnlnm("SYS") .eqs. "" +$ then +$ if axp +$ then +$ define sys sys$library: +$ else +$ ccopt = "/decc" + ccopt +$ define sys decc$library_include: +$ endif +$ endif +$ endif +$ if its_vaxc .or. its_gnuc +$ then +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ endif +$! +$! Build a fake configure input header +$! +$ open/write conf_hin config.hin +$ write conf_hin "#undef _LARGEFILE64_SOURCE" +$ close conf_hin +$! +$! +$ i = 0 +$FIND_ACONF: +$ fname = f$element(i,"#",aconf_in_file) +$ if fname .eqs. "#" then goto AMISS_ERR +$ if f$search(fname) .eqs. "" +$ then +$ i = i + 1 +$ goto find_aconf +$ endif +$ open/read/err=aconf_err aconf_in 'fname' +$ open/write aconf zconf.h +$ACONF_LOOP: +$ read/end_of_file=aconf_exit aconf_in line +$ work = f$edit(line, "compress,trim") +$ if f$extract(0,6,work) .nes. "#undef" +$ then +$ if f$extract(0,12,work) .nes. "#cmakedefine" +$ then +$ write aconf line +$ endif +$ else +$ cdef = f$element(1," ",work) +$ gosub check_config +$ endif +$ goto aconf_loop +$ACONF_EXIT: +$ write aconf "#define VMS 1" +$ write aconf "#include " +$ write aconf "#include " +$ write aconf "#ifdef _LARGEFILE" +$ write aconf "#define off64_t __off64_t" +$ write aconf "#define fopen64 fopen" +$ write aconf "#define fseeko64 fseeko" +$ write aconf "#define lseek64 lseek" +$ write aconf "#define ftello64 ftell" +$ write aconf "#endif" +$ close aconf_in +$ close aconf +$ if f$search("''th'") .nes. "" then delete 'th';* +$! Build the thing plain or with mms +$! +$ write sys$output "Compiling Zlib sources ..." +$ if make.eqs."" +$ then +$ dele example.obj;*,minigzip.obj;* +$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - + adler32.c zlib.h zconf.h +$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - + compress.c zlib.h zconf.h +$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - + crc32.c zlib.h zconf.h +$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - + deflate.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE gzclose.OBJ "CC ''CCOPT' gzclose" - + gzclose.c zutil.h zlib.h zconf.h +$ CALL MAKE gzlib.OBJ "CC ''CCOPT' gzlib" - + gzlib.c zutil.h zlib.h zconf.h +$ CALL MAKE gzread.OBJ "CC ''CCOPT' gzread" - + gzread.c zutil.h zlib.h zconf.h +$ CALL MAKE gzwrite.OBJ "CC ''CCOPT' gzwrite" - + gzwrite.c zutil.h zlib.h zconf.h +$ CALL MAKE infback.OBJ "CC ''CCOPT' infback" - + infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - + inffast.c zutil.h zlib.h zconf.h inffast.h +$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - + inflate.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - + inftrees.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - + trees.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - + uncompr.c zlib.h zconf.h +$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - + zutil.c zutil.h zlib.h zconf.h +$ write sys$output "Building Zlib ..." +$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ +$ write sys$output "Building example..." +$ CALL MAKE example.OBJ "CC ''CCOPT' example" - + example.c zlib.h zconf.h +$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb +$ if f$search("x11vms:xvmsutils.olb") .nes. "" +$ then +$ write sys$output "Building minigzip..." +$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" - + minigzip.c zlib.h zconf.h +$ call make minigzip.exe - + "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" - + minigzip.obj libz.olb +$ endif +$ else +$ gosub crea_mms +$ write sys$output "Make ''name' ''version' with ''Make' " +$ 'make' +$ endif +$! +$! Alpha gets a shareable image +$! +$ If axp +$ Then +$ gosub crea_olist +$ write sys$output "Creating libzshr.exe" +$ call anal_obj_axp modules.opt _link.opt +$ if s_case +$ then +$ open/append optf modules.opt +$ write optf "case_sensitive=YES" +$ close optf +$ endif +$ LINK_'lopts'/SHARE=libzshr.exe modules.opt/opt,_link.opt/opt +$ endif +$ write sys$output "Zlib build completed" +$ exit +$CC_ERR: +$ write sys$output "C compiler required to build ''name'" +$ goto err_exit +$ERR_EXIT: +$ set message/facil/ident/sever/text +$ close/nolog optf +$ close/nolog topt +$ close/nolog conf_hin +$ close/nolog aconf_in +$ close/nolog aconf +$ close/nolog out +$ close/nolog min +$ close/nolog mod +$ close/nolog h_in +$ write sys$output "Exiting..." +$ exit 2 +$! +$! +$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES +$ V = 'F$Verify(0) +$! P1 = What we are trying to make +$! P2 = Command to make it +$! P3 - P8 What it depends on +$ +$ If F$Search(P1) .Eqs. "" Then Goto Makeit +$ Time = F$CvTime(F$File(P1,"RDT")) +$arg=3 +$Loop: +$ Argument = P'arg +$ If Argument .Eqs. "" Then Goto Exit +$ El=0 +$Loop2: +$ File = F$Element(El," ",Argument) +$ If File .Eqs. " " Then Goto Endl +$ AFile = "" +$Loop3: +$ OFile = AFile +$ AFile = F$Search(File) +$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl +$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit +$ Goto Loop3 +$NextEL: +$ El = El + 1 +$ Goto Loop2 +$EndL: +$ arg=arg+1 +$ If arg .Le. 8 Then Goto Loop +$ Goto Exit +$ +$Makeit: +$ VV=F$VERIFY(0) +$ write sys$output P2 +$ 'P2 +$ VV='F$Verify(VV) +$Exit: +$ If V Then Set Verify +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ +$! +$! Check command line options and set symbols accordingly +$! +$!------------------------------------------------------------------------------ +$! Version history +$! 0.01 20041206 First version to receive a number +$! 0.02 20060126 Add new "HELP" target +$ CHECK_OPTS: +$ i = 1 +$ OPT_LOOP: +$ if i .lt. 9 +$ then +$ cparm = f$edit(p'i',"upcase") +$! +$! Check if parameter actually contains something +$! +$ if f$edit(cparm,"trim") .nes. "" +$ then +$ if cparm .eqs. "DEBUG" +$ then +$ ccopt = ccopt + "/noopt/deb" +$ lopts = lopts + "/deb" +$ endif +$ if f$locate("CCOPT=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ ccopt = ccopt + f$extract(start,len,cparm) +$ if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) - + then s_case = true +$ endif +$ if cparm .eqs. "LINK" then linkonly = true +$ if f$locate("LOPTS=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ lopts = lopts + f$extract(start,len,cparm) +$ endif +$ if f$locate("CC=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ cc_com = f$extract(start,len,cparm) + if (cc_com .nes. "DECC") .and. - + (cc_com .nes. "VAXC") .and. - + (cc_com .nes. "GNUC") +$ then +$ write sys$output "Unsupported compiler choice ''cc_com' ignored" +$ write sys$output "Use DECC, VAXC, or GNUC instead" +$ else +$ if cc_com .eqs. "DECC" then its_decc = true +$ if cc_com .eqs. "VAXC" then its_vaxc = true +$ if cc_com .eqs. "GNUC" then its_gnuc = true +$ endif +$ endif +$ if f$locate("MAKE=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ mmks = f$extract(start,len,cparm) +$ if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS") +$ then +$ make = mmks +$ else +$ write sys$output "Unsupported make choice ''mmks' ignored" +$ write sys$output "Use MMK or MMS instead" +$ endif +$ endif +$ if cparm .eqs. "HELP" then gosub bhelp +$ endif +$ i = i + 1 +$ goto opt_loop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Look for the compiler used +$! +$! Version history +$! 0.01 20040223 First version to receive a number +$! 0.02 20040229 Save/set value of decc$no_rooted_search_lists +$! 0.03 20060202 Extend handling of GNU C +$! 0.04 20090402 Compaq -> hp +$CHECK_COMPILER: +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then +$ its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "") +$ its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "") +$ its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "") +$ endif +$! +$! Exit if no compiler available +$! +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then goto CC_ERR +$ else +$ if its_decc +$ then +$ write sys$output "CC compiler check ... hp C" +$ if f$trnlnm("decc$no_rooted_search_lists") .nes. "" +$ then +$ dnrsl = f$trnlnm("decc$no_rooted_search_lists") +$ endif +$ define/nolog decc$no_rooted_search_lists 1 +$ else +$ if its_vaxc then write sys$output "CC compiler check ... VAX C" +$ if its_gnuc +$ then +$ write sys$output "CC compiler check ... GNU C" +$ if f$trnlnm(topt) then write topt "gnu_cc:[000000]gcclib.olb/lib" +$ if f$trnlnm(optf) then write optf "gnu_cc:[000000]gcclib.olb/lib" +$ cc = "gcc" +$ endif +$ if f$trnlnm(topt) then write topt "sys$share:vaxcrtl.exe/share" +$ if f$trnlnm(optf) then write optf "sys$share:vaxcrtl.exe/share" +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! If MMS/MMK are available dump out the descrip.mms if required +$! +$CREA_MMS: +$ write sys$output "Creating descrip.mms..." +$ create descrip.mms +$ open/append out descrip.mms +$ copy sys$input: out +$ deck +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser +# + +OBJS = adler32.obj, compress.obj, crc32.obj, gzclose.obj, gzlib.obj\ + gzread.obj, gzwrite.obj, uncompr.obj, infback.obj\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, \ + inftrees.obj, inffast.obj + +$ eod +$ write out "CFLAGS=", ccopt +$ write out "LOPTS=", lopts +$ copy sys$input: out +$ deck + +all : example.exe minigzip.exe libz.olb + @ write sys$output " Example applications available" + +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link $(LOPTS) example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link $(LOPTS) minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;*,*.opt;*,*.exe;* + + +# Other dependencies. +adler32.obj : adler32.c zutil.h zlib.h zconf.h +compress.obj : compress.c zlib.h zconf.h +crc32.obj : crc32.c zutil.h zlib.h zconf.h +deflate.obj : deflate.c deflate.h zutil.h zlib.h zconf.h +example.obj : example.c zlib.h zconf.h +gzclose.obj : gzclose.c zutil.h zlib.h zconf.h +gzlib.obj : gzlib.c zutil.h zlib.h zconf.h +gzread.obj : gzread.c zutil.h zlib.h zconf.h +gzwrite.obj : gzwrite.c zutil.h zlib.h zconf.h +inffast.obj : inffast.c zutil.h zlib.h zconf.h inftrees.h inffast.h +inflate.obj : inflate.c zutil.h zlib.h zconf.h +inftrees.obj : inftrees.c zutil.h zlib.h zconf.h inftrees.h +minigzip.obj : minigzip.c zlib.h zconf.h +trees.obj : trees.c deflate.h zutil.h zlib.h zconf.h +uncompr.obj : uncompr.c zlib.h zconf.h +zutil.obj : zutil.c zutil.h zlib.h zconf.h +infback.obj : infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ eod +$ close out +$ return +$!------------------------------------------------------------------------------ +$! +$! Read list of core library sources from makefile.in and create options +$! needed to build shareable image +$! +$CREA_OLIST: +$ open/read min makefile.in +$ open/write mod modules.opt +$ src_check = "OBJC =" +$MRLOOP: +$ read/end=mrdone min rec +$ if (f$extract(0,6,rec) .nes. src_check) then goto mrloop +$ rec = rec - src_check +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .eqs. "\") then goto mrdone +$MRSLOOP: +$ read/end=mrdone min rec +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .nes. "\") then goto mrsloop +$MRDONE: +$ close min +$ close mod +$ return +$!------------------------------------------------------------------------------ +$! +$! Take record extracted in crea_olist and split it into single filenames +$! +$EXTRA_FILNAM: +$ myrec = f$edit(rec - "\", "trim,compress") +$ i = 0 +$FELOOP: +$ srcfil = f$element(i," ", myrec) +$ if (srcfil .nes. " ") +$ then +$ write mod f$parse(srcfil,,,"NAME"), ".obj" +$ i = i + 1 +$ goto feloop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Find current Zlib version number +$! +$FIND_VERSION: +$ open/read h_in 'v_file' +$hloop: +$ read/end=hdone h_in rec +$ rec = f$edit(rec,"TRIM") +$ if (f$extract(0,1,rec) .nes. "#") then goto hloop +$ rec = f$edit(rec - "#", "TRIM") +$ if f$element(0," ",rec) .nes. "define" then goto hloop +$ if f$element(1," ",rec) .eqs. v_string +$ then +$ version = 'f$element(2," ",rec)' +$ goto hdone +$ endif +$ goto hloop +$hdone: +$ close h_in +$ return +$!------------------------------------------------------------------------------ +$! +$CHECK_CONFIG: +$! +$ in_ldef = f$locate(cdef,libdefs) +$ if (in_ldef .lt. f$length(libdefs)) +$ then +$ write aconf "#define ''cdef' 1" +$ libdefs = f$extract(0,in_ldef,libdefs) + - + f$extract(in_ldef + f$length(cdef) + 1, - + f$length(libdefs) - in_ldef - f$length(cdef) - 1, - + libdefs) +$ else +$ if (f$type('cdef') .eqs. "INTEGER") +$ then +$ write aconf "#define ''cdef' ", 'cdef' +$ else +$ if (f$type('cdef') .eqs. "STRING") +$ then +$ write aconf "#define ''cdef' ", """", '''cdef'', """" +$ else +$ gosub check_cc_def +$ endif +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Check if this is a define relating to the properties of the C/C++ +$! compiler +$! +$ CHECK_CC_DEF: +$ if (cdef .eqs. "_LARGEFILE64_SOURCE") +$ then +$ copy sys$input: 'tc' +$ deck +#include "tconfig" +#define _LARGEFILE +#include + +int main(){ +FILE *fp; + fp = fopen("temp.txt","r"); + fseeko(fp,1,SEEK_SET); + fclose(fp); +} + +$ eod +$ test_inv = false +$ comm_h = false +$ gosub cc_prop_check +$ return +$ endif +$ write aconf "/* ", line, " */" +$ return +$!------------------------------------------------------------------------------ +$! +$! Check for properties of C/C++ compiler +$! +$! Version history +$! 0.01 20031020 First version to receive a number +$! 0.02 20031022 Added logic for defines with value +$! 0.03 20040309 Make sure local config file gets not deleted +$! 0.04 20041230 Also write include for configure run +$! 0.05 20050103 Add processing of "comment defines" +$CC_PROP_CHECK: +$ cc_prop = true +$ is_need = false +$ is_need = (f$extract(0,4,cdef) .eqs. "NEED") .or. (test_inv .eq. true) +$ if f$search(th) .eqs. "" then create 'th' +$ set message/nofac/noident/nosever/notext +$ on error then continue +$ cc 'tmpnam' +$ if .not. ($status) then cc_prop = false +$ on error then continue +$! The headers might lie about the capabilities of the RTL +$ link 'tmpnam',tmp.opt/opt +$ if .not. ($status) then cc_prop = false +$ set message/fac/ident/sever/text +$ on error then goto err_exit +$ delete/nolog 'tmpnam'.*;*/exclude='th' +$ if (cc_prop .and. .not. is_need) .or. - + (.not. cc_prop .and. is_need) +$ then +$ write sys$output "Checking for ''cdef'... yes" +$ if f$type('cdef_val'_yes) .nes. "" +$ then +$ if f$type('cdef_val'_yes) .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_yes) +$ if f$type('cdef_val'_yes) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_yes) +$ else +$ call write_config f$fao("#define !AS 1",cdef) +$ endif +$ if (cdef .eqs. "HAVE_FSEEKO") .or. (cdef .eqs. "_LARGE_FILES") .or. - + (cdef .eqs. "_LARGEFILE64_SOURCE") then - + call write_config f$string("#define _LARGEFILE 1") +$ else +$ write sys$output "Checking for ''cdef'... no" +$ if (comm_h) +$ then + call write_config f$fao("/* !AS */",line) +$ else +$ if f$type('cdef_val'_no) .nes. "" +$ then +$ if f$type('cdef_val'_no) .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_no) +$ if f$type('cdef_val'_no) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_no) +$ else +$ call write_config f$fao("#undef !AS",cdef) +$ endif +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Check for properties of C/C++ compiler with multiple result values +$! +$! Version history +$! 0.01 20040127 First version +$! 0.02 20050103 Reconcile changes from cc_prop up to version 0.05 +$CC_MPROP_CHECK: +$ cc_prop = true +$ i = 1 +$ idel = 1 +$ MT_LOOP: +$ if f$type(result_'i') .eqs. "STRING" +$ then +$ set message/nofac/noident/nosever/notext +$ on error then continue +$ cc 'tmpnam'_'i' +$ if .not. ($status) then cc_prop = false +$ on error then continue +$! The headers might lie about the capabilities of the RTL +$ link 'tmpnam'_'i',tmp.opt/opt +$ if .not. ($status) then cc_prop = false +$ set message/fac/ident/sever/text +$ on error then goto err_exit +$ delete/nolog 'tmpnam'_'i'.*;* +$ if (cc_prop) +$ then +$ write sys$output "Checking for ''cdef'... ", mdef_'i' +$ if f$type(mdef_'i') .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,mdef_'i') +$ if f$type('cdef_val'_yes) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,mdef_'i') +$ goto msym_clean +$ else +$ i = i + 1 +$ goto mt_loop +$ endif +$ endif +$ write sys$output "Checking for ''cdef'... no" +$ call write_config f$fao("#undef !AS",cdef) +$ MSYM_CLEAN: +$ if (idel .le. msym_max) +$ then +$ delete/sym mdef_'idel' +$ idel = idel + 1 +$ goto msym_clean +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Analyze Object files for OpenVMS AXP to extract Procedure and Data +$! information to build a symbol vector for a shareable image +$! All the "brains" of this logic was suggested by Hartmut Becker +$! (Hartmut.Becker@compaq.com). All the bugs were introduced by me +$! (zinser@zinser.no-ip.info), so if you do have problem reports please do not +$! bother Hartmut/HP, but get in touch with me +$! +$! Version history +$! 0.01 20040406 Skip over shareable images in option file +$! 0.02 20041109 Fix option file for shareable images with case_sensitive=YES +$! 0.03 20050107 Skip over Identification labels in option file +$! 0.04 20060117 Add uppercase alias to code compiled with /name=as_is +$! +$ ANAL_OBJ_AXP: Subroutine +$ V = 'F$Verify(0) +$ SAY := "WRITE_ SYS$OUTPUT" +$ +$ IF F$SEARCH("''P1'") .EQS. "" +$ THEN +$ SAY "ANAL_OBJ_AXP-E-NOSUCHFILE: Error, inputfile ''p1' not available" +$ goto exit_aa +$ ENDIF +$ IF "''P2'" .EQS. "" +$ THEN +$ SAY "ANAL_OBJ_AXP: Error, no output file provided" +$ goto exit_aa +$ ENDIF +$ +$ open/read in 'p1 +$ create a.tmp +$ open/append atmp a.tmp +$ loop: +$ read/end=end_loop in line +$ if f$locate("/SHARE",f$edit(line,"upcase")) .lt. f$length(line) +$ then +$ write sys$output "ANAL_SKP_SHR-i-skipshare, ''line'" +$ goto loop +$ endif +$ if f$locate("IDENTIFICATION=",f$edit(line,"upcase")) .lt. f$length(line) +$ then +$ write sys$output "ANAL_OBJ_AXP-i-ident: Identification ", - + f$element(1,"=",line) +$ goto loop +$ endif +$ f= f$search(line) +$ if f .eqs. "" +$ then +$ write sys$output "ANAL_OBJ_AXP-w-nosuchfile, ''line'" +$ goto loop +$ endif +$ define/user sys$output nl: +$ define/user sys$error nl: +$ anal/obj/gsd 'f /out=x.tmp +$ open/read xtmp x.tmp +$ XLOOP: +$ read/end=end_xloop xtmp xline +$ xline = f$edit(xline,"compress") +$ write atmp xline +$ goto xloop +$ END_XLOOP: +$ close xtmp +$ goto loop +$ end_loop: +$ close in +$ close atmp +$ if f$search("a.tmp") .eqs. "" - + then $ exit +$ ! all global definitions +$ search a.tmp "symbol:","EGSY$V_DEF 1","EGSY$V_NORM 1"/out=b.tmp +$ ! all procedures +$ search b.tmp "EGSY$V_NORM 1"/wind=(0,1) /out=c.tmp +$ search c.tmp "symbol:"/out=d.tmp +$ define/user sys$output nl: +$ edito/edt/command=sys$input d.tmp +sub/symbol: "/symbol_vector=(/whole +sub/"/=PROCEDURE)/whole +exit +$ ! all data +$ search b.tmp "EGSY$V_DEF 1"/wind=(0,1) /out=e.tmp +$ search e.tmp "symbol:"/out=f.tmp +$ define/user sys$output nl: +$ edito/edt/command=sys$input f.tmp +sub/symbol: "/symbol_vector=(/whole +sub/"/=DATA)/whole +exit +$ sort/nodupl d.tmp,f.tmp g.tmp +$ open/read raw_vector g.tmp +$ open/write case_vector 'p2' +$ RAWLOOP: +$ read/end=end_rawloop raw_vector raw_element +$ write case_vector raw_element +$ if f$locate("=PROCEDURE)",raw_element) .lt. f$length(raw_element) +$ then +$ name = f$element(1,"=",raw_element) - "(" +$ if f$edit(name,"UPCASE") .nes. name then - + write case_vector f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)", - + f$edit(name,"UPCASE"), name) +$ endif +$ if f$locate("=DATA)",raw_element) .lt. f$length(raw_element) +$ then +$ name = f$element(1,"=",raw_element) - "(" +$ if f$edit(name,"UPCASE") .nes. name then - + write case_vector f$fao(" symbol_vector=(!AS/!AS=DATA)", - + f$edit(name,"UPCASE"), name) +$ endif +$ goto rawloop +$ END_RAWLOOP: +$ close raw_vector +$ close case_vector +$ delete a.tmp;*,b.tmp;*,c.tmp;*,d.tmp;*,e.tmp;*,f.tmp;*,g.tmp;* +$ if f$search("x.tmp") .nes. "" - + then $ delete x.tmp;* +$! +$ EXIT_AA: +$ if V then set verify +$ endsubroutine +$!------------------------------------------------------------------------------ +$! +$! Write configuration to both permanent and temporary config file +$! +$! Version history +$! 0.01 20031029 First version to receive a number +$! +$WRITE_CONFIG: SUBROUTINE +$ write aconf 'p1' +$ open/append confh 'th' +$ write confh 'p1' +$ close confh +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/minigzip.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/minigzip.c new file mode 100644 index 00000000..fe618836 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/minigzip.c @@ -0,0 +1,440 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id: minigzip.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# ifdef UNDER_CE +# include +# endif +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif +#endif + +#if defined(UNDER_CE) +# include +# define perror(s) pwinerror(s) + +/* Map the Windows error number in ERROR to a locale-dependent error + message string and return a pointer to it. Typically, the values + for ERROR come from GetLastError. + + The string pointed to shall not be modified by the application, + but may be overwritten by a subsequent call to strwinerror + + The strwinerror function does not change the current setting + of GetLastError. */ + +static char *strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +static void pwinerror (s) + const char *s; +{ + if (s && *s) + fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); + else + fprintf(stderr, "%s\n", strwinerror(GetLastError ())); +} + +#endif /* UNDER_CE */ + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + size_t len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -c : write to standard output + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int copyout = 0; + int uncompr = 0; + gzFile file; + char *bname, outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + bname = strrchr(argv[0], '/'); + if (bname) + bname++; + else + bname = argv[0]; + argc--, argv++; + + if (!strcmp(bname, "gunzip")) + uncompr = 1; + else if (!strcmp(bname, "zcat")) + copyout = uncompr = 1; + + while (argc > 0) { + if (strcmp(*argv, "-c") == 0) + copyout = 1; + else if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + if (copyout) { + SET_BINARY_MODE(stdout); + } + do { + if (uncompr) { + if (copyout) { + file = gzopen(*argv, "rb"); + if (file == NULL) + fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); + else + gz_uncompress(file, stdout); + } else { + file_uncompress(*argv); + } + } else { + if (copyout) { + FILE * in = fopen(*argv, "rb"); + + if (in == NULL) { + perror(*argv); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + + gz_compress(in, file); + } + + } else { + file_compress(*argv, outmode); + } + } + } while (argv++, --argc); + } + return 0; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.bor b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.bor new file mode 100644 index 00000000..0c1b99c9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.bor @@ -0,0 +1,115 @@ +# Makefile for zlib +# Borland C++ +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.bor" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C++, Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# memory model: one of s, m, c, l (small, medium, compact, large) +MODEL=l + +# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version +CC=bcc +LD=bcc +AR=tlib + +# compiler flags +# replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0 +CFLAGS=-O2 -Z -m$(MODEL) $(LOC) + +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.dj2 b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.dj2 new file mode 100644 index 00000000..29b03954 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.dj2 @@ -0,0 +1,104 @@ +# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.dj2; make test -fmakefile.dj2 +# +# To install libz.a, zconf.h and zlib.h in the djgpp directories, type: +# +# make install -fmakefile.dj2 +# +# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as +# in the sample below if the pattern of the DJGPP distribution is to +# be followed. Remember that, while 'es around <=> are ignored in +# makefiles, they are *not* in batch files or in djgpp.env. +# - - - - - +# [make] +# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include +# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib +# BUTT=-m486 +# - - - - - +# Alternately, these variables may be defined below, overriding the values +# in djgpp.env, as +# INCLUDE_PATH=c:\usr\include +# LIBRARY_PATH=c:\usr\lib + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lz +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=libz.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +check: test +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + +# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env . + +.PHONY : uninstall clean + +install: $(INCL) $(LIBS) + -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH) + -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH) + $(INSTALL) zlib.h $(INCLUDE_PATH) + $(INSTALL) zconf.h $(INCLUDE_PATH) + $(INSTALL) libz.a $(LIBRARY_PATH) + +uninstall: + $(RM) $(INCLUDE_PATH)\zlib.h + $(RM) $(INCLUDE_PATH)\zconf.h + $(RM) $(LIBRARY_PATH)\libz.a + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) libz.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.emx b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.emx new file mode 100644 index 00000000..9c1b57a5 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.msc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.msc new file mode 100644 index 00000000..cd2816fb --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.msc @@ -0,0 +1,112 @@ +# Makefile for zlib +# Microsoft C 5.1 or later +# Last updated: 19-Mar-2003 + +# To use, do "make makefile.msc" +# To compile in small model, set below: MODEL=S + +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------- Microsoft C 5.1 and later ------------- + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# Memory model: one of S, M, C, L (small, medium, compact, large) +MODEL=L + +CC=cl +CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC) +#-Ox generates bad code with MSC 5.1 +LIB_CFLAGS=-Zl $(CFLAGS) + +LD=link +LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode +# "/farcall/packcode" are only useful for `large code' memory models +# but should be a "no-op" for small code models. + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(LIB_CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + +minigzip.obj: minigzip.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + if exist $(ZLIB_LIB) del $(ZLIB_LIB) + lib $(ZLIB_LIB) $(OBJ1); + lib $(ZLIB_LIB) $(OBJ2); + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB); + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB); + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del *.map + -del zlib_*.bak + -del foo.gz diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.tc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.tc new file mode 100644 index 00000000..bcd0d188 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/msdos/Makefile.tc @@ -0,0 +1,100 @@ +# Makefile for zlib +# Turbo C 2.01, Turbo C++ 1.01 +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.tc" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to CFLAGS below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C 2.01, Turbo C++ 1.01 ------------ +MODEL=l +CC=tcc +LD=tcc +AR=tlib +# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +CFLAGS=-O2 -G -Z -m$(MODEL) +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/nintendods/Makefile b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/nintendods/Makefile new file mode 100644 index 00000000..21337d01 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/nintendods/Makefile @@ -0,0 +1,126 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(CURDIR)) +BUILD := build +SOURCES := ../../ +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -Wall -O2\ + -march=armv5te -mtune=arm946e-s \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/lib/libz.a + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + @[ -d $@ ] || mkdir -p include + @cp ../../*.h include + +lib: + @[ -d $@ ] || mkdir -p $@ + +$(BUILD): lib + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) lib + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/nintendods/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/nintendods/README new file mode 100644 index 00000000..ba7a37db --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/nintendods/README @@ -0,0 +1,5 @@ +This Makefile requires devkitARM (http://www.devkitpro.org/category/devkitarm/) and works inside "contrib/nds". It is based on a devkitARM template. + +Eduardo Costa +January 3, 2009 + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/Makefile.riscos b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/Makefile.riscos new file mode 100644 index 00000000..57e29d3f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/Makefile.riscos @@ -0,0 +1,151 @@ +# Project: zlib_1_03 +# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430 +# test works out-of-the-box, installs `somewhere' on demand + +# Toolflags: +CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah +C++flags = -c -depend !Depend -IC: -throwback +Linkflags = -aif -c++ -o $@ +ObjAsmflags = -throwback -NoCache -depend !Depend +CMHGflags = +LibFileflags = -c -l -o $@ +Squeezeflags = -o $@ + +# change the line below to where _you_ want the library installed. +libdest = lib:zlib + +# Final targets: +@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \ + @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \ + @.o.uncompr @.o.zutil + LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \ + @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \ + @.o.trees @.o.uncompr @.o.zutil +test: @.minigzip @.example @.lib + @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV + @echo running tests: hang on. + @/@.minigzip -f -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -f -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -1 libc + @/@.minigzip -d libc-gz + @diff @.lib @.libc + @echo that should have reported '@.lib and @.libc identical' if you have diff. + @/@.example @.fred @.fred + @echo that will have given lots of hello!'s. + +@.minigzip: @.o.minigzip @.lib C:o.Stubs + Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs +@.example: @.o.example @.lib C:o.Stubs + Link $(Linkflags) @.o.example @.lib C:o.Stubs + +install: @.lib + cdir $(libdest) + cdir $(libdest).h + @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV + @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV + @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV + @echo okay, installed zlib in $(libdest) + +clean:; remove @.minigzip + remove @.example + remove @.libc + -wipe @.o.* F~r~cV + remove @.fred + +# User-editable dependencies: +.c.o: + cc $(ccflags) -o $@ $< + +# Static dependencies: + +# Dynamic dependencies: +o.example: c.example +o.example: h.zlib +o.example: h.zconf +o.minigzip: c.minigzip +o.minigzip: h.zlib +o.minigzip: h.zconf +o.adler32: c.adler32 +o.adler32: h.zlib +o.adler32: h.zconf +o.compress: c.compress +o.compress: h.zlib +o.compress: h.zconf +o.crc32: c.crc32 +o.crc32: h.zlib +o.crc32: h.zconf +o.deflate: c.deflate +o.deflate: h.deflate +o.deflate: h.zutil +o.deflate: h.zlib +o.deflate: h.zconf +o.gzio: c.gzio +o.gzio: h.zutil +o.gzio: h.zlib +o.gzio: h.zconf +o.infblock: c.infblock +o.infblock: h.zutil +o.infblock: h.zlib +o.infblock: h.zconf +o.infblock: h.infblock +o.infblock: h.inftrees +o.infblock: h.infcodes +o.infblock: h.infutil +o.infcodes: c.infcodes +o.infcodes: h.zutil +o.infcodes: h.zlib +o.infcodes: h.zconf +o.infcodes: h.inftrees +o.infcodes: h.infblock +o.infcodes: h.infcodes +o.infcodes: h.infutil +o.infcodes: h.inffast +o.inffast: c.inffast +o.inffast: h.zutil +o.inffast: h.zlib +o.inffast: h.zconf +o.inffast: h.inftrees +o.inffast: h.infblock +o.inffast: h.infcodes +o.inffast: h.infutil +o.inffast: h.inffast +o.inflate: c.inflate +o.inflate: h.zutil +o.inflate: h.zlib +o.inflate: h.zconf +o.inflate: h.infblock +o.inftrees: c.inftrees +o.inftrees: h.zutil +o.inftrees: h.zlib +o.inftrees: h.zconf +o.inftrees: h.inftrees +o.inftrees: h.inffixed +o.infutil: c.infutil +o.infutil: h.zutil +o.infutil: h.zlib +o.infutil: h.zconf +o.infutil: h.infblock +o.infutil: h.inftrees +o.infutil: h.infcodes +o.infutil: h.infutil +o.trees: c.trees +o.trees: h.deflate +o.trees: h.zutil +o.trees: h.zlib +o.trees: h.zconf +o.trees: h.trees +o.uncompr: c.uncompr +o.uncompr: h.zlib +o.uncompr: h.zconf +o.zutil: c.zutil +o.zutil: h.zutil +o.zutil: h.zlib +o.zutil: h.zconf diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/README b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/README new file mode 100644 index 00000000..800bf079 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/README @@ -0,0 +1,3 @@ +This directory contains files that have not been updated for zlib 1.2.x + +(Volunteers are encouraged to help clean this up. Thanks.) diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/bndsrc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/bndsrc new file mode 100644 index 00000000..9cf94bb3 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/bndsrc @@ -0,0 +1,132 @@ +STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('ZLIB') + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.1.3 entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + +/********************************************************************/ +/* *MODULE ADLER32 ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("adler32") + +/********************************************************************/ +/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("compress") + EXPORT SYMBOL("compress2") + +/********************************************************************/ +/* *MODULE CRC32 ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("crc32") + EXPORT SYMBOL("get_crc_table") + +/********************************************************************/ +/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("deflate") + EXPORT SYMBOL("deflateEnd") + EXPORT SYMBOL("deflateSetDictionary") + EXPORT SYMBOL("deflateCopy") + EXPORT SYMBOL("deflateReset") + EXPORT SYMBOL("deflateParams") + EXPORT SYMBOL("deflatePrime") + EXPORT SYMBOL("deflateInit_") + EXPORT SYMBOL("deflateInit2_") + +/********************************************************************/ +/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("gzopen") + EXPORT SYMBOL("gzdopen") + EXPORT SYMBOL("gzsetparams") + EXPORT SYMBOL("gzread") + EXPORT SYMBOL("gzwrite") + EXPORT SYMBOL("gzprintf") + EXPORT SYMBOL("gzputs") + EXPORT SYMBOL("gzgets") + EXPORT SYMBOL("gzputc") + EXPORT SYMBOL("gzgetc") + EXPORT SYMBOL("gzflush") + EXPORT SYMBOL("gzseek") + EXPORT SYMBOL("gzrewind") + EXPORT SYMBOL("gztell") + EXPORT SYMBOL("gzeof") + EXPORT SYMBOL("gzclose") + EXPORT SYMBOL("gzerror") + +/********************************************************************/ +/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("inflate") + EXPORT SYMBOL("inflateEnd") + EXPORT SYMBOL("inflateSetDictionary") + EXPORT SYMBOL("inflateSync") + EXPORT SYMBOL("inflateReset") + EXPORT SYMBOL("inflateInit_") + EXPORT SYMBOL("inflateInit2_") + EXPORT SYMBOL("inflateSyncPoint") + +/********************************************************************/ +/* *MODULE UNCOMPR ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("uncompress") + +/********************************************************************/ +/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("zlibVersion") + EXPORT SYMBOL("zError") + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.2.1 additional entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + +/********************************************************************/ +/* *MODULE COMPRESS ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("compressBound") + +/********************************************************************/ +/* *MODULE DEFLATE ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("deflateBound") + +/********************************************************************/ +/* *MODULE GZIO ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("gzungetc") + EXPORT SYMBOL("gzclearerr") + +/********************************************************************/ +/* *MODULE INFBACK ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("inflateBack") + EXPORT SYMBOL("inflateBackEnd") + EXPORT SYMBOL("inflateBackInit_") + +/********************************************************************/ +/* *MODULE INFLATE ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("inflateCopy") + +/********************************************************************/ +/* *MODULE ZUTIL ZLIB 01/02/01 00:15:09 */ +/********************************************************************/ + + EXPORT SYMBOL("zlibCompileFlags") + +ENDPGMEXP diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/compile.clp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/compile.clp new file mode 100644 index 00000000..85549515 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/compile.clp @@ -0,0 +1,123 @@ +/******************************************************************************/ +/* */ +/* ZLIB */ +/* */ +/* Compile sources into modules and link them into a service program. */ +/* */ +/******************************************************************************/ + + PGM + +/* Configuration adjustable parameters. */ + + DCL VAR(&SRCLIB) TYPE(*CHAR) LEN(10) + + VALUE('ZLIB') /* Source library. */ + DCL VAR(&SRCFILE) TYPE(*CHAR) LEN(10) + + VALUE('SOURCES') /* Source member file. */ + DCL VAR(&CTLFILE) TYPE(*CHAR) LEN(10) + + VALUE('TOOLS') /* Control member file. */ + + DCL VAR(&MODLIB) TYPE(*CHAR) LEN(10) + + VALUE('ZLIB') /* Module library. */ + + DCL VAR(&SRVLIB) TYPE(*CHAR) LEN(10) + + VALUE('LGPL') /* Service program library. */ + + DCL VAR(&CFLAGS) TYPE(*CHAR) + + VALUE('OPTIMIZE(40)') /* Compile options. */ + + +/* Working storage. */ + + DCL VAR(&CMDLEN) TYPE(*DEC) LEN(15 5) VALUE(300) /* Command length. */ + DCL VAR(&CMD) TYPE(*CHAR) LEN(512) + + +/* Compile sources into modules. */ + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/ADLER32) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/COMPRESS) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/CRC32) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/DEFLATE) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/GZIO) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/INFBACK) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/INFFAST) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/INFLATE) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/INFTREES) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/TREES) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/UNCOMPR) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + CHGVAR VAR(&CMD) VALUE('CRTCMOD MODULE(' *TCAT &MODLIB *TCAT + + '/ZUTIL) SRCFILE(' *TCAT + + &SRCLIB *TCAT '/' *TCAT &SRCFILE *TCAT + + ') SYSIFCOPT(*IFSIO)' *BCAT &CFLAGS) + CALL PGM(QCMDEXC) PARM(&CMD &CMDLEN) + + +/* Link modules into a service program. */ + + CRTSRVPGM SRVPGM(&SRVLIB/ZLIB) + + MODULE(&MODLIB/ADLER32 &MODLIB/COMPRESS + + &MODLIB/CRC32 &MODLIB/DEFLATE + + &MODLIB/GZIO &MODLIB/INFBACK + + &MODLIB/INFFAST &MODLIB/INFLATE + + &MODLIB/INFTREES &MODLIB/TREES + + &MODLIB/UNCOMPR &MODLIB/ZUTIL) + + SRCFILE(&SRCLIB/&CTLFILE) SRCMBR(BNDSRC) + + TEXT('ZLIB 1.2.3') TGTRLS(V4R4M0) + + ENDPGM diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/readme.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/readme.txt new file mode 100644 index 00000000..beae13f5 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/readme.txt @@ -0,0 +1,111 @@ + ZLIB version 1.2.3 for AS400 installation instructions + +I) From an AS400 *SAVF file: + +1) Unpacking archive to an AS400 save file + +On the AS400: + +_ Create the ZLIB AS400 library: + + CRTLIB LIB(ZLIB) TYPE(PROD) TEXT('ZLIB compression API library') + +_ Create a work save file, for example: + + CRTSAVF FILE(ZLIB/ZLIBSAVF) + +On a PC connected to the target AS400: + +_ Unpack the save file image to a PC file "ZLIBSAVF" +_ Upload this file into the save file on the AS400, for example + using ftp in BINARY mode. + + +2) Populating the ZLIB AS400 source library + +On the AS400: + +_ Extract the saved objects into the ZLIB AS400 library using: + +RSTOBJ OBJ(*ALL) SAVLIB(ZLIB) DEV(*SAVF) SAVF(ZLIB/ZLIBSAVF) RSTLIB(ZLIB) + + +3) Customize installation: + +_ Edit CL member ZLIB/TOOLS(COMPILE) and change parameters if needed, + according to the comments. + +_ Compile this member with: + + CRTCLPGM PGM(ZLIB/COMPILE) SRCFILE(ZLIB/TOOLS) SRCMBR(COMPILE) + + +4) Compile and generate the service program: + +_ This can now be done by executing: + + CALL PGM(ZLIB/COMPILE) + + + +II) From the original source distribution: + +1) On the AS400, create the source library: + + CRTLIB LIB(ZLIB) TYPE(PROD) TEXT('ZLIB compression API library') + +2) Create the source files: + + CRTSRCPF FILE(ZLIB/SOURCES) RCDLEN(112) TEXT('ZLIB library modules') + CRTSRCPF FILE(ZLIB/H) RCDLEN(112) TEXT('ZLIB library includes') + CRTSRCPF FILE(ZLIB/TOOLS) RCDLEN(112) TEXT('ZLIB library control utilities') + +3) From the machine hosting the distribution files, upload them (with + FTP in text mode, for example) according to the following table: + + Original AS400 AS400 AS400 AS400 + file file member type description + SOURCES Original ZLIB C subprogram sources + adler32.c ADLER32 C ZLIB - Compute the Adler-32 checksum of a dta strm + compress.c COMPRESS C ZLIB - Compress a memory buffer + crc32.c CRC32 C ZLIB - Compute the CRC-32 of a data stream + deflate.c DEFLATE C ZLIB - Compress data using the deflation algorithm + gzio.c GZIO C ZLIB - IO on .gz files + infback.c INFBACK C ZLIB - Inflate using a callback interface + inffast.c INFFAST C ZLIB - Fast proc. literals & length/distance pairs + inflate.c INFLATE C ZLIB - Interface to inflate modules + inftrees.c INFTREES C ZLIB - Generate Huffman trees for efficient decode + trees.c TREES C ZLIB - Output deflated data using Huffman coding + uncompr.c UNCOMPR C ZLIB - Decompress a memory buffer + zutil.c ZUTIL C ZLIB - Target dependent utility functions + H Original ZLIB C and ILE/RPG include files + crc32.h CRC32 C ZLIB - CRC32 tables + deflate.h DEFLATE C ZLIB - Internal compression state + inffast.h INFFAST C ZLIB - Header to use inffast.c + inffixed.h INFFIXED C ZLIB - Table for decoding fixed codes + inflate.h INFLATE C ZLIB - Internal inflate state definitions + inftrees.h INFTREES C ZLIB - Header to use inftrees.c + trees.h TREES C ZLIB - Created automatically with -DGEN_TREES_H + zconf.h ZCONF C ZLIB - Compression library configuration + zlib.h ZLIB C ZLIB - Compression library C user interface + as400/zlib.inc ZLIB.INC RPGLE ZLIB - Compression library ILE RPG user interface + zutil.h ZUTIL C ZLIB - Internal interface and configuration + TOOLS Building source software & AS/400 README + as400/bndsrc BNDSRC Entry point exportation list + as400/compile.clp COMPILE CLP Compile sources & generate service program + as400/readme.txt README TXT Installation instructions + +4) Continue as in I)3). + + + + +Notes: For AS400 ILE RPG programmers, a /copy member defining the ZLIB + API prototypes for ILE RPG can be found in ZLIB/H(ZLIB.INC). + Please read comments in this member for more information. + + Remember that most foreign textual data are ASCII coded: this + implementation does not handle conversion from/to ASCII, so + text data code conversions must be done explicitely. + + Always open zipped files in binary mode. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/zlib.inc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/zlib.inc new file mode 100644 index 00000000..a9a4f5cf --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/as400/zlib.inc @@ -0,0 +1,331 @@ + * ZLIB.INC - Interface to the general purpose compression library + * + * ILE RPG400 version by Patrick Monnerat, DATASPHERE. + * Version 1.2.3.9 + * + * + * WARNING: + * Procedures inflateInit(), inflateInit2(), deflateInit(), + * deflateInit2() and inflateBackInit() need to be called with + * two additional arguments: + * the package version string and the stream control structure. + * size. This is needed because RPG lacks some macro feature. + * Call these procedures as: + * inflateInit(...: ZLIB_VERSION: %size(z_stream)) + * + /if not defined(ZLIB_H_) + /define ZLIB_H_ + * + ************************************************************************** + * Constants + ************************************************************************** + * + * Versioning information. + * + D ZLIB_VERSION C '1.2.3.9' + D ZLIB_VERNUM C X'1239' + * + * Other equates. + * + D Z_NO_FLUSH C 0 + D Z_SYNC_FLUSH C 2 + D Z_FULL_FLUSH C 3 + D Z_FINISH C 4 + D Z_BLOCK C 5 + * + D Z_OK C 0 + D Z_STREAM_END C 1 + D Z_NEED_DICT C 2 + D Z_ERRNO C -1 + D Z_STREAM_ERROR C -2 + D Z_DATA_ERROR C -3 + D Z_MEM_ERROR C -4 + D Z_BUF_ERROR C -5 + DZ_VERSION_ERROR C -6 + * + D Z_NO_COMPRESSION... + D C 0 + D Z_BEST_SPEED C 1 + D Z_BEST_COMPRESSION... + D C 9 + D Z_DEFAULT_COMPRESSION... + D C -1 + * + D Z_FILTERED C 1 + D Z_HUFFMAN_ONLY C 2 + D Z_RLE C 3 + D Z_DEFAULT_STRATEGY... + D C 0 + * + D Z_BINARY C 0 + D Z_ASCII C 1 + D Z_UNKNOWN C 2 + * + D Z_DEFLATED C 8 + * + D Z_NULL C 0 + * + ************************************************************************** + * Types + ************************************************************************** + * + D z_streamp S * Stream struct ptr + D gzFile S * File pointer + D z_off_t S 10i 0 Stream offsets + * + ************************************************************************** + * Structures + ************************************************************************** + * + * The GZIP encode/decode stream support structure. + * + D z_stream DS align based(z_streamp) + D zs_next_in * Next input byte + D zs_avail_in 10U 0 Byte cnt at next_in + D zs_total_in 10U 0 Total bytes read + D zs_next_out * Output buffer ptr + D zs_avail_out 10U 0 Room left @ next_out + D zs_total_out 10U 0 Total bytes written + D zs_msg * Last errmsg or null + D zs_state * Internal state + D zs_zalloc * procptr Int. state allocator + D zs_free * procptr Int. state dealloc. + D zs_opaque * Private alloc. data + D zs_data_type 10i 0 ASC/BIN best guess + D zs_adler 10u 0 Uncompr. adler32 val + D 10U 0 Reserved + D 10U 0 Ptr. alignment + * + ************************************************************************** + * Utility function prototypes + ************************************************************************** + * + D compress PR 10I 0 extproc('compress') + D dest 32767 options(*varsize) Destination buffer + D destLen 10U 0 Destination length + D source 32767 const options(*varsize) Source buffer + D sourceLen 10u 0 value Source length + * + D compress2 PR 10I 0 extproc('compress2') + D dest 32767 options(*varsize) Destination buffer + D destLen 10U 0 Destination length + D source 32767 const options(*varsize) Source buffer + D sourceLen 10U 0 value Source length + D level 10I 0 value Compression level + * + D compressBound PR 10U 0 extproc('compressBound') + D sourceLen 10U 0 value + * + D uncompress PR 10I 0 extproc('uncompress') + D dest 32767 options(*varsize) Destination buffer + D destLen 10U 0 Destination length + D source 32767 const options(*varsize) Source buffer + D sourceLen 10U 0 value Source length + * + D gzopen PR extproc('gzopen') + D like(gzFile) + D path * value options(*string) File pathname + D mode * value options(*string) Open mode + * + D gzdopen PR extproc('gzdopen') + D like(gzFile) + D fd 10i 0 value File descriptor + D mode * value options(*string) Open mode + * + D gzsetparams PR 10I 0 extproc('gzsetparams') + D file value like(gzFile) File pointer + D level 10I 0 value + D strategy 10i 0 value + * + D gzread PR 10I 0 extproc('gzread') + D file value like(gzFile) File pointer + D buf 32767 options(*varsize) Buffer + D len 10u 0 value Buffer length + * + D gzwrite PR 10I 0 extproc('gzwrite') + D file value like(gzFile) File pointer + D buf 32767 const options(*varsize) Buffer + D len 10u 0 value Buffer length + * + D gzputs PR 10I 0 extproc('gzputs') + D file value like(gzFile) File pointer + D s * value options(*string) String to output + * + D gzgets PR * extproc('gzgets') + D file value like(gzFile) File pointer + D buf 32767 options(*varsize) Read buffer + D len 10i 0 value Buffer length + * + D gzflush PR 10i 0 extproc('gzflush') + D file value like(gzFile) File pointer + D flush 10I 0 value Type of flush + * + D gzseek PR extproc('gzseek') + D like(z_off_t) + D file value like(gzFile) File pointer + D offset value like(z_off_t) Offset + D whence 10i 0 value Origin + * + D gzrewind PR 10i 0 extproc('gzrewind') + D file value like(gzFile) File pointer + * + D gztell PR extproc('gztell') + D like(z_off_t) + D file value like(gzFile) File pointer + * + D gzeof PR 10i 0 extproc('gzeof') + D file value like(gzFile) File pointer + * + D gzclose PR 10i 0 extproc('gzclose') + D file value like(gzFile) File pointer + * + D gzerror PR * extproc('gzerror') Error string + D file value like(gzFile) File pointer + D errnum 10I 0 Error code + * + D gzclearerr PR extproc('gzclearerr') + D file value like(gzFile) File pointer + * + ************************************************************************** + * Basic function prototypes + ************************************************************************** + * + D zlibVersion PR * extproc('zlibVersion') Version string + * + D deflateInit PR 10I 0 extproc('deflateInit_') Init. compression + D strm like(z_stream) Compression stream + D level 10I 0 value Compression level + D version * value options(*string) Version string + D stream_size 10i 0 value Stream struct. size + * + D deflate PR 10I 0 extproc('deflate') Compress data + D strm like(z_stream) Compression stream + D flush 10I 0 value Flush type required + * + D deflateEnd PR 10I 0 extproc('deflateEnd') Termin. compression + D strm like(z_stream) Compression stream + * + D inflateInit PR 10I 0 extproc('inflateInit_') Init. expansion + D strm like(z_stream) Expansion stream + D version * value options(*string) Version string + D stream_size 10i 0 value Stream struct. size + * + D inflate PR 10I 0 extproc('inflate') Expand data + D strm like(z_stream) Expansion stream + D flush 10I 0 value Flush type required + * + D inflateEnd PR 10I 0 extproc('inflateEnd') Termin. expansion + D strm like(z_stream) Expansion stream + * + ************************************************************************** + * Advanced function prototypes + ************************************************************************** + * + D deflateInit2 PR 10I 0 extproc('deflateInit2_') Init. compression + D strm like(z_stream) Compression stream + D level 10I 0 value Compression level + D method 10I 0 value Compression method + D windowBits 10I 0 value log2(window size) + D memLevel 10I 0 value Mem/cmpress tradeoff + D strategy 10I 0 value Compression stategy + D version * value options(*string) Version string + D stream_size 10i 0 value Stream struct. size + * + D deflateSetDictionary... + D PR 10I 0 extproc('deflateSetDictionary') Init. dictionary + D strm like(z_stream) Compression stream + D dictionary 32767 const options(*varsize) Dictionary bytes + D dictLength 10U 0 value Dictionary length + * + D deflateCopy PR 10I 0 extproc('deflateCopy') Compress strm 2 strm + D dest like(z_stream) Destination stream + D source like(z_stream) Source stream + * + D deflateReset PR 10I 0 extproc('deflateReset') End and init. stream + D strm like(z_stream) Compression stream + * + D deflateParams PR 10I 0 extproc('deflateParams') Change level & strat + D strm like(z_stream) Compression stream + D level 10I 0 value Compression level + D strategy 10I 0 value Compression stategy + * + D deflateBound PR 10U 0 extproc('deflateBound') Change level & strat + D strm like(z_stream) Compression stream + D sourcelen 10U 0 value Compression level + * + D deflatePrime PR 10I 0 extproc('deflatePrime') Change level & strat + D strm like(z_stream) Compression stream + D bits 10I 0 value Number of bits to insert + D value 10I 0 value Bits to insert + * + D inflateInit2 PR 10I 0 extproc('inflateInit2_') Init. expansion + D strm like(z_stream) Expansion stream + D windowBits 10I 0 value log2(window size) + D version * value options(*string) Version string + D stream_size 10i 0 value Stream struct. size + * + D inflateSetDictionary... + D PR 10I 0 extproc('inflateSetDictionary') Init. dictionary + D strm like(z_stream) Expansion stream + D dictionary 32767 const options(*varsize) Dictionary bytes + D dictLength 10U 0 value Dictionary length + * + D inflateSync PR 10I 0 extproc('inflateSync') Sync. expansion + D strm like(z_stream) Expansion stream + * + D inflateCopy PR 10I 0 extproc('inflateCopy') + D dest like(z_stream) Destination stream + D source like(z_stream) Source stream + * + D inflateReset PR 10I 0 extproc('inflateReset') End and init. stream + D strm like(z_stream) Expansion stream + * + D inflateBackInit... + D PR 10I 0 extproc('inflateBackInit_') + D strm like(z_stream) Expansion stream + D windowBits 10I 0 value Log2(buffer size) + D window 32767 options(*varsize) Buffer + D version * value options(*string) Version string + D stream_size 10i 0 value Stream struct. size + * + D inflateBack PR 10I 0 extproc('inflateBack') + D strm like(z_stream) Expansion stream + D in * value procptr Input function + D in_desc * value Input descriptor + D out * value procptr Output function + D out_desc * value Output descriptor + * + D inflateBackEnd PR 10I 0 extproc('inflateBackEnd') + D strm like(z_stream) Expansion stream + * + D zlibCompileFlags... + D PR 10U 0 extproc('zlibCompileFlags') + * + ************************************************************************** + * Checksum function prototypes + ************************************************************************** + * + D adler32 PR 10U 0 extproc('adler32') New checksum + D adler 10U 0 value Old checksum + D buf 32767 const options(*varsize) Bytes to accumulate + D len 10U 0 value Buffer length + * + D crc32 PR 10U 0 extproc('crc32') New checksum + D crc 10U 0 value Old checksum + D buf 32767 const options(*varsize) Bytes to accumulate + D len 10U 0 value Buffer length + * + ************************************************************************** + * Miscellaneous function prototypes + ************************************************************************** + * + D zError PR * extproc('zError') Error string + D err 10I 0 value Error code + * + D inflateSyncPoint... + D PR 10I 0 extproc('inflateSyncPoint') + D strm like(z_stream) Expansion stream + * + D get_crc_table PR * extproc('get_crc_table') Ptr to ulongs + * + /endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/descrip.mms b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/descrip.mms new file mode 100644 index 00000000..7066da5b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/descrip.mms @@ -0,0 +1,48 @@ +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser + +cc_defs = +c_deb = + +.ifdef __DECC__ +pref = /prefix=all +.endif + +OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\ + inftrees.obj, infcodes.obj, infutil.obj, inffast.obj + +CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF) + +all : example.exe minigzip.exe + @ write sys$output " Example applications available" +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;* + + +# Other dependencies. +adler32.obj : zutil.h zlib.h zconf.h +compress.obj : zlib.h zconf.h +crc32.obj : zutil.h zlib.h zconf.h +deflate.obj : deflate.h zutil.h zlib.h zconf.h +example.obj : zlib.h zconf.h +gzio.obj : zutil.h zlib.h zconf.h +infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h +inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h +inflate.obj : zutil.h zlib.h zconf.h infblock.h +inftrees.obj : zutil.h zlib.h zconf.h inftrees.h +infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h +minigzip.obj : zlib.h zconf.h +trees.obj : deflate.h zutil.h zlib.h zconf.h +uncompr.obj : zlib.h zconf.h +zutil.obj : zutil.h zlib.h zconf.h diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/os2/Makefile.os2 b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/os2/Makefile.os2 new file mode 100644 index 00000000..a105aaa5 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/os2/Makefile.os2 @@ -0,0 +1,136 @@ +# Makefile for zlib under OS/2 using GCC (PGCC) +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# cp Makefile.os2 .. +# cd .. +# make -f Makefile.os2 test + +# This makefile will build a static library z.lib, a shared library +# z.dll and a import library zdll.lib. You can use either z.lib or +# zdll.lib by specifying either -lz or -lzdll on gcc's command line + +CC=gcc -Zomf -s + +CFLAGS=-O6 -Wall +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +#################### BUG WARNING: ##################### +## infcodes.c hits a bug in pgcc-1.0, so you have to use either +## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem) +## This bug is reportedly fixed in pgcc >1.0, but this was not tested +CFLAGS+=-fno-force-mem + +LDFLAGS=-s -L. -lzdll -Zcrtdll +LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll + +VER=1.1.0 +ZLIB=z.lib +SHAREDLIB=z.dll +SHAREDLIBIMP=zdll.lib +LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP) + +AR=emxomfar cr +IMPLIB=emximp +RANLIB=echo +TAR=tar +SHELL=bash + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +TEST_OBJS = example.o minigzip.o + +DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \ + algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \ + nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \ + contrib/asm386/*.asm contrib/asm386/*.c \ + contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \ + contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \ + contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 + +all: example.exe minigzip.exe + +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +$(ZLIB): $(OBJS) + $(AR) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +$(SHAREDLIB): $(OBJS) os2/z.def + $(LDSHARED) -o $@ $^ + +$(SHAREDLIBIMP): os2/z.def + $(IMPLIB) -o $@ $^ + +example.exe: example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip.exe: minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +clean: + rm -f *.o *~ example minigzip libz.a libz.so* foo.gz + +distclean: clean + +zip: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + zip -ul9 zlib$$v $(DISTFILES) + mv Makefile~ Makefile + +dist: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + rm -f $$d.tar.gz; \ + if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \ + files=""; \ + for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \ + cd ..; \ + GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \ + if test ! -d $$d; then rm -f $$d; fi + mv Makefile~ Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/os2/zlib.def b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/os2/zlib.def new file mode 100644 index 00000000..438e8c0d --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/os2/zlib.def @@ -0,0 +1,51 @@ +; +; Slightly modified version of ../nt/zlib.dnt :-) +; + +LIBRARY Z +DESCRIPTION "Zlib compression library for OS/2" +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE + +EXPORTS + adler32 + compress + crc32 + deflate + deflateCopy + deflateEnd + deflateInit2_ + deflateInit_ + deflateParams + deflateReset + deflateSetDictionary + gzclose + gzdopen + gzerror + gzflush + gzopen + gzread + gzwrite + inflate + inflateEnd + inflateInit2_ + inflateInit_ + inflateReset + inflateSetDictionary + inflateSync + uncompress + zlibVersion + gzprintf + gzputc + gzgetc + gzseek + gzrewind + gztell + gzeof + gzsetparams + zError + inflateSyncPoint + get_crc_table + compress2 + gzputs + gzgets diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visual-basic.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visual-basic.txt new file mode 100644 index 00000000..57efe581 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visual-basic.txt @@ -0,0 +1,160 @@ +See below some functions declarations for Visual Basic. + +Frequently Asked Question: + +Q: Each time I use the compress function I get the -5 error (not enough + room in the output buffer). + +A: Make sure that the length of the compressed buffer is passed by + reference ("as any"), not by value ("as long"). Also check that + before the call of compress this length is equal to the total size of + the compressed buffer and not zero. + + +From: "Jon Caruana" +Subject: Re: How to port zlib declares to vb? +Date: Mon, 28 Oct 1996 18:33:03 -0600 + +Got the answer! (I haven't had time to check this but it's what I got, and +looks correct): + +He has the following routines working: + compress + uncompress + gzopen + gzwrite + gzread + gzclose + +Declares follow: (Quoted from Carlos Rios , in Vb4 form) + +#If Win16 Then 'Use Win16 calls. +Declare Function compress Lib "ZLIB.DLL" (ByVal compr As + String, comprLen As Any, ByVal buf As String, ByVal buflen + As Long) As Integer +Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr + As String, uncomprLen As Any, ByVal compr As String, ByVal + lcompr As Long) As Integer +Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As + String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As + Long) As Integer +#Else +Declare Function compress Lib "ZLIB32.DLL" + (ByVal compr As String, comprLen As Any, ByVal buf As + String, ByVal buflen As Long) As Integer +Declare Function uncompress Lib "ZLIB32.DLL" + (ByVal uncompr As String, uncomprLen As Any, ByVal compr As + String, ByVal lcompr As Long) As Long +Declare Function gzopen Lib "ZLIB32.DLL" + (ByVal file As String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzwrite Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzclose Lib "ZLIB32.DLL" + (ByVal file As Long) As Long +#End If + +-Jon Caruana +jon-net@usa.net +Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member + + +Here is another example from Michael that he +says conforms to the VB guidelines, and that solves the problem of not +knowing the uncompressed size by storing it at the end of the file: + +'Calling the functions: +'bracket meaning: [optional] {Range of possible values} +'Call subCompressFile( [, , [level of compression {1..9}]]) +'Call subUncompressFile() + +Option Explicit +Private lngpvtPcnSml As Long 'Stores value for 'lngPercentSmaller' +Private Const SUCCESS As Long = 0 +Private Const strFilExt As String = ".cpr" +Private Declare Function lngfncCpr Lib "zlib.dll" Alias "compress2" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long, +ByVal level As Integer) As Long +Private Declare Function lngfncUcp Lib "zlib.dll" Alias "uncompress" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long) +As Long + +Public Sub subCompressFile(ByVal strargOriFilPth As String, Optional ByVal +strargCprFilPth As String, Optional ByVal intLvl As Integer = 9) + Dim strCprPth As String + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim bytaryOri() As Byte + Dim bytaryCpr() As Byte + lngOriSiz = FileLen(strargOriFilPth) + ReDim bytaryOri(lngOriSiz - 1) + Open strargOriFilPth For Binary Access Read As #1 + Get #1, , bytaryOri() + Close #1 + strCprPth = IIf(strargCprFilPth = "", strargOriFilPth, strargCprFilPth) +'Select file path and name + strCprPth = strCprPth & IIf(Right(strCprPth, Len(strFilExt)) = +strFilExt, "", strFilExt) 'Add file extension if not exists + lngCprSiz = (lngOriSiz * 1.01) + 12 'Compression needs temporary a bit +more space then original file size + ReDim bytaryCpr(lngCprSiz - 1) + If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) = +SUCCESS Then + lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100 + ReDim Preserve bytaryCpr(lngCprSiz - 1) + Open strCprPth For Binary Access Write As #1 + Put #1, , bytaryCpr() + Put #1, , lngOriSiz 'Add the the original size value to the end +(last 4 bytes) + Close #1 + Else + MsgBox "Compression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub + +Public Sub subUncompressFile(ByVal strargFilPth As String) + Dim bytaryCpr() As Byte + Dim bytaryOri() As Byte + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim strOriPth As String + lngCprSiz = FileLen(strargFilPth) + ReDim bytaryCpr(lngCprSiz - 1) + Open strargFilPth For Binary Access Read As #1 + Get #1, , bytaryCpr() + Close #1 + 'Read the original file size value: + lngOriSiz = bytaryCpr(lngCprSiz - 1) * (2 ^ 24) _ + + bytaryCpr(lngCprSiz - 2) * (2 ^ 16) _ + + bytaryCpr(lngCprSiz - 3) * (2 ^ 8) _ + + bytaryCpr(lngCprSiz - 4) + ReDim Preserve bytaryCpr(lngCprSiz - 5) 'Cut of the original size value + ReDim bytaryOri(lngOriSiz - 1) + If lngfncUcp(bytaryOri(0), lngOriSiz, bytaryCpr(0), lngCprSiz) = SUCCESS +Then + strOriPth = Left(strargFilPth, Len(strargFilPth) - Len(strFilExt)) + Open strOriPth For Binary Access Write As #1 + Put #1, , bytaryOri() + Close #1 + Else + MsgBox "Uncompression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub +Public Property Get lngPercentSmaller() As Long + lngPercentSmaller = lngpvtPcnSml +End Property diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/README.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/README.txt new file mode 100644 index 00000000..3d0aef0a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/README.txt @@ -0,0 +1,73 @@ +Microsoft Developer Studio Project Files, Format Version 6.00 for zlib. + +Copyright (C) 2000-2004 Simon-Pierre Cadieux. +Copyright (C) 2004 Cosmin Truta. +For conditions of distribution and use, see copyright notice in zlib.h. + + +This project builds the zlib binaries as follows: + +* Win32_DLL_Release\zlib1.dll DLL build +* Win32_DLL_Debug\zlib1d.dll DLL build (debug version) +* Win32_DLL_ASM_Release\zlib1.dll DLL build using ASM code +* Win32_DLL_ASM_Debug\zlib1d.dll DLL build using ASM code (debug version) +* Win32_LIB_Release\zlib.lib static build +* Win32_LIB_Debug\zlibd.lib static build (debug version) +* Win32_LIB_ASM_Release\zlib.lib static build using ASM code +* Win32_LIB_ASM_Debug\zlibd.lib static build using ASM code (debug version) + + +For more information regarding the DLL builds, please see the DLL FAQ +in ..\..\win32\DLL_FAQ.txt. + + +To build and test: + +1) On the main menu, select "File | Open Workspace". + Open "zlib.dsw". + +2) Select "Build | Set Active Configuration". + Choose the configuration you wish to build. + +3) Select "Build | Clean". + +4) Select "Build | Build ... (F7)". Ignore warning messages about + not being able to find certain include files (e.g. alloc.h). + +5) If you built one of the sample programs (example or minigzip), + select "Build | Execute ... (Ctrl+F5)". + + +To use: + +1) Select "Project | Settings (Alt+F7)". + Make note of the configuration names used in your project. + Usually, these names are "Win32 Release" and "Win32 Debug". + +2) In the Workspace window, select the "FileView" tab. + Right-click on the root item "Workspace '...'". + Select "Insert Project into Workspace". + Switch on the checkbox "Dependency of:", and select the name + of your project. Open "zlib.dsp". + +3) Select "Build | Configurations". + For each configuration of your project: + 3.1) Choose the zlib configuration you wish to use. + 3.2) Click on "Add". + 3.3) Set the new zlib configuration name to the name used by + the configuration from the current iteration. + +4) Select "Build | Set Active Configuration". + Choose the configuration you wish to build. + +5) Select "Build | Build ... (F7)". + +6) If you built an executable program, select + "Build | Execute ... (Ctrl+F5)". + + +Note: + +To build the ASM-enabled code, you need Microsoft Assembler +(ML.EXE). You can get it by downloading and installing the +latest Processor Pack for Visual C++ 6.0. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/example.dsp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/example.dsp new file mode 100644 index 00000000..d3580525 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/example.dsp @@ -0,0 +1,278 @@ +# Microsoft Developer Studio Project File - Name="example" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=example - Win32 LIB Debug +!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 "example.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 "example.mak" CFG="example - Win32 LIB Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "example - Win32 DLL ASM Release" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 DLL ASM Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 DLL Release" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 DLL Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 LIB ASM Release" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 LIB ASM Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 LIB Release" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 LIB Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "example - Win32 DLL ASM Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "example___Win32_DLL_ASM_Release" +# PROP BASE Intermediate_Dir "example___Win32_DLL_ASM_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_DLL_ASM_Release" +# PROP Intermediate_Dir "Win32_DLL_ASM_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "example - Win32 DLL ASM Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "example___Win32_DLL_ASM_Debug" +# PROP BASE Intermediate_Dir "example___Win32_DLL_ASM_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_DLL_ASM_Debug" +# PROP Intermediate_Dir "Win32_DLL_ASM_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "example - Win32 DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "example___Win32_DLL_Release" +# PROP BASE Intermediate_Dir "example___Win32_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_DLL_Release" +# PROP Intermediate_Dir "Win32_DLL_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "example - Win32 DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "example___Win32_DLL_Debug" +# PROP BASE Intermediate_Dir "example___Win32_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_DLL_Debug" +# PROP Intermediate_Dir "Win32_DLL_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "example - Win32 LIB ASM Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "example___Win32_LIB_ASM_Release" +# PROP BASE Intermediate_Dir "example___Win32_LIB_ASM_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_LIB_ASM_Release" +# PROP Intermediate_Dir "Win32_LIB_ASM_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "example - Win32 LIB ASM Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "example___Win32_LIB_ASM_Debug" +# PROP BASE Intermediate_Dir "example___Win32_LIB_ASM_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_LIB_ASM_Debug" +# PROP Intermediate_Dir "Win32_LIB_ASM_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "example - Win32 LIB Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "example___Win32_LIB_Release" +# PROP BASE Intermediate_Dir "example___Win32_LIB_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_LIB_Release" +# PROP Intermediate_Dir "Win32_LIB_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "example - Win32 LIB Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "example___Win32_LIB_Debug" +# PROP BASE Intermediate_Dir "example___Win32_LIB_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_LIB_Debug" +# PROP Intermediate_Dir "Win32_LIB_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "example - Win32 DLL ASM Release" +# Name "example - Win32 DLL ASM Debug" +# Name "example - Win32 DLL Release" +# Name "example - Win32 DLL Debug" +# Name "example - Win32 LIB ASM Release" +# Name "example - Win32 LIB ASM Debug" +# Name "example - Win32 LIB Release" +# Name "example - Win32 LIB Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\example.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\zconf.h +# End Source File +# Begin Source File + +SOURCE=..\..\zlib.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/minigzip.dsp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/minigzip.dsp new file mode 100644 index 00000000..71034684 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/minigzip.dsp @@ -0,0 +1,278 @@ +# Microsoft Developer Studio Project File - Name="minigzip" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=minigzip - Win32 LIB Debug +!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 "minigzip.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 "minigzip.mak" CFG="minigzip - Win32 LIB Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "minigzip - Win32 DLL ASM Release" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 DLL ASM Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 DLL Release" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 DLL Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 LIB ASM Release" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 LIB ASM Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 LIB Release" (based on "Win32 (x86) Console Application") +!MESSAGE "minigzip - Win32 LIB Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "minigzip - Win32 DLL ASM Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "minigzip___Win32_DLL_ASM_Release" +# PROP BASE Intermediate_Dir "minigzip___Win32_DLL_ASM_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_DLL_ASM_Release" +# PROP Intermediate_Dir "Win32_DLL_ASM_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "minigzip - Win32 DLL ASM Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "minigzip___Win32_DLL_ASM_Debug" +# PROP BASE Intermediate_Dir "minigzip___Win32_DLL_ASM_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_DLL_ASM_Debug" +# PROP Intermediate_Dir "Win32_DLL_ASM_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "minigzip - Win32 DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "minigzip___Win32_DLL_Release" +# PROP BASE Intermediate_Dir "minigzip___Win32_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_DLL_Release" +# PROP Intermediate_Dir "Win32_DLL_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "minigzip - Win32 DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "minigzip___Win32_DLL_Debug" +# PROP BASE Intermediate_Dir "minigzip___Win32_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_DLL_Debug" +# PROP Intermediate_Dir "Win32_DLL_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "minigzip - Win32 LIB ASM Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "minigzip___Win32_LIB_ASM_Release" +# PROP BASE Intermediate_Dir "minigzip___Win32_LIB_ASM_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_LIB_ASM_Release" +# PROP Intermediate_Dir "Win32_LIB_ASM_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "minigzip - Win32 LIB ASM Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "minigzip___Win32_LIB_ASM_Debug" +# PROP BASE Intermediate_Dir "minigzip___Win32_LIB_ASM_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_LIB_ASM_Debug" +# PROP Intermediate_Dir "Win32_LIB_ASM_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "minigzip - Win32 LIB Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "minigzip___Win32_LIB_Release" +# PROP BASE Intermediate_Dir "minigzip___Win32_LIB_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_LIB_Release" +# PROP Intermediate_Dir "Win32_LIB_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "minigzip - Win32 LIB Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "minigzip___Win32_LIB_Debug" +# PROP BASE Intermediate_Dir "minigzip___Win32_LIB_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_LIB_Debug" +# PROP Intermediate_Dir "Win32_LIB_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "minigzip - Win32 DLL ASM Release" +# Name "minigzip - Win32 DLL ASM Debug" +# Name "minigzip - Win32 DLL Release" +# Name "minigzip - Win32 DLL Debug" +# Name "minigzip - Win32 LIB ASM Release" +# Name "minigzip - Win32 LIB ASM Debug" +# Name "minigzip - Win32 LIB Release" +# Name "minigzip - Win32 LIB Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\minigzip.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\zconf.h +# End Source File +# Begin Source File + +SOURCE=..\..\zlib.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/zlib.dsp b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/zlib.dsp new file mode 100644 index 00000000..00f54ea4 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/zlib.dsp @@ -0,0 +1,621 @@ +# Microsoft Developer Studio Project File - Name="zlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=zlib - Win32 LIB Debug +!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 "zlib.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 "zlib.mak" CFG="zlib - Win32 LIB Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "zlib - Win32 DLL ASM Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "zlib - Win32 DLL ASM Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "zlib - Win32 DLL Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "zlib - Win32 DLL Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "zlib - Win32 LIB ASM Release" (based on "Win32 (x86) Static Library") +!MESSAGE "zlib - Win32 LIB ASM Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "zlib - Win32 LIB Release" (based on "Win32 (x86) Static Library") +!MESSAGE "zlib - Win32 LIB Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "zlib - Win32 DLL ASM Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "zlib___Win32_DLL_ASM_Release" +# PROP BASE Intermediate_Dir "zlib___Win32_DLL_ASM_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_DLL_ASM_Release" +# PROP Intermediate_Dir "Win32_DLL_ASM_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /D "ASMV" /D "ASMINF" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /dll /machine:I386 /out:"Win32_DLL_ASM_Release\zlib1.dll" + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL ASM Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "zlib___Win32_DLL_ASM_Debug" +# PROP BASE Intermediate_Dir "zlib___Win32_DLL_ASM_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_DLL_ASM_Debug" +# PROP Intermediate_Dir "Win32_DLL_ASM_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /D "ASMV" /D "ASMINF" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /debug /machine:I386 /out:"Win32_DLL_ASM_Debug\zlib1d.dll" /pdbtype:sept + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "zlib___Win32_DLL_Release" +# PROP BASE Intermediate_Dir "zlib___Win32_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_DLL_Release" +# PROP Intermediate_Dir "Win32_DLL_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /dll /machine:I386 /out:"Win32_DLL_Release\zlib1.dll" + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "zlib___Win32_DLL_Debug" +# PROP BASE Intermediate_Dir "zlib___Win32_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_DLL_Debug" +# PROP Intermediate_Dir "Win32_DLL_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /debug /machine:I386 /out:"Win32_DLL_Debug\zlib1d.dll" /pdbtype:sept + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "zlib___Win32_LIB_ASM_Release" +# PROP BASE Intermediate_Dir "zlib___Win32_LIB_ASM_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_LIB_ASM_Release" +# PROP Intermediate_Dir "Win32_LIB_ASM_Release" +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /D "ASMV" /D "ASMINF" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "zlib___Win32_LIB_ASM_Debug" +# PROP BASE Intermediate_Dir "zlib___Win32_LIB_ASM_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_LIB_ASM_Debug" +# PROP Intermediate_Dir "Win32_LIB_ASM_Debug" +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /D "ASMV" /D "ASMINF" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Win32_LIB_ASM_Debug\zlibd.lib" + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "zlib___Win32_LIB_Release" +# PROP BASE Intermediate_Dir "zlib___Win32_LIB_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Win32_LIB_Release" +# PROP Intermediate_Dir "Win32_LIB_Release" +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "NDEBUG" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "zlib___Win32_LIB_Debug" +# PROP BASE Intermediate_Dir "zlib___Win32_LIB_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Win32_LIB_Debug" +# PROP Intermediate_Dir "Win32_LIB_Debug" +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "_DEBUG" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Win32_LIB_Debug\zlibd.lib" + +!ENDIF + +# Begin Target + +# Name "zlib - Win32 DLL ASM Release" +# Name "zlib - Win32 DLL ASM Debug" +# Name "zlib - Win32 DLL Release" +# Name "zlib - Win32 DLL Debug" +# Name "zlib - Win32 LIB ASM Release" +# Name "zlib - Win32 LIB ASM Debug" +# Name "zlib - Win32 LIB Release" +# Name "zlib - Win32 LIB Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\adler32.c +# End Source File +# Begin Source File + +SOURCE=..\..\compress.c +# End Source File +# Begin Source File + +SOURCE=..\..\crc32.c +# End Source File +# Begin Source File + +SOURCE=..\..\deflate.c +# End Source File +# Begin Source File + +SOURCE=..\..\gzclose.c +# End Source File +# Begin Source File + +SOURCE=..\..\gzlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\gzread.c +# End Source File +# Begin Source File + +SOURCE=..\..\gzwrite.c +# End Source File +# Begin Source File + +SOURCE=..\..\infback.c +# End Source File +# Begin Source File + +SOURCE=..\..\inffast.c +# End Source File +# Begin Source File + +SOURCE=..\..\inflate.c +# End Source File +# Begin Source File + +SOURCE=..\..\inftrees.c +# End Source File +# Begin Source File + +SOURCE=..\..\trees.c +# End Source File +# Begin Source File + +SOURCE=..\..\uncompr.c +# End Source File +# Begin Source File + +SOURCE=..\..\win32\zlib.def + +!IF "$(CFG)" == "zlib - Win32 DLL ASM Release" + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL ASM Debug" + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Release" + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Debug" + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\zutil.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\crc32.h +# End Source File +# Begin Source File + +SOURCE=..\..\deflate.h +# End Source File +# Begin Source File + +SOURCE=..\..\inffast.h +# End Source File +# Begin Source File + +SOURCE=..\..\inffixed.h +# End Source File +# Begin Source File + +SOURCE=..\..\inflate.h +# End Source File +# Begin Source File + +SOURCE=..\..\inftrees.h +# End Source File +# Begin Source File + +SOURCE=..\..\trees.h +# End Source File +# Begin Source File + +SOURCE=..\..\zconf.h +# End Source File +# Begin Source File + +SOURCE=..\..\zlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\zutil.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\win32\zlib1.rc +# End Source File +# End Group +# Begin Group "Assembler Files (Unsupported)" + +# PROP Default_Filter "asm;obj;c;cpp;cxx;h;hpp;hxx" +# Begin Source File + +SOURCE=..\..\contrib\masmx86\gvmat32.asm + +!IF "$(CFG)" == "zlib - Win32 DLL ASM Release" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_DLL_ASM_Release +InputPath=..\..\contrib\masmx86\gvmat32.asm +InputName=gvmat32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL ASM Debug" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_DLL_ASM_Debug +InputPath=..\..\contrib\masmx86\gvmat32.asm +InputName=gvmat32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Release" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_LIB_ASM_Release +InputPath=..\..\contrib\masmx86\gvmat32.asm +InputName=gvmat32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Debug" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_LIB_ASM_Debug +InputPath=..\..\contrib\masmx86\gvmat32.asm +InputName=gvmat32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\contrib\masmx86\gvmat32c.c + +!IF "$(CFG)" == "zlib - Win32 DLL ASM Release" + +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL ASM Debug" + +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Release" + +# PROP Exclude_From_Build 1 +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Debug" + +# PROP Exclude_From_Build 1 +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Release" + +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Debug" + +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Release" + +# PROP Exclude_From_Build 1 +# ADD CPP /I "..\.." + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Debug" + +# PROP Exclude_From_Build 1 +# ADD CPP /I "..\.." + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\contrib\masmx86\inffas32.asm + +!IF "$(CFG)" == "zlib - Win32 DLL ASM Release" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_DLL_ASM_Release +InputPath=..\..\contrib\masmx86\inffas32.asm +InputName=inffas32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL ASM Debug" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_DLL_ASM_Debug +InputPath=..\..\contrib\masmx86\inffas32.asm +InputName=inffas32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 DLL Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Release" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_LIB_ASM_Release +InputPath=..\..\contrib\masmx86\inffas32.asm +InputName=inffas32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB ASM Debug" + +# Begin Custom Build - Assembling... +IntDir=.\Win32_LIB_ASM_Debug +InputPath=..\..\contrib\masmx86\inffas32.asm +InputName=inffas32 + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe /nologo /c /coff /Cx /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)" + +# End Custom Build + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "zlib - Win32 LIB Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=.\README.txt +# End Source File +# End Target +# End Project diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/zlib.dsw b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/zlib.dsw new file mode 100644 index 00000000..3a771fce --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/old/visualc6/zlib.dsw @@ -0,0 +1,59 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "example"=.\example.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name zlib + End Project Dependency +}}} + +############################################################################### + +Project: "minigzip"=.\minigzip.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name zlib + End Project Dependency +}}} + +############################################################################### + +Project: "zlib"=.\zlib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/qnx/package.qpg b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/qnx/package.qpg new file mode 100644 index 00000000..2bc63b21 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/qnx/package.qpg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Library + + Medium + + 2.0 + + + + zlib + zlib + alain.bonnefoy@icbt.com + Public + public + www.gzip.org/zlib + + + Jean-Loup Gailly,Mark Adler + www.gzip.org/zlib + + zlib@gzip.org + + + A massively spiffy yet delicately unobtrusive compression library. + zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system. + http://www.gzip.org/zlib + + + + + 1.2.5 + Medium + Stable + + + + + + + No License + + + + Software Development/Libraries and Extensions/C Libraries + zlib,compression + qnx6 + qnx6 + None + Developer + + + + + + + + + + + + + + Install + Post + No + Ignore + + No + Optional + + + + + + + + + + + + + InstallOver + zlib + + + + + + + + + + + + + InstallOver + zlib-dev + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/treebuild.xml b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/treebuild.xml new file mode 100644 index 00000000..6b8f5428 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/treebuild.xml @@ -0,0 +1,116 @@ + + + + zip compression library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/trees.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/trees.c new file mode 100644 index 00000000..098ef669 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/trees.c @@ -0,0 +1,1244 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2010 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/trees.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/trees.h new file mode 100644 index 00000000..d35639d8 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 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, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 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, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 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, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/uncompr.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/uncompr.c new file mode 100644 index 00000000..ed694113 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/uncompr.c @@ -0,0 +1,59 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/watcom/watcom_f.mak b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/watcom/watcom_f.mak new file mode 100644 index 00000000..37f4d74c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/watcom/watcom_f.mak @@ -0,0 +1,43 @@ +# Makefile for zlib +# OpenWatcom flat model +# Last updated: 28-Dec-2005 + +# To use, do "wmake -f watcom_f.mak" + +C_SOURCE = adler32.c compress.c crc32.c deflate.c & + gzclose.c gzlib.c gzread.c gzwrite.c & + infback.c inffast.c inflate.c inftrees.c & + trees.c uncompr.c zutil.c + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj & + gzclose.obj gzlib.obj gzread.obj gzwrite.obj & + infback.obj inffast.obj inflate.obj inftrees.obj & + trees.obj uncompr.obj zutil.obj + +CC = wcc386 +LINKER = wcl386 +CFLAGS = -zq -mf -3r -fp3 -s -bt=dos -oilrtfm -fr=nul -wx +ZLIB_LIB = zlib_f.lib + +.C.OBJ: + $(CC) $(CFLAGS) $[@ + +all: $(ZLIB_LIB) example.exe minigzip.exe + +$(ZLIB_LIB): $(OBJS) + wlib -b -c $(ZLIB_LIB) -+adler32.obj -+compress.obj -+crc32.obj + wlib -b -c $(ZLIB_LIB) -+gzclose.obj -+gzlib.obj -+gzread.obj -+gzwrite.obj + wlib -b -c $(ZLIB_LIB) -+deflate.obj -+infback.obj + wlib -b -c $(ZLIB_LIB) -+inffast.obj -+inflate.obj -+inftrees.obj + wlib -b -c $(ZLIB_LIB) -+trees.obj -+uncompr.obj -+zutil.obj + +example.exe: $(ZLIB_LIB) example.obj + $(LINKER) -ldos32a -fe=example.exe example.obj $(ZLIB_LIB) + +minigzip.exe: $(ZLIB_LIB) minigzip.obj + $(LINKER) -ldos32a -fe=minigzip.exe minigzip.obj $(ZLIB_LIB) + +clean: .SYMBOLIC + del *.obj + del $(ZLIB_LIB) + @echo Cleaning done diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/watcom/watcom_l.mak b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/watcom/watcom_l.mak new file mode 100644 index 00000000..193eed7b --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/watcom/watcom_l.mak @@ -0,0 +1,43 @@ +# Makefile for zlib +# OpenWatcom large model +# Last updated: 28-Dec-2005 + +# To use, do "wmake -f watcom_l.mak" + +C_SOURCE = adler32.c compress.c crc32.c deflate.c & + gzclose.c gzlib.c gzread.c gzwrite.c & + infback.c inffast.c inflate.c inftrees.c & + trees.c uncompr.c zutil.c + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj & + gzclose.obj gzlib.obj gzread.obj gzwrite.obj & + infback.obj inffast.obj inflate.obj inftrees.obj & + trees.obj uncompr.obj zutil.obj + +CC = wcc +LINKER = wcl +CFLAGS = -zq -ml -s -bt=dos -oilrtfm -fr=nul -wx +ZLIB_LIB = zlib_l.lib + +.C.OBJ: + $(CC) $(CFLAGS) $[@ + +all: $(ZLIB_LIB) example.exe minigzip.exe + +$(ZLIB_LIB): $(OBJS) + wlib -b -c $(ZLIB_LIB) -+adler32.obj -+compress.obj -+crc32.obj + wlib -b -c $(ZLIB_LIB) -+gzclose.obj -+gzlib.obj -+gzread.obj -+gzwrite.obj + wlib -b -c $(ZLIB_LIB) -+deflate.obj -+infback.obj + wlib -b -c $(ZLIB_LIB) -+inffast.obj -+inflate.obj -+inftrees.obj + wlib -b -c $(ZLIB_LIB) -+trees.obj -+uncompr.obj -+zutil.obj + +example.exe: $(ZLIB_LIB) example.obj + $(LINKER) -fe=example.exe example.obj $(ZLIB_LIB) + +minigzip.exe: $(ZLIB_LIB) minigzip.obj + $(LINKER) -fe=minigzip.exe minigzip.obj $(ZLIB_LIB) + +clean: .SYMBOLIC + del *.obj + del $(ZLIB_LIB) + @echo Cleaning done diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/DLL_FAQ.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/DLL_FAQ.txt new file mode 100644 index 00000000..12c00901 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/DLL_FAQ.txt @@ -0,0 +1,397 @@ + + Frequently Asked Questions about ZLIB1.DLL + + +This document describes the design, the rationale, and the usage +of the official DLL build of zlib, named ZLIB1.DLL. If you have +general questions about zlib, you should see the file "FAQ" found +in the zlib distribution, or at the following location: + http://www.gzip.org/zlib/zlib_faq.html + + + 1. What is ZLIB1.DLL, and how can I get it? + + - ZLIB1.DLL is the official build of zlib as a DLL. + (Please remark the character '1' in the name.) + + Pointers to a precompiled ZLIB1.DLL can be found in the zlib + web site at: + http://www.zlib.net/ + + Applications that link to ZLIB1.DLL can rely on the following + specification: + + * The exported symbols are exclusively defined in the source + files "zlib.h" and "zlib.def", found in an official zlib + source distribution. + * The symbols are exported by name, not by ordinal. + * The exported names are undecorated. + * The calling convention of functions is "C" (CDECL). + * The ZLIB1.DLL binary is linked to MSVCRT.DLL. + + The archive in which ZLIB1.DLL is bundled contains compiled + test programs that must run with a valid build of ZLIB1.DLL. + It is recommended to download the prebuilt DLL from the zlib + web site, instead of building it yourself, to avoid potential + incompatibilities that could be introduced by your compiler + and build settings. If you do build the DLL yourself, please + make sure that it complies with all the above requirements, + and it runs with the precompiled test programs, bundled with + the original ZLIB1.DLL distribution. + + If, for any reason, you need to build an incompatible DLL, + please use a different file name. + + + 2. Why did you change the name of the DLL to ZLIB1.DLL? + What happened to the old ZLIB.DLL? + + - The old ZLIB.DLL, built from zlib-1.1.4 or earlier, required + compilation settings that were incompatible to those used by + a static build. The DLL settings were supposed to be enabled + by defining the macro ZLIB_DLL, before including "zlib.h". + Incorrect handling of this macro was silently accepted at + build time, resulting in two major problems: + + * ZLIB_DLL was missing from the old makefile. When building + the DLL, not all people added it to the build options. In + consequence, incompatible incarnations of ZLIB.DLL started + to circulate around the net. + + * When switching from using the static library to using the + DLL, applications had to define the ZLIB_DLL macro and + to recompile all the sources that contained calls to zlib + functions. Failure to do so resulted in creating binaries + that were unable to run with the official ZLIB.DLL build. + + The only possible solution that we could foresee was to make + a binary-incompatible change in the DLL interface, in order to + remove the dependency on the ZLIB_DLL macro, and to release + the new DLL under a different name. + + We chose the name ZLIB1.DLL, where '1' indicates the major + zlib version number. We hope that we will not have to break + the binary compatibility again, at least not as long as the + zlib-1.x series will last. + + There is still a ZLIB_DLL macro, that can trigger a more + efficient build and use of the DLL, but compatibility no + longer dependents on it. + + + 3. Can I build ZLIB.DLL from the new zlib sources, and replace + an old ZLIB.DLL, that was built from zlib-1.1.4 or earlier? + + - In principle, you can do it by assigning calling convention + keywords to the macros ZEXPORT and ZEXPORTVA. In practice, + it depends on what you mean by "an old ZLIB.DLL", because the + old DLL exists in several mutually-incompatible versions. + You have to find out first what kind of calling convention is + being used in your particular ZLIB.DLL build, and to use the + same one in the new build. If you don't know what this is all + about, you might be better off if you would just leave the old + DLL intact. + + + 4. Can I compile my application using the new zlib interface, and + link it to an old ZLIB.DLL, that was built from zlib-1.1.4 or + earlier? + + - The official answer is "no"; the real answer depends again on + what kind of ZLIB.DLL you have. Even if you are lucky, this + course of action is unreliable. + + If you rebuild your application and you intend to use a newer + version of zlib (post- 1.1.4), it is strongly recommended to + link it to the new ZLIB1.DLL. + + + 5. Why are the zlib symbols exported by name, and not by ordinal? + + - Although exporting symbols by ordinal is a little faster, it + is risky. Any single glitch in the maintenance or use of the + DEF file that contains the ordinals can result in incompatible + builds and frustrating crashes. Simply put, the benefits of + exporting symbols by ordinal do not justify the risks. + + Technically, it should be possible to maintain ordinals in + the DEF file, and still export the symbols by name. Ordinals + exist in every DLL, and even if the dynamic linking performed + at the DLL startup is searching for names, ordinals serve as + hints, for a faster name lookup. However, if the DEF file + contains ordinals, the Microsoft linker automatically builds + an implib that will cause the executables linked to it to use + those ordinals, and not the names. It is interesting to + notice that the GNU linker for Win32 does not suffer from this + problem. + + It is possible to avoid the DEF file if the exported symbols + are accompanied by a "__declspec(dllexport)" attribute in the + source files. You can do this in zlib by predefining the + ZLIB_DLL macro. + + + 6. I see that the ZLIB1.DLL functions use the "C" (CDECL) calling + convention. Why not use the STDCALL convention? + STDCALL is the standard convention in Win32, and I need it in + my Visual Basic project! + + (For readability, we use CDECL to refer to the convention + triggered by the "__cdecl" keyword, STDCALL to refer to + the convention triggered by "__stdcall", and FASTCALL to + refer to the convention triggered by "__fastcall".) + + - Most of the native Windows API functions (without varargs) use + indeed the WINAPI convention (which translates to STDCALL in + Win32), but the standard C functions use CDECL. If a user + application is intrinsically tied to the Windows API (e.g. + it calls native Windows API functions such as CreateFile()), + sometimes it makes sense to decorate its own functions with + WINAPI. But if ANSI C or POSIX portability is a goal (e.g. + it calls standard C functions such as fopen()), it is not a + sound decision to request the inclusion of , or to + use non-ANSI constructs, for the sole purpose to make the user + functions STDCALL-able. + + The functionality offered by zlib is not in the category of + "Windows functionality", but is more like "C functionality". + + Technically, STDCALL is not bad; in fact, it is slightly + faster than CDECL, and it works with variable-argument + functions, just like CDECL. It is unfortunate that, in spite + of using STDCALL in the Windows API, it is not the default + convention used by the C compilers that run under Windows. + The roots of the problem reside deep inside the unsafety of + the K&R-style function prototypes, where the argument types + are not specified; but that is another story for another day. + + The remaining fact is that CDECL is the default convention. + Even if an explicit convention is hard-coded into the function + prototypes inside C headers, problems may appear. The + necessity to expose the convention in users' callbacks is one + of these problems. + + The calling convention issues are also important when using + zlib in other programming languages. Some of them, like Ada + (GNAT) and Fortran (GNU G77), have C bindings implemented + initially on Unix, and relying on the C calling convention. + On the other hand, the pre- .NET versions of Microsoft Visual + Basic require STDCALL, while Borland Delphi prefers, although + it does not require, FASTCALL. + + In fairness to all possible uses of zlib outside the C + programming language, we choose the default "C" convention. + Anyone interested in different bindings or conventions is + encouraged to maintain specialized projects. The "contrib/" + directory from the zlib distribution already holds a couple + of foreign bindings, such as Ada, C++, and Delphi. + + + 7. I need a DLL for my Visual Basic project. What can I do? + + - Define the ZLIB_WINAPI macro before including "zlib.h", when + building both the DLL and the user application (except that + you don't need to define anything when using the DLL in Visual + Basic). The ZLIB_WINAPI macro will switch on the WINAPI + (STDCALL) convention. The name of this DLL must be different + than the official ZLIB1.DLL. + + Gilles Vollant has contributed a build named ZLIBWAPI.DLL, + with the ZLIB_WINAPI macro turned on, and with the minizip + functionality built in. For more information, please read + the notes inside "contrib/vstudio/readme.txt", found in the + zlib distribution. + + + 8. I need to use zlib in my Microsoft .NET project. What can I + do? + + - Henrik Ravn has contributed a .NET wrapper around zlib. Look + into contrib/dotzlib/, inside the zlib distribution. + + + 9. If my application uses ZLIB1.DLL, should I link it to + MSVCRT.DLL? Why? + + - It is not required, but it is recommended to link your + application to MSVCRT.DLL, if it uses ZLIB1.DLL. + + The executables (.EXE, .DLL, etc.) that are involved in the + same process and are using the C run-time library (i.e. they + are calling standard C functions), must link to the same + library. There are several libraries in the Win32 system: + CRTDLL.DLL, MSVCRT.DLL, the static C libraries, etc. + Since ZLIB1.DLL is linked to MSVCRT.DLL, the executables that + depend on it should also be linked to MSVCRT.DLL. + + +10. Why are you saying that ZLIB1.DLL and my application should + be linked to the same C run-time (CRT) library? I linked my + application and my DLLs to different C libraries (e.g. my + application to a static library, and my DLLs to MSVCRT.DLL), + and everything works fine. + + - If a user library invokes only pure Win32 API (accessible via + and the related headers), its DLL build will work + in any context. But if this library invokes standard C API, + things get more complicated. + + There is a single Win32 library in a Win32 system. Every + function in this library resides in a single DLL module, that + is safe to call from anywhere. On the other hand, there are + multiple versions of the C library, and each of them has its + own separate internal state. Standalone executables and user + DLLs that call standard C functions must link to a C run-time + (CRT) library, be it static or shared (DLL). Intermixing + occurs when an executable (not necessarily standalone) and a + DLL are linked to different CRTs, and both are running in the + same process. + + Intermixing multiple CRTs is possible, as long as their + internal states are kept intact. The Microsoft Knowledge Base + articles KB94248 "HOWTO: Use the C Run-Time" and KB140584 + "HOWTO: Link with the Correct C Run-Time (CRT) Library" + mention the potential problems raised by intermixing. + + If intermixing works for you, it's because your application + and DLLs are avoiding the corruption of each of the CRTs' + internal states, maybe by careful design, or maybe by fortune. + + Also note that linking ZLIB1.DLL to non-Microsoft CRTs, such + as those provided by Borland, raises similar problems. + + +11. Why are you linking ZLIB1.DLL to MSVCRT.DLL? + + - MSVCRT.DLL exists on every Windows 95 with a new service pack + installed, or with Microsoft Internet Explorer 4 or later, and + on all other Windows 4.x or later (Windows 98, Windows NT 4, + or later). It is freely distributable; if not present in the + system, it can be downloaded from Microsoft or from other + software provider for free. + + The fact that MSVCRT.DLL does not exist on a virgin Windows 95 + is not so problematic. Windows 95 is scarcely found nowadays, + Microsoft ended its support a long time ago, and many recent + applications from various vendors, including Microsoft, do not + even run on it. Furthermore, no serious user should run + Windows 95 without a proper update installed. + + +12. Why are you not linking ZLIB1.DLL to + <> ? + + - We considered and abandoned the following alternatives: + + * Linking ZLIB1.DLL to a static C library (LIBC.LIB, or + LIBCMT.LIB) is not a good option. People are using the DLL + mainly to save disk space. If you are linking your program + to a static C library, you may as well consider linking zlib + in statically, too. + + * Linking ZLIB1.DLL to CRTDLL.DLL looks appealing, because + CRTDLL.DLL is present on every Win32 installation. + Unfortunately, it has a series of problems: it does not + work properly with Microsoft's C++ libraries, it does not + provide support for 64-bit file offsets, (and so on...), + and Microsoft discontinued its support a long time ago. + + * Linking ZLIB1.DLL to MSVCR70.DLL or MSVCR71.DLL, supplied + with the Microsoft .NET platform, and Visual C++ 7.0/7.1, + raises problems related to the status of ZLIB1.DLL as a + system component. According to the Microsoft Knowledge Base + article KB326922 "INFO: Redistribution of the Shared C + Runtime Component in Visual C++ .NET", MSVCR70.DLL and + MSVCR71.DLL are not supposed to function as system DLLs, + because they may clash with MSVCRT.DLL. Instead, the + application's installer is supposed to put these DLLs + (if needed) in the application's private directory. + If ZLIB1.DLL depends on a non-system runtime, it cannot + function as a redistributable system component. + + * Linking ZLIB1.DLL to non-Microsoft runtimes, such as + Borland's, or Cygwin's, raises problems related to the + reliable presence of these runtimes on Win32 systems. + It's easier to let the DLL build of zlib up to the people + who distribute these runtimes, and who may proceed as + explained in the answer to Question 14. + + +13. If ZLIB1.DLL cannot be linked to MSVCR70.DLL or MSVCR71.DLL, + how can I build/use ZLIB1.DLL in Microsoft Visual C++ 7.0 + (Visual Studio .NET) or newer? + + - Due to the problems explained in the Microsoft Knowledge Base + article KB326922 (see the previous answer), the C runtime that + comes with the VC7 environment is no longer considered a + system component. That is, it should not be assumed that this + runtime exists, or may be installed in a system directory. + Since ZLIB1.DLL is supposed to be a system component, it may + not depend on a non-system component. + + In order to link ZLIB1.DLL and your application to MSVCRT.DLL + in VC7, you need the library of Visual C++ 6.0 or older. If + you don't have this library at hand, it's probably best not to + use ZLIB1.DLL. + + We are hoping that, in the future, Microsoft will provide a + way to build applications linked to a proper system runtime, + from the Visual C++ environment. Until then, you have a + couple of alternatives, such as linking zlib in statically. + If your application requires dynamic linking, you may proceed + as explained in the answer to Question 14. + + +14. I need to link my own DLL build to a CRT different than + MSVCRT.DLL. What can I do? + + - Feel free to rebuild the DLL from the zlib sources, and link + it the way you want. You should, however, clearly state that + your build is unofficial. You should give it a different file + name, and/or install it in a private directory that can be + accessed by your application only, and is not visible to the + others (i.e. it's neither in the PATH, nor in the SYSTEM or + SYSTEM32 directories). Otherwise, your build may clash with + applications that link to the official build. + + For example, in Cygwin, zlib is linked to the Cygwin runtime + CYGWIN1.DLL, and it is distributed under the name CYGZ.DLL. + + +15. May I include additional pieces of code that I find useful, + link them in ZLIB1.DLL, and export them? + + - No. A legitimate build of ZLIB1.DLL must not include code + that does not originate from the official zlib source code. + But you can make your own private DLL build, under a different + file name, as suggested in the previous answer. + + For example, zlib is a part of the VCL library, distributed + with Borland Delphi and C++ Builder. The DLL build of VCL + is a redistributable file, named VCLxx.DLL. + + +16. May I remove some functionality out of ZLIB1.DLL, by enabling + macros like NO_GZCOMPRESS or NO_GZIP at compile time? + + - No. A legitimate build of ZLIB1.DLL must provide the complete + zlib functionality, as implemented in the official zlib source + code. But you can make your own private DLL build, under a + different file name, as suggested in the previous answer. + + +17. I made my own ZLIB1.DLL build. Can I test it for compliance? + + - We prefer that you download the official DLL from the zlib + web site. If you need something peculiar from this DLL, you + can send your suggestion to the zlib mailing list. + + However, in case you do rebuild the DLL yourself, you can run + it with the test programs found in the DLL distribution. + Running these test programs is not a guarantee of compliance, + but a failure can imply a detected problem. + +** + +This document is written and maintained by +Cosmin Truta diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.bor b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.bor new file mode 100644 index 00000000..3981d424 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.bor @@ -0,0 +1,110 @@ +# Makefile for zlib +# Borland C++ for Win32 +# +# Usage: +# make -f win32/Makefile.bor +# make -f win32/Makefile.bor LOCAL_ZLIB=-DASMV OBJA=match.obj OBJPA=+match.obj + +# ------------ Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or +# added to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +CC = bcc32 +AS = bcc32 +LD = bcc32 +AR = tlib +CFLAGS = -a -d -k- -O2 $(LOC) +ASFLAGS = $(LOC) +LDFLAGS = $(LOC) + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +#OBJA = +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj +#OBJPA= + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $< + +.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) $(OBJA) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + $(AR) $(ZLIB_LIB) $(OBJPA) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del $(ZLIB_LIB) + -del *.obj + -del *.exe + -del *.tds + -del zlib.bak + -del foo.gz diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.emx b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.emx new file mode 100644 index 00000000..4d6ab0ef --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx/rsxnt by Chr. Spieler, 6/16/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc -Zwin32 + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.gcc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.gcc new file mode 100644 index 00000000..0a33bf6a --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.gcc @@ -0,0 +1,164 @@ +# Makefile for zlib, derived from Makefile.dj2. +# Modified for mingw32 by C. Spieler, 6/16/98. +# Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003. +# Last updated: 1-Aug-2003. +# Tested under Cygwin and MinGW. + +# Copyright (C) 1995-2003 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.gcc; make test testdll -fmakefile.gcc +# +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o -fmakefile.gcc +# +# To install libz.a, zconf.h and zlib.h in the system directories, type: +# +# make install -fmakefile.gcc + +# Note: +# If the platform is *not* MinGW (e.g. it is Cygwin or UWIN), +# the DLL name should be changed from "zlib1.dll". + +STATICLIB = libz.a +SHAREDLIB = zlib1.dll +IMPLIB = libzdll.a + +# +# Set to 1 if shared object needs to be installed +# +SHARED_MODE=0 + +#LOC = -DASMV +#LOC = -DDEBUG -g + +PREFIX = +CC = $(PREFIX)gcc +CFLAGS = $(LOC) -O3 -Wall +EXTRA_CFLAGS = -DNO_VIZ + +AS = $(CC) +ASFLAGS = $(LOC) -Wall + +LD = $(CC) +LDFLAGS = $(LOC) + +AR = $(PREFIX)ar +ARFLAGS = rcs + +RC = $(PREFIX)windres +RCFLAGS = --define GCC_WINDRES + +STRIP = $(PREFIX)strip + +CP = cp -fp +# If GNU install is available, replace $(CP) with install. +INSTALL = $(CP) +RM = rm -f + +prefix = /usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o +OBJA = + +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) example.exe minigzip.exe example_d.exe minigzip_d.exe + +test: example.exe minigzip.exe + ./example + echo hello world | ./minigzip | ./minigzip -d + +testdll: example_d.exe minigzip_d.exe + ./example_d + echo hello world | ./minigzip_d | ./minigzip_d -d + +.c.o: + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + +.S.o: + $(AS) $(ASFLAGS) -c -o $@ $< + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) $@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + $(CC) -shared -Wl,--out-implib,$(IMPLIB) $(LDFLAGS) \ + -o $@ win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + $(STRIP) $@ + +example.exe: example.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(STATICLIB) + $(STRIP) $@ + +minigzip.exe: minigzip.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(STATICLIB) + $(STRIP) $@ + +example_d.exe: example.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(IMPLIB) + $(STRIP) $@ + +minigzip_d.exe: minigzip.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(IMPLIB) + $(STRIP) $@ + +zlibrc.o: win32/zlib1.rc + $(RC) $(RCFLAGS) -o $@ win32/zlib1.rc + + +# BINARY_PATH, INCLUDE_PATH and LIBRARY_PATH must be set. + +.PHONY: install uninstall clean + +install: zlib.h zconf.h $(STATICLIB) $(IMPLIB) + -@mkdir -p $(INCLUDE_PATH) + -@mkdir -p $(LIBRARY_PATH) + -if [ "$(SHARED_MODE)" = "1" ]; then \ + mkdir -p $(BINARY_PATH); \ + $(INSTALL) $(SHAREDLIB) $(BINARY_PATH); \ + $(INSTALL) $(IMPLIB) $(LIBRARY_PATH); \ + fi + -$(INSTALL) zlib.h $(INCLUDE_PATH) + -$(INSTALL) zconf.h $(INCLUDE_PATH) + -$(INSTALL) $(STATICLIB) $(LIBRARY_PATH) + +uninstall: + -if [ "$(SHARED_MODE)" = "1" ]; then \ + $(RM) $(BINARY_PATH)/$(SHAREDLIB); \ + $(RM) $(LIBRARY_PATH)/$(IMPLIB); \ + fi + -$(RM) $(INCLUDE_PATH)/zlib.h + -$(RM) $(INCLUDE_PATH)/zconf.h + -$(RM) $(LIBRARY_PATH)/$(STATICLIB) + +clean: + -$(RM) $(STATICLIB) + -$(RM) $(SHAREDLIB) + -$(RM) $(IMPLIB) + -$(RM) *.o + -$(RM) *.exe + -$(RM) foo.gz + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzclose.o: zlib.h zconf.h gzguts.h +gzlib.o: zlib.h zconf.h gzguts.h +gzread.o: zlib.h zconf.h gzguts.h +gzwrite.o: zlib.h zconf.h gzguts.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.msc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.msc new file mode 100644 index 00000000..fa10a1aa --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/Makefile.msc @@ -0,0 +1,157 @@ +# Makefile for zlib using Microsoft (Visual) C +# zlib is copyright (C) 1995-2006 Jean-loup Gailly and Mark Adler +# +# Usage: +# nmake -f win32/Makefile.msc (standard build) +# nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) +# nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" \ +# OBJA="inffas32.obj match686.obj" (use ASM code, x86) +# nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF" \ +# OBJA="inffasx64.obj gvmat64.obj inffas8664.c" (use ASM code, x64) + +# optional build flags +LOC = + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib + +CC = cl +AS = ml +LD = link +AR = lib +RC = rc +CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) +WFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE +ASFLAGS = -coff -Zi $(LOC) +LDFLAGS = -nologo -debug -incremental:no -opt:ref +ARFLAGS = -nologo +RCFLAGS = /dWIN32 /r + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj \ + gzwrite.obj infback.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJA = + + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlib1.res + $(LD) $(LDFLAGS) -def:win32/zlib.def -dll -implib:$(IMPLIB) \ + -out:$@ -base:0x5A4C0000 $(OBJS) $(OBJA) zlib1.res + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +example.exe: example.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip.exe: minigzip.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example_d.exe: example.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip_d.exe: minigzip.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +{contrib/masmx64}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +{contrib/masmx64}.asm.obj: + $(AS) -c $(ASFLAGS) $< + +{contrib/masmx86}.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +gvmat64.obj: contrib\masmx64\gvmat64.asm + +inffasx64.obj: contrib\masmx64\inffasx64.asm + +inffas8664.obj: contrib\masmx64\inffas8664.c zutil.h zlib.h zconf.h \ + inftrees.h inflate.h inffast.h + +inffas32.obj: contrib\masmx86\inffas32.asm + +match686.obj: contrib\masmx86\match686.asm + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + +zlib1.res: win32/zlib1.rc + $(RC) $(RCFLAGS) /fo$@ win32/zlib1.rc + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del *.pdb + -del *.manifest + -del foo.gz diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/README-WIN32.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/README-WIN32.txt new file mode 100644 index 00000000..1e4c093c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/README-WIN32.txt @@ -0,0 +1,103 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.4 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). Two compiled +examples are distributed in this package, example and minigzip. The example_d +and minigzip_d flavors validate that the zlib1.dll file is working correctly. + +Questions about zlib should be sent to . The zlib home page +is http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read DLL_FAQ.txt, and the the zlib FAQ http://zlib.net/zlib_faq.html +before asking for help. + + +Manifest: + +The package zlib-1.2.4-win32-x86.zip contains the following files: + + README-WIN32.txt This document + ChangeLog Changes since previous zlib packages + DLL_FAQ.txt Frequently asked questions about zlib1.dll + zlib.3.pdf Documentation of this library in Adobe Acrobat format + + example.exe A statically-bound example (using zlib.lib, not the dll) + example.pdb Symbolic information for debugging example.exe + + example_d.exe A zlib1.dll bound example (using zdll.lib) + example_d.pdb Symbolic information for debugging example_d.exe + + minigzip.exe A statically-bound test program (using zlib.lib, not the dll) + minigzip.pdb Symbolic information for debugging minigzip.exe + + minigzip_d.exe A zlib1.dll bound test program (using zdll.lib) + minigzip_d.pdb Symbolic information for debugging minigzip_d.exe + + zlib.h Install these files into the compilers' INCLUDE path to + zconf.h compile programs which use zlib.lib or zdll.lib + + zdll.lib Install these files into the compilers' LIB path if linking + zdll.exp a compiled program to the zlib1.dll binary + + zlib.lib Install these files into the compilers' LIB path to link zlib + zlib.pdb into compiled programs, without zlib1.dll runtime dependency + (zlib.pdb provides debugging info to the compile time linker) + + zlib1.dll Install this binary shared library into the system PATH, or + the program's runtime directory (where the .exe resides) + zlib1.pdb Install in the same directory as zlib1.dll, in order to debug + an application crash using WinDbg or similar tools. + +All .pdb files above are entirely optional, but are very useful to a developer +attempting to diagnose program misbehavior or a crash. Many additional +important files for developers can be found in the zlib124.zip source package +available from http://zlib.net/ - review that package's README file for details. + + +Acknowledgments: + +The deflate format used by zlib was defined by Phil Katz. The deflate and +zlib specifications were written by L. Peter Deutsch. Thanks to all the +people who reported problems and suggested various improvements in zlib; they +are too numerous to cite here. + + +Copyright notice: + + (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/VisualC.txt b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/VisualC.txt new file mode 100644 index 00000000..579a5fc9 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/VisualC.txt @@ -0,0 +1,3 @@ + +To build zlib using the Microsoft Visual C++ environment, +use the appropriate project from the projects/ directory. diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/zlib.def b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/zlib.def new file mode 100644 index 00000000..94533753 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/zlib.def @@ -0,0 +1,74 @@ +LIBRARY +; zlib data compression library + +EXPORTS +; basic functions + zlibVersion + deflate + deflateEnd + inflate + inflateEnd +; advanced functions + deflateSetDictionary + deflateCopy + deflateReset + deflateParams + deflateTune + deflateBound + deflatePrime + deflateSetHeader + inflateSetDictionary + inflateSync + inflateCopy + inflateReset + inflateReset2 + inflatePrime + inflateMark + inflateGetHeader + inflateBack + inflateBackEnd + zlibCompileFlags +; utility functions + compress + compress2 + compressBound + uncompress + gzopen + gzdopen + gzbuffer + gzsetparams + gzread + gzwrite + gzprintf + gzputs + gzgets + gzputc + gzgetc + gzungetc + gzflush + gzseek + gzrewind + gztell + gzoffset + gzeof + gzdirect + gzclose + gzclose_r + gzclose_w + gzerror + gzclearerr +; checksum functions + adler32 + crc32 + adler32_combine + crc32_combine +; various hacks, don't look :) + deflateInit_ + deflateInit2_ + inflateInit_ + inflateInit2_ + inflateBackInit_ + zError + inflateSyncPoint + get_crc_table + inflateUndermine diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/zlib1.rc b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/zlib1.rc new file mode 100644 index 00000000..0d1d7ffc --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/win32/zlib1.rc @@ -0,0 +1,40 @@ +#include +#include "../zlib.h" + +#ifdef GCC_WINDRES +VS_VERSION_INFO VERSIONINFO +#else +VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE +#endif + FILEVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + PRODUCTVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS 1 +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", ZLIB_VERSION "\0" + VALUE "InternalName", "zlib1.dll\0" + VALUE "LegalCopyright", "(C) 1995-2006 Jean-loup Gailly & Mark Adler\0" + VALUE "OriginalFilename", "zlib1.dll\0" + VALUE "ProductName", "zlib\0" + VALUE "ProductVersion", ZLIB_VERSION "\0" + VALUE "Comments", "For more information visit http://www.zlib.net/\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h new file mode 100644 index 00000000..043488fe --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h @@ -0,0 +1,428 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h 246 2010-04-23 10:54:55Z nijtmans $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h.cmakein b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h.cmakein new file mode 100644 index 00000000..a2f71b1f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h.cmakein @@ -0,0 +1,430 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +#cmakedefine Z_PREFIX +#cmakedefine Z_HAVE_UNISTD_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h.in b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h.in new file mode 100644 index 00000000..3e9a4813 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zconf.h.in @@ -0,0 +1,428 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h.in 246 2010-04-23 10:54:55Z nijtmans $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.3 b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.3 new file mode 100644 index 00000000..27adc4cd --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.3 @@ -0,0 +1,151 @@ +.TH ZLIB 3 "19 Apr 2010" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe, assuming that the standard library functions +used are thread safe, such as memory allocation routines. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms may be added later +with the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in the case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I example.c +and +.IR minigzip.c, +as well as other examples in the +.IR examples/ +directory. +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source. +.LP +.I zlib +is available in Java using the java.util.zip package: +.IP +http://java.sun.com/developer/technicalArticles/Programming/compression/ +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://www.python.org/doc/lib/module-zlib.html +.LP +.I zlib +is built into +.IR tcl: +.IP +http://wiki.tcl.tk/4610 +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/minizip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +source distribution. +.SH "SEE ALSO" +The +.I zlib +web site can be found at: +.IP +http://zlib.net/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://www.ietf.org/rfc/rfc1950.txt (for the zlib header and trailer format) +.br +http://www.ietf.org/rfc/rfc1951.txt (for the deflate compressed data format) +.br +http://www.ietf.org/rfc/rfc1952.txt (for the gzip header and trailer format) +.LP +Mark Nelson wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://marknelson.us/1997/01/01/zlib-engine/ +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://zlib.net/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.5 +Copyright (C) 1995-2010 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.3.pdf b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.3.pdf new file mode 100644 index 00000000..9f8a2c39 Binary files /dev/null and b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.3.pdf differ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.h new file mode 100644 index 00000000..bfbba83e --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.h @@ -0,0 +1,1613 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.5, April 19th, 2010 + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.5" +#define ZLIB_VERNUM 0x1250 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is never required, but can be + used to inform inflate that a faster approach may be used for the single + inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK or Z_TREES is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been + found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the + success case, the application may save the current current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef voidp gzFile; /* opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) Also "a" + can be used instead of "w" to request that the gzip stream that will be + written be appended to the file. "+" will result in an error, since reading + and writing to the same gzip file is not supported. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file was not in gzip format, gzread copies the given number of + bytes into the buffer. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream, or failing that, reading the rest + of the input file directly without decompression. The entire input file + will be read if gzread is called until it returns less than the requested + len. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. This state can change from + false to true while reading the input file if the end of a gzip stream is + reached, but is followed by data that is not another gzip stream. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# ifdef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.map b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.map new file mode 100644 index 00000000..f282d362 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.map @@ -0,0 +1,68 @@ +ZLIB_1.2.0 { + global: + compressBound; + deflateBound; + inflateBack; + inflateBackEnd; + inflateBackInit_; + inflateCopy; + local: + deflate_copyright; + inflate_copyright; + inflate_fast; + inflate_table; + zcalloc; + zcfree; + z_errmsg; + gz_error; + gz_intmax; + _*; +}; + +ZLIB_1.2.0.2 { + gzclearerr; + gzungetc; + zlibCompileFlags; +} ZLIB_1.2.0; + +ZLIB_1.2.0.8 { + deflatePrime; +} ZLIB_1.2.0.2; + +ZLIB_1.2.2 { + adler32_combine; + crc32_combine; + deflateSetHeader; + inflateGetHeader; +} ZLIB_1.2.0.8; + +ZLIB_1.2.2.3 { + deflateTune; + gzdirect; +} ZLIB_1.2.2; + +ZLIB_1.2.2.4 { + inflatePrime; +} ZLIB_1.2.2.3; + +ZLIB_1.2.3.3 { + adler32_combine64; + crc32_combine64; + gzopen64; + gzseek64; + gztell64; + inflateUndermine; +} ZLIB_1.2.2.4; + +ZLIB_1.2.3.4 { + inflateReset2; + inflateMark; +} ZLIB_1.2.3.3; + +ZLIB_1.2.3.5 { + gzbuffer; + gzoffset; + gzoffset64; + gzclose_r; + gzclose_w; +} ZLIB_1.2.3.4; diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.pc.in b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.pc.in new file mode 100644 index 00000000..7e5acf9c --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sharedlibdir=@sharedlibdir@ +includedir=@includedir@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib2ansi b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib2ansi new file mode 100644 index 00000000..15e3e165 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zlib2ansi @@ -0,0 +1,152 @@ +#!/usr/bin/perl + +# Transform K&R C function definitions into ANSI equivalent. +# +# Author: Paul Marquess +# Version: 1.0 +# Date: 3 October 2006 + +# TODO +# +# Asumes no function pointer parameters. unless they are typedefed. +# Assumes no literal strings that look like function definitions +# Assumes functions start at the beginning of a line + +use strict; +use warnings; + +local $/; +$_ = <>; + +my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments + +my $d1 = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ; +my $decl = qr{ $sp (?: \w+ $sp )+ $d1 }xo ; +my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ; + + +while (s/^ + ( # Start $1 + ( # Start $2 + .*? # Minimal eat content + ( ^ \w [\w\s\*]+ ) # $3 -- function name + \s* # optional whitespace + ) # $2 - Matched up to before parameter list + + \( \s* # Literal "(" + optional whitespace + ( [^\)]+ ) # $4 - one or more anythings except ")" + \s* \) # optional whitespace surrounding a Literal ")" + + ( (?: $dList )+ ) # $5 + + $sp ^ { # literal "{" at start of line + ) # Remember to $1 + //xsom + ) +{ + my $all = $1 ; + my $prefix = $2; + my $param_list = $4 ; + my $params = $5; + + StripComments($params); + StripComments($param_list); + $param_list =~ s/^\s+//; + $param_list =~ s/\s+$//; + + my $i = 0 ; + my %pList = map { $_ => $i++ } + split /\s*,\s*/, $param_list; + my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ; + + my @params = split /\s*;\s*/, $params; + my @outParams = (); + foreach my $p (@params) + { + if ($p =~ /,/) + { + my @bits = split /\s*,\s*/, $p; + my $first = shift @bits; + $first =~ s/^\s*//; + push @outParams, $first; + $first =~ /^(\w+\s*)/; + my $type = $1 ; + push @outParams, map { $type . $_ } @bits; + } + else + { + $p =~ s/^\s+//; + push @outParams, $p; + } + } + + + my %tmp = map { /$pMatch/; $_ => $pList{$1} } + @outParams ; + + @outParams = map { " $_" } + sort { $tmp{$a} <=> $tmp{$b} } + @outParams ; + + print $prefix ; + print "(\n" . join(",\n", @outParams) . ")\n"; + print "{" ; + +} + +# Output any trailing code. +print ; +exit 0; + + +sub StripComments +{ + + no warnings; + + # Strip C & C++ coments + # From the perlfaq + $_[0] =~ + + s{ + /\* ## Start of /* ... */ comment + [^*]*\*+ ## Non-* followed by 1-or-more *'s + ( + [^/*][^*]*\*+ + )* ## 0-or-more things which don't start with / + ## but do end with '*' + / ## End of /* ... */ comment + + | ## OR C++ Comment + // ## Start of C++ comment // + [^\n]* ## followed by 0-or-more non end of line characters + + | ## OR various things which aren't comments: + + ( + " ## Start of " ... " string + ( + \\. ## Escaped char + | ## OR + [^"\\] ## Non "\ + )* + " ## End of " ... " string + + | ## OR + + ' ## Start of ' ... ' string + ( + \\. ## Escaped char + | ## OR + [^'\\] ## Non '\ + )* + ' ## End of ' ... ' string + + | ## OR + + . ## Anything other char + [^/"'\\]* ## Chars which doesn't start a comment, string or escape + ) + }{$2}gxs; + +} diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zutil.c b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zutil.c new file mode 100644 index 00000000..d9451be7 --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c 246 2010-04-23 10:54:55Z nijtmans $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zutil.h b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zutil.h new file mode 100644 index 00000000..e7832a1f --- /dev/null +++ b/src/vfs/critcl.vfs/examples/zlibwrap/zlib/zutil.h @@ -0,0 +1,274 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h 246 2010-04-23 10:54:55Z nijtmans $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#ifdef STDC +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); +void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/src/vfs/critcl.vfs/lib/app-critcl/critcl.tcl b/src/vfs/critcl.vfs/lib/app-critcl/critcl.tcl new file mode 100644 index 00000000..47e5bf64 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/critcl.tcl @@ -0,0 +1,1861 @@ +#!/bin/sh +# -*- tcl -*- +# # ## ### ##### ######## ############# ##################### + +# Critcl Application. + +# # ## ### ##### ######## ############# ##################### + +# Prebuild shared libraries using the Critcl package. +# +# Based originally on critbind by Jean-Claude Wippler +# Transmogrified into critcl by Steve Landers +# +# Copyright (c) 2001-20?? Jean-Claude Wippler +# Copyright (c) 2002-20?? Steve Landers +# Copyright (c) 20??-2023 Andreas Kupries +# +# \ + exec tclkit $0 ${1+"$@"} + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.6 9 +package provide critcl::app [package require critcl] +package require cmdline + +# It is expected here that critcl already imported platform, or an +# equivalent package, i.e. the critcl::platform fallback. No need to +# do it again. +#package require platform + +# Note: We can assume here that the commands lassign and dict are +# available. The critcl package has made sure of that. + +namespace eval ::critcl::app {} + +# # ## ### ##### ######## ############# ##################### +## https://github.com/andreas-kupries/critcl/issues/112 +## Ensure that we have maximal 'info frame' data, if supported +# +## ATTENTION: This slows the Tcl core down by about 10%, sometimes +## more, due to the need to track location information in some +## critical paths of Tcl_Obj management. +# +## I am willing to pay that price here, because this is isolated to +## the operation of the critcl application itself. While some more +## time is spent in the ahead-of-time compilation the result is not +## affected. And I want the more precise location information for when +## compilation fails. + +catch { interp debug {} -frame 1 } + +# # ## ### ##### ######## ############# ##################### +## Intercept 'package' calls. +# +# This code is present to handle the possibility of building multiple +# different versions of the same package, or of different packages +# having dependencies on different versions of a 3rd party +# package. Each will 'package provide' its version to our Tcl, and +# thus normally be reported as a conflict. To prevent that the +# intercepted command checks for this situation, and forces Tcl to +# forget the previously registered package. + +rename package ::critcl::app::__package +proc package {option args} { + if {$option eq "provide"} { + if {![catch { + set v [::critcl::app::__package present [lindex $args 0]] + }] && + ([llength $args] > 1) && + ($v ne [lindex $args 1]) + } { + # A package is provided which is already present in + # memory, the number of arguments is ok, and the version + # of the new package is different from what is + # known. Force Tcl to forget the previous package, this is + # not truly a conflict. + ::critcl::app::__package forget [lindex $args 0] + } + } + + return [eval [linsert $args 0 ::critcl::app::__package $option]] +} + +# # ## ### ##### ######## ############# ##################### +## Override the default of the critcl package for errors and +## message. Write them to the terminal (and, for errors, abort the +## application instead of throwing them up the stack to an uncertain +## catch). + +proc ::critcl::error {msg} { + global argv0 + puts stderr "$argv0 error: $msg" + flush stderr + exit 1 +} + +proc ::critcl::msg {args} { + switch -exact -- [llength $args] { + 1 { + puts stdout [lindex $args 0] + flush stdout + } + 2 { + lassign $args o m + if {$o ne "-nonewline"} { + return -code error "wrong\#args, expected: ?-nonewline? msg" + } + puts -nonewline stdout $m + flush stdout + } + default { + return -code error "wrong\#args, expected: ?-nonewline? msg" + } + } + return +} + +# # ## ### ##### ######## ############# ##################### +## +# Rewrite the hook handling declarations found after the build. +# The default of clearing state for a new build is not the right +# thing to do in mode "precompile". Here we want to see an ERROR. + +proc ::critcl::HandleDeclAfterBuild {} { + if {![done]} return + set cloc {} + if {![catch { + array set loc [info frame -2] + } msg]} { + if {$loc(type) eq "source"} { + set cloc "@$loc(file):$loc(line)" + } else { + set cloc " ([array get loc])" + } + } ;#else { set cloc " ($msg)" } + + append err [lindex [info level -1] 0] + append err $cloc + append err ": Illegal attempt to define C code in [This] after it was built." + append err \n [at::SHOWFRAMES] + error $err +} + +# # ## ### ##### ######## ############# ##################### + +proc ::critcl::app::main {argv} { + Cmdline $argv + + # When creating a package use a transient cache which is not in + # conflict with "compile & run", or other instances of the critcl + # application. + + if {$v::mode eq "pkg"} { + set pkgcache [PackageCache] + critcl::cache $pkgcache + critcl::fastuuid + } + + ProcessInput + StopOnFailed + + # All input files have been processed and their data saved. Now + # generate the boilerplate bracketing all the sub-ordinate + # Foo_Init() functions, i.e. the code which provides a single + # initialization function for the whole set of input files. + + if {$v::mode eq "pkg"} { + # Create a merged shared library and put a proper Tcl package + # around it. + + BuildBracket + StopOnFailed + AssemblePackage + + if {!$v::keep} { + file delete -force $pkgcache + } + } elseif {$v::mode eq "tea"} { + AssembleTEA + } + + StopOnFailed + + if {$v::keep} { + ::critcl::print stderr "Files left in [critcl::cache]" + } + + ::critcl::print "Done\n" + return +} + +proc ::critcl::app::PackageCache {} { + global env + if {$v::cache ne {}} { + return $v::cache + } + return [file join $env(HOME) .critcl pkg[pid].[clock seconds]] +} + +proc ::critcl::app::StopOnFailed {} { + if {!$v::failed} return + ::critcl::print stderr "Files left in [critcl::cache]" + ::critcl::print stderr "FAILURES $v::failed" + ::critcl::print stderr "FAILED: [join $v::borken "\nFAILED: "]" + ::critcl::print stderr "FAILED [join [split [join $v::log \n\n] \n] "\nFAILED "]" + exit 1 ; #return -code return +} + +proc ::critcl::app::Cmdline {argv} { + variable options + + # Rationalized application name. Direct user is the intercepted + # '::critcl::error' command. + set ::argv0 [cmdline::getArgv0] + + # Semi-global application configuration. + set v::verbose 0 ; # Default, no logging. + set v::src {} ; # No files to process. + set v::mode cache ; # Fill cache. Alternatively build a + # package, or TEA hierarchy. + set v::shlname "" ; # Name of shlib to build. + set v::outname "" ; # Name of shlib dir to create. + set v::libdir lib ; # Directory to put the -pkg or -tea + # directory into. + set v::incdir include ; # Directory to put the -pkg include files into (stubs export), + # and search in (stubs import) + set v::keep 0 ; # Default: Do not keep generated .c files. + + # Local actions. + set selftest 0 ;# Invoke the application selftest, which simply + # runs whatever test/*.tst files are found in the + # starkit or starpack. IOW, this functionality is + # usable only for a wrapped critcl application. + set cleaning 0 ;# Clean the critcl cache. Default: no. + set showall 0 ;# Show all configurations in full. Default: no. + set show 0 ;# Show the chosen build configuration. Default: no. + set showtarget 0 ;# Show the chosen build target only. Default: no. + set targets 0 ;# Show the available targets. + set help 0 ;# Show the application's help text. + + # Local configuration. Seen outside of this procedure only + # directly, through the chosen build configuration. + + set target "" ;# The user-specified build target, if any. + set configfile "" ;# The user-specified custom configuration file, + # if any + + # Process the command line... + + while {[set result [cmdline::getopt argv $options opt arg]] != 0} { + if {$result == -1} { + switch -glob -- $opt { + with-* { + set argv [lassign $argv opt arg] + regsub {^-with-} $opt {} opt + lappend v::uc $opt $arg + continue + } + default { + Usage "Unknown option \"$opt\"" + } + } + } + switch -exact -- $opt { + v - -version { + ::critcl::print [package present critcl] + ::exit 0 + } + I { AddIncludePath $arg } + L { AddLibraryPath $arg } + cache { set v::cache $arg } + clean { incr cleaning } + config { set configfile $arg } + debug { + lappend v::debug $arg + #critcl::config lines 0 + } + force { + critcl::config force 1 + ::critcl::print stderr "Compilation forced" + } + disable-tcl9 { + critcl::config tcl9 0 + ::critcl::print stderr "Disabled checking for Tcl 9 compatibility issues" + } + keep { + critcl::config keepsrc 1 + #critcl::config lines 0 + set v::keep 1 + } + trace-commands { + critcl::config trace 1 + } + trace { + critcl::cflags -DCRITCL_TRACER + } + help { incr help } + libdir { + set v::libdir $arg + + # In case critcl is wrapped Tcl must be told about the + # outside location for packages. + + lappend ::auto_path $arg + lappend ::auto_path [file dirname $arg] + AddLibraryPath $arg + } + includedir { + set v::incdir $arg + AddIncludePath $arg + } + enable { lappend v::uc $arg 1 } + disable { lappend v::uc $arg 0 } + pkg { set v::mode pkg ; incr v::verbose } + tea { set v::mode tea ; incr v::verbose } + show { incr show } + showall { incr showall } + showtarget { incr showtarget } + target { set target $arg } + targets { incr targets } + test { set selftest 1 } + default { + Usage "Unknown option \"$opt\"" + } + } + } + + # ... validate the settings, and act on them. + + if {$help} { + Help + exit + } + + # Parse the user-specified configuration file, if any. This + # overrides the default configuration file read by the critcl + # package when it was loaded. It does keep the default platform + # from that active. + + if {$configfile ne ""} { + if {$argv eq "" && [file extension $configfile] eq ".tcl"} { + # probably means the user has omitted the config file and we've + # picked up the source file name + Usage "-config is missing file argument" + } + if {![file exists $configfile]} { + Usate "Can't read configuration file $configfile" + } + critcl::readconfig $configfile + } + + # And switch to the user-provided target platform. + + if {$target ne ""} { + if {($argv eq "") && [file extension $target] eq ".tcl"} { + # probably means the user has omitted the config file and we've + # picked up the source file name + Usage "-target is missing file argument" + } + + set match [critcl::chooseconfig $target 1] + + if {[llength $match] == 1} { + critcl::setconfig [lindex $match 0] + } else { + Usage "multiple targets matched : $match" + } + } + + if {($v::mode eq "pkg") || $show} { + critcl::crosscheck + } + + if {$cleaning} { + critcl::clean_cache + } + + if {$show} { + if {$v::mode eq "pkg"} { + critcl::cache [PackageCache] + } + critcl::showconfig stdout + } + + if {$showall} { + critcl::showallconfig stdout + } + + if {$showtarget} { + ::critcl::print [critcl::targetplatform] + } + + if {$targets} { + ::critcl::print [critcl::knowntargets] + } + + if {$show || $showall || $targets || $showtarget} { + exit + } + + if {$selftest} { + Selftest + exit + } + + # Invoking the application without input files is an error, except + # if it was to just clean the local critcl cache. + + if {[llength $argv] < 1} { + if {!$cleaning} Usage + exit + } + + # The remainder of the arguments are the files to process, except + # for lib and pkg modes where they can be prefixed with the name + # of the output file, i.e. shared library. If however no such + # output file is present the name of the first input file will be + # used as name of the library. + + set v::src $argv + + # (%) Determine the name of the shared library to generate from + # the input files. This location is referenced by (=). + + if {$v::mode ne "cache"} { + set name [lindex $argv 0] + set addext 0 + + # Split a version number off the package name. + set ver {} + if {[regexp {^([^0-9]+)([0-9][.0-9]*)$} $name -> base ver]} { + set name $base + } + + switch [file extension $name] { + .dll - + .dylib - + .sl - + .so { + # The name of the result shlib is prefixed, take it as + # package name, and strip it off the list of input + # files. + set v::outname [file rootname $name] + set v::src [lrange $v::src 1 end] + set addext 1 + } + .tcl { + # We have no discernible result shlib, take + # the stem of the first input file as package + # name + + set v::outname [file rootname $name] + set addext 1 + } + "" { + # See above for .tcl, except that there is no stem to + # take. And if this is the only argument we also have + # to derive the full name of the expected input file + # from it. + set v::outname $name + if {[llength $argv] == 1} { + set v::src [list $v::outname.tcl] + } else { + set v::src [lrange $v::src 1 end] + } + } + default { + Usage "Not sure how to handle \"$name\"" + } + } + + # Put the version number back. We have to distinguish package + # library file name and package directory name. Only the + # latter should have the version number. + set v::shlname $v::outname + if {$ver ne {}} { + append v::outname $ver + } + + if {$addext || ([file extension $v::shlname] eq "")} { + append v::shlname [critcl::sharedlibext] + } + + critcl::config combine dynamic + + if {![llength $v::src]} { + Usage "No input files" + } + } + + # Determine the platform to use by the build backend, based on + # actual platform we are on and the user's chosen target, if any. + + set v::actualplatform [::critcl::actualtarget] + return +} + +proc ::critcl::app::AddIncludePath {path} { + set dirs [critcl::config I] + lappend dirs [file normalize $path] + critcl::config I $dirs + return +} + +proc ::critcl::app::AddLibraryPath {path} { + set dirs [critcl::config L] + lappend dirs [file normalize $path] + critcl::config L $dirs + return +} + +proc ::critcl::app::Log {text} { + if {!$v::verbose} return + ::critcl::print -nonewline $text + flush stdout + return +} + +proc ::critcl::app::LogLn {text} { + if {!$v::verbose} return + ::critcl::print $text + flush stdout + return +} + +proc ::critcl::app::Usage {args} { + global argv0 + if {[llength $args]} { + ::critcl::print stderr "$argv0 error: [join $args]" + } + + ::critcl::print stderr [string map [list @ $argv0] {To compile and run a tcl script + @ [-force] [-keep] [-cache dir] file[.tcl] + +To compile and build a package + @ options -pkg ?name? [files...] + +To repackage for TEA + @ options -tea ?name? [files...] + +Options include: + -debug [symbols|memory|all] enable debugging + -force force compilation of C files + -show show the configuration options being used + -target target generate binary for specified target platform/architecture + +Other options that may be useful: + -I dir adds dir to the include search path when compiling. + -L dir adds dir to the library search path when linking. + -cache dir sets the Critcl cache directory to dir. + -keep keep intermediate C files in the Critcl cache + -config file read the Critcl configuration options from file + -libdir dir location of generated library/package + -includedir dir location of generated package headers (stubs) + -showall show configuration for all supported platforms + -targets show all available target platforms + +You can display the built-in help wiki on most platforms using: + @ -help }] + exit 1 + return +} + +proc ::critcl::app::Help {} { + if {[catch {package require Mk4tcl} msg] || + [catch {package require Wikit} msg]} { + ::critcl::print $msg + set txt "Couldn't load the Critcl help Wiki\n" + append txt "To display the Critcl help wiki run \"critcl\" " + append txt "without any options.\n" + ::critcl::print $txt + exit + } else { + Wikit::init [file join $::starkit::topdir doc critcl.tkd] + } +} + +proc ::critcl::app::Selftest {} { + foreach t [glob -directory [file join $starkit::topdir test] *.tst] { + source $t + } + return +} + +proc ::critcl::app::ProcessInput {} { + # Main loop. This processes the input files, one by one. + + set v::debug [lsort -unique $v::debug] + + # NOTE that this effectively executes them (source!) in the + # context of this application. The files are trusted to not + # contain malicious side-effects, etc. + + # Initialize the accumulator variables for various per-file + # information which will be needed later when building the + # over-arching initialization code. + + set v::clibraries {} ;# External libraries used. To link the final shlib against. + set v::ldflags {} ;# Linker flags. + set v::objects {} ;# The object files to link. + set v::edecls {} ;# Initialization function decls for the pieces. + set v::initnames {} ;# Initialization function calls for the pieces. + set v::tsources {} ;# Tcl companion sources. + set v::mintcl 8.4 ;# Minimum version of Tcl required to run the package. + set v::tk 0 ;# Boolean flag. Set if any sub-package needs Tk, forcing it on the collection as well. + set v::preload {} ;# List of libraries declared for preload. + set v::license {} ;# Accumulated licenses, if any. + set v::failed 0 ;# Number of build failures encountered. + set v::borken {} ;# List of files which failed to build. + set v::log {} ;# List of log messages for the failed files + set v::headers {} ;# List of header directories (in the result cache) + # to export. + set v::pkgs {} ;# List of package names for the pieces. + set v::inits {} ;# Init function names for the pieces, list. + set v::meta {} ;# All meta data declared by the input files. + + # Other loop status information. + + set first 1 ;# Flag, reset after first round, helps with output formatting. + set missing 0 + + if {$v::mode eq "tea"} { + LogLn "Config: TEA Generation" + Log "Source: " + + # Initialize the accumulator variables for various per-file + # information. + + set v::org {} ; # Organization the package is licensed by. + set v::ver {} ; # Version of the package. + set v::cfiles {} ; # Companion files (.tcl, .c, .h, etc). + set v::teasrc {} ; # Input file(s) transformed for use in the Makefile.in. + set v::imported {} ; # List of stubs APIs imported from elsewhere. + set v::config {} ; # List of user-specified configuration settings. + + } elseif {[llength $v::src]} { + LogLn "Config: [::critcl::targetconfig]" + LogLn "Build: [::critcl::buildplatform]" + + set t [::critcl::targetplatform] + if {$v::actualplatform ne $t} { + LogLn "Target: $v::actualplatform (by $t)" + } else { + LogLn "Target: $v::actualplatform" + } + Log "Source: " + } + + foreach f $v::src { + # Avoid reloading itself. + if {[file rootname [file tail $f]] eq "critcl"} continue + + if {$v::mode eq "tea"} { + lappend v::teasrc "\${srcdir}/src/[file tail $f]" + } + + # Canonicalize input argument, and search in a few places. + set fn [file normalize $f] + + set found [file exists $fn] + if {!$found} { + if {[file extension $fn] ne ".tcl"} { + append fn .tcl + set found [file exists $fn] + } + if {!$found} { + if {!$first} { ::critcl::print stderr "" } + ::critcl::print stderr "$f doesn't exist" + incr missing + continue + } + } + + set first 0 + LogLn "[file tail $fn]" + set dir [file dirname $fn] + + if {$v::mode eq "tea"} { + # In TEA mode we are not building anything at all. We only + # wish to know and scan for the declarations of companion + # files, so that we know what to put these into the TEA + # directory hierarchy. This also provides us with the + # version number to use. + + LogLn "" + array set r [critcl::scan $fn] + lappend v::cfiles $f $r(files) + if {$r(org) ne {}} { + lappend v::org $r(org) + } + if {$r(version) ne {}} { + lappend v::ver $r(version) + } + if {$r(imported) ne {}} { + critcl::lappendlist v::imported $r(imported) + } + if {$r(config) ne {}} { + critcl::lappendlist v::config $r(config) + } + if {$r(meta) ne {}} { + lappend v::meta $r(meta) + } + continue + } + + # Execute the input file and collect all the crit(i)c(a)l :) + # information. Depending on the use of 'critcl::failed' this + # may or may not have generated the internal object file. + + if {$v::mode eq "pkg"} { + critcl::buildforpackage + } + + if {[llength $v::debug]} { + # As the debug settings are stored per file we now take + # the information from the application's commandline and + # force things here, faking the proper path information. + + set save [info script] + info script $fn + eval [linsert $v::debug 0 critcl::debug] + info script $save + } + + #puts ||$v::uc|| + if {[llength $v::uc]} { + # As the user-config settings are stored per file we now + # take the information from the application's commandline + # and force things here, faking the proper path information. + # Full checking of the data happens only if the setting is + # actually used by the file. + + set save [info script] + info script $fn + + foreach {k v} $v::uc { + #puts UC($k)=|$v| + critcl::userconfig set $k $v + } + info script $save + } + + # Ensure that critcl's namespace introspection is done + # correctly, and not thinking that 'critcl::app' is the + # namespace to use for the user's commands. + + uplevel #0 [list source $fn] + + if {[critcl::cnothingtodo $fn]} { + ::critcl::print stderr "nothing to build for $f" + continue + } + + # Force build. Our 'buildforpackage' call above disabled + # 'critcl::failed' and 'critcl::load' (Causing them to return + # OK, and bypassing anything conditional on their failure). If + # there is a failure we want to know it correctly, here. + # + # Regardless, we have to force (and later restore) the proper + # script location, something the 'source' comand above did + # automatically. + + set save [info script] + info script $fn + set failed [critcl::cbuild $fn 0] + incr v::failed $failed + info script $save + + # We can skip the part where we collect the build results for + # use by the overarching code if either no overall shlib is + # generated from the input, or any of the builds made so far + # failed. + + # NOTE that we were NOT skipping the build step for any of the + # packages, even if previous packages failed. We want the + # maximum information about problems from a single run, not + # fix things one by one. + + set results [critcl::cresults $fn] + if {$failed} { + lappend v::borken $f + lappend v::log [dict get $results log] + Log "(FAILED) " + } elseif {[dict exists $results warnings]} { + # There might be warnings to print even if the build did + # not fail. + set warnings [dict get $results warnings] + if {[llength $warnings]} { + ::critcl::print stderr "\n\nWarning [join $warnings "\nWarning "]" + } + } + if {$v::failed || ($v::mode ne "pkg")} continue + + array set r $results + + append v::edecls "extern Tcl_AppInitProc $r(initname)_Init;\n" + append v::initnames " if ($r(initname)_Init(interp) != TCL_OK) return TCL_ERROR;\n" + append v::license [License $f $r(license)] + + lappend v::pkgs $r(pkgname) + lappend v::inits $r(initname) + lappend v::meta $r(meta) + + # The overall minimum version of Tcl required by the combined + # packages is the maximum over all of their minima. + set v::mintcl [Vmax $v::mintcl $r(mintcl)] + set v::tk [Max $v::tk $r(tk)] + critcl::lappendlist v::objects $r(objects) + critcl::lappendlist v::tsources $r(tsources) + critcl::lappendlist v::clibraries $r(clibraries) + critcl::lappendlist v::ldflags $r(ldflags) + critcl::lappendlist v::preload $r(preload) + + if {[info exists r(apiheader)]} { + critcl::lappendlist v::headers $r(apiheader) + } + } + + if {$missing} { + critcl::error "Missing files: $missing, aborting" + } + + # Reduce package and init function to the first pieces. Easier to + # do it this way than having a conditional set in the loop. + + set v::pkgs [lindex $v::pkgs 0] + set v::inits [lindex $v::inits 0] + # Strip the prefix used by the foundation package. Keep in sync. + regsub {^ns_} $v::inits {} v::inits + + return +} + +proc ::critcl::app::Vmax {a b} { + if {[package vcompare $a $b] >= 0} { + return $a + } else { + return $b + } +} + +proc ::critcl::app::Max {a b} { + if {$a >= $b} { + return $a + } else { + return $b + } +} + +proc ::critcl::app::License {file text} { + if {$text eq "<>"} { return {} } + return "\n\[\[ [file tail $file] \]\] __________________\n$text" +} + +proc ::critcl::app::BuildBracket {} { + ::critcl::print "\nLibrary: [file tail $v::shlname]" + + # The overarching initialization code, the bracket, has no real + # file behind it. Fake it based on the destination shlib, this + # ensures that the generated _Init function has the proper name + # without having to redefine things through C macros, as was done + # before. + info script $v::shlname + + critcl::config combine "" + + # Inject the information collected from the input files, making + # them part of the final result. + critcl::tcl $v::mintcl + if {$v::tk} { critcl::tk } + + set lib critcl::cobjects + critcl::lappendlist lib $v::objects + eval $lib + + set lib critcl::clibraries + critcl::lappendlist lib $v::clibraries + eval $lib + + eval [linsert [lsort -unique $v::ldflags] 0 critcl::ldflags] + eval [linsert [lsort -unique $v::preload] 0 critcl::preload] + + critcl::cinit $v::initnames $v::edecls + + # And build everything. + critcl::buildforpackage 0 + set failed [critcl::cbuild "" 0] + + incr v::failed $failed + if {$failed} { + lappend v::borken <> + Log "(FAILED) " + } + return +} + +proc ::critcl::app::PlaceShlib {} { + # Copy the generated shlib from the cache to its final resting + # place. For -pkg this was set be inside the directory hierarchy + # of the newly-minted package. To prevent hassle a previously + # existing file gets deleted. + + if {[file exists $v::shlname]} { + file delete -force $v::shlname + } + + # NOTE that the fake 'info script location' set by 'BuildBracket' + # is still in effect, making access to the build results easy. + set shlib [dict get [critcl::cresults] shlib] + file copy $shlib $v::shlname + + # For MSVC debug builds we get a separate debug info file. + set pdb [file root $shlib].pdb + if {[file exists $pdb]} { + file copy -force $pdb [file root $v::shlname].pdb + } + + # Record shlib in the meta data, list of package files. + set d [file tail [file dirname $v::shlname]] + set f [file tail $v::shlname] + lappend v::meta [list included [file join $d $f]] + return +} + +proc ::critcl::app::ExportHeaders {} { + set incdir [CreateIncludeDirectory] + + foreach dir $v::headers { + set stem [file tail $dir] + set dst [file join $incdir $stem] + + ::critcl::print "Headers Placed Into: $v::incdir/$stem" + + file mkdir $dst + foreach f [glob -nocomplain -directory $dir *] { + file copy -force $f $dst + } + } + return +} + +proc ::critcl::app::AssemblePackage {} { + # Validate and/or create the main destination directory L. The + # package will become a subdirectory of L. See (x). And a platform + # specific directory inside of that will hold the shared + # library. This allows us to later merge the packages for + # different platforms into a single multi-platform package. + + if {![llength $v::pkgs]} { + ::critcl::print stderr "ERROR: `package provide` missing in package sources" + exit 1 + } + + set libdir [CreateLibDirectory] + + set libname [file tail $v::outname] + set pkgdir [file join $libdir $libname] + set shlibdir [file join $pkgdir $v::actualplatform] + + # XXX fileutil::stripPwd ... + if {[string first [pwd] $pkgdir] != -1} { + set first [string length [pwd]] + set dir [string range $pkgdir [incr first] end] + } else { + set dir $pkgdir + } + ::critcl::print "\nPackage Placed Into: $dir" + + file mkdir $pkgdir + file mkdir $shlibdir + + set shl [file tail $v::shlname] + + CreatePackageIndex $shlibdir [file rootname $shl] \ + [PlaceTclCompanionFiles $pkgdir] + CreateLicenseTerms $pkgdir + CreateRuntimeSupport $pkgdir + + # Place the shlib generated by BuildBracket into its final resting + # place, in the directory hierarchy of the just-assembled package. + + set v::shlname [file join $shlibdir $shl] + PlaceShlib + + # At last we can generate and write the meta data. Many of the + # commands before added application-level information (like + # included files, entrytclcommand, ...) to the information + # collected from the input files + + CreateTeapotMetadata $pkgdir + ExportHeaders + return +} + +proc ::critcl::app::CreatePackageIndex {shlibdir libname tsources} { + # Build pkgIndex.tcl + + set version [package present $v::pkgs] + + # (=) The 'package present' works because (a) 'ProcessInput' + # sources the package files in its own context, this process, and + # (b) the package files (are expected to) contain the proper + # 'package provide' commands (for compile & run mode), and we + # expect that at least one of the input files specifies the + # overall package built from all the inputs. See also (%) in + # Cmdline, where the application determines shlib name and package + # name, often from the first input file, and/or working backwards + # from package name to input file. + + set index [open [file join [file dirname $shlibdir] pkgIndex.tcl] w] + puts $index [PackageGuard $v::mintcl] + puts $index [IndexCommand $version $libname $tsources $shlibdir] + close $index + return +} + +proc ::critcl::app::Mapping {} { + # Create the platform mapping for each of the platforms listed on + # the Config platform line + + set map [critcl::getconfigvalue platform] + set minver [lindex $map 1] + + set plats [list] + foreach plat [lrange $map 2 end] { + set mapping($plat) [list [critcl::actualtarget] $minver] + lappend plats $plat + } + + if {[llength $plats]} { + ::critcl::print "Platform: [join $plats {, }] $minver and later" + } + + set map {} + foreach plat [lsort [array names mapping]] { + lappend map $plat $mapping($plat) + } + return $map +} + +proc ::critcl::app::Preload {shlibdir} { + if {![llength $v::preload]} { return {} } + + # Locate the external libraries declared for preloading and put + # them into the package. Put the shared library of the internal + # preload support pseudo-package into it as well. This will all be + # picked up by the 'package ifneeded' script. + + # First handle the declared libraries. Any problem there throws an + # error, or aborts. + + set preload {} + foreach shlib $v::preload { + file copy -force [PreloadLocation $shlib] $shlibdir + lappend preload [file tail $shlib] + } + + # Everything was ok, now place the supporting shlib into the + # package as well. + + file copy -force \ + [file join [critcl::cache] preload[critcl::sharedlibext]] \ + $shlibdir + + ::critcl::print "Preload: [join $preload {, }]" + return $preload +} + +proc ::critcl::app::PreloadLocation {shlib} { + set searchpath [PreloadSearchPath $shlib] + + foreach path $searchpath { + if {![file exists $path]} continue + return $path + } + + set msg "can't find preload library $shlib" + append msg " for target platform \"$v::actualplatform\";" + append msg " searched for " + append msg [linsert [join $searchpath {, }] end-1 and] + critcl::error $msg + return +} + +proc ::critcl::app::PreloadSearchPath {shlib} { + + # Look for lib FOO as follows: + # (1) FOO.so + # (2) FOO/FOO.so + # (3) FOO//FOO.so + # + # Look for lib BAR/FOO as follows: + # (1) FOO.so + # + # Then, if BAR/FOO doesn't exist as directory: + # (2) BAR/FOO.so + # (3) BAR//FOO.so + # + # Conversely, if BAR/FOO does exist as directory: + # (2) BAR/FOO/FOO.so + # (3) BAR/FOO//FOO.so + + # - lib.so + # - dir/lib.so + # - dir/plat/lib.so + + set tail [file tail $shlib] + + if {[file isdirectory $shlib]} { + set dir $shlib + } else { + set dir [file dirname $shlib] + if {$dir eq "."} { + set dir $tail + } + } + + set ext [critcl::sharedlibext] + return [list \ + $tail$ext \ + [file join $dir $tail$ext] \ + [file join $dir $v::actualplatform $tail$ext]] +} + +proc ::critcl::app::PackageGuard {v} { + return [string map [list @ $v] \ + {if {![package vsatisfies [package provide Tcl] @]} {return}}] +} + +proc ::critcl::app::IndexCommand {version libname tsources shlibdir} { + # We precompute as much as possible instead of wholesale defering + # to the runtime and dynamic code. See ticket (38bf01b26e). That + # makes it easier to debug the index command, as it is immediately + # visible in the pkgIndex.tcl file. And supports placement into + # the meta data. + + set loadcmd [LoadCommand $version $libname $tsources $shlibdir] + return "package ifneeded [list $v::pkgs $version] $loadcmd" +} + +proc ::critcl::app::LoadCommand {version libname tsources shlibdir} { + # New style. Precompute as much as possible. + + set map [Mapping] + if {$map ne {}} { set map " [list $map]" } + set platform "\[::critcl::runtime::MapPlatform$map\]" + + set loadcmd {} + lappend loadcmd {source [file join $dir critcl-rt.tcl]} + lappend loadcmd "set path \[file join \$dir $platform\]" + lappend loadcmd "set ext \[info sharedlibextension\]" + lappend loadcmd "set lib \[file join \$path \"$libname\$ext\"\]" + + foreach p [Preload $shlibdir] { + lappend loadcmd "::critcl::runtime::preFetch \$path \$ext [list $p]" + } + + lappend loadcmd "load \$lib [list $v::inits]" + + foreach t $tsources { + lappend loadcmd "::critcl::runtime::Fetch \$dir [list $t]" + } + + lappend loadcmd [list package provide $v::pkgs $version] + + # Wrap the load command for use by the index command. + # First make it a proper script, indented, i.e. proc body. + + set loadcmd "\n [join $loadcmd "\n "]" + + if {[package vsatisfies $v::mintcl 8.5]} { + # 8.5+: Put the load command into an ::apply, i.e. make it + # an anonymous procedure. + + set loadcmd "\[list ::apply \{dir \{$loadcmd\n\}\} \$dir\]" + } else { + # 8.4: Use a named, transient procedure. Name is chosen + # for low probability of collision with anything else. + # NOTE: We have to catch the auto-delete command because + # the procedure may have been redefined and destroyed by + # recursive calls to 'package require' of more critcl-based + # packages. + set n __critcl_load__ + append loadcmd "\n catch \{rename $n {}\}";# auto delete + set loadcmd "\"\[list proc $n \{dir\} \{[string map [list \n { ; }] $loadcmd]\}\] ; \[list $n \$dir\]\"" + } + + lappend v::meta [list entrytclcommand [list "eval $loadcmd"]] + + return $loadcmd +} + +proc ::critcl::app::IndexCommandXXXXX {version libname tsources shlibdir} { + # Old style critcl. Ifneeded and loading is entirely and + # dynamically handled in the runtime support code. + + set map [Mapping] + set preload [Preload $shlibdir] + set arguments [list $v::pkgs $version $libname $v::inits $tsources $map] + return "source \[file join \$dir critcl-rt.tcl\]\n::critcl::runtime::loadlib \$dir $arguments $preload" +} + +proc ::critcl::app::CreateLicenseTerms {pkgdir} { + # Create a license.terms file. + + if {$v::license eq ""} { + set v::license <> + } else { + set v::license [string trimleft $v::license] + } + set license [open [file join $pkgdir license.terms] w] + puts $license $v::license + close $license + return +} + +proc ::critcl::app::CreateTeapotMetadata {pkgdir} { + if {![llength $v::meta]} { + critcl::error "Meta data missing" + return + } + + # Merge the data from all input files, creating a list of words + # per key. Note: Data from later input files does not replace + # previous words, they get added instead. + + set umd {} + foreach md $v::meta { + foreach {k vlist} $md { + foreach v $vlist { + dict lappend umd $k $v + } + } + } + + # Check the identifying keys, i.e. package name, version, and + # platform for existence. + + foreach k {name version platform} { + if {![dict exists $umd $k]} { + critcl::error "Package $k missing in meta data" + } + } + + + # Collapse the data of various keys which must have only one, + # unique, element. + + foreach k {name version platform build::date generated::date} { + if {![dict exists $umd $k]} continue + dict set umd $k [lindex [dict get $umd $k] 0] + } + + # Add the entity information, and format the data for writing, + # using the "external" format for TEApot meta data. This writer + # limits lines to 72 characters, roughly. Beyond that nothing is + # done to make the output look pretty. + + set md {} + lappend md "Package [dict get $umd name] [dict get $umd version]" + dict unset umd name + dict unset umd version + + dict for {k vlist} $umd { + set init 1 + foreach v $vlist { + if {$init} { + # The first element of the value list is always added, + # regardless of length, to avoid infinite looping + # without progress. + set line {} + lappend line Meta $k $v + set init 0 + continue + } + if {[string length [linsert $line end $v]] > 72} { + # If the next element brings us beyond the limit we + # flush the current state and re-initialize. + lappend md $line + set line {} + lappend line Meta $k $v + set init 0 + continue + } + # Add the current element, extending the line. + lappend line $v + } + + # Flush the last line. + lappend md $line + } + + # Last step, write the formatted meta data to the associated file. + + set teapot [open [file join $pkgdir teapot.txt] w] + puts $teapot [join $md \n] + close $teapot + return +} + +proc ::critcl::app::PlaceTclCompanionFiles {pkgdir} { + # Arrange for the companion Tcl source files (as specified by + # critcl::tsources) to be copied into the Tcl subdirectory (in + # accordance with TIP 55) + + if {![llength $v::tsources]} { return {} } + + set tcldir [file join $pkgdir tcl] + file mkdir $tcldir + set files {} + set id 0 + foreach t $v::tsources { + set dst [file tail $t] + set dst [file rootname $dst]_[incr id][file extension $dst] + + file copy -force $t $tcldir/$dst + lappend files $dst + + # Metadata management + lappend v::meta [list included tcl/$dst] + } + return $files +} + +proc ::critcl::app::CreateRuntimeSupport {pkgdir} { + # Create the critcl-rt.tcl file in the generated package. This + # provides the code which dynamically assembles at runtime the + # package loading code, i.e. the 'package ifneeded' command + # expected by Tcl package management. + + variable mydir + set runtime [file join $mydir runtime.tcl] + + if {![file exists $runtime]} { + critcl::error "can't find Critcl's package runtime support file \"runtime.tcl\"" + } + + set fd [open $runtime] + set txt [read $fd] + close $fd + + append txt [DummyCritclPackage] + append txt [PlatformGeneric] + + set fd [open [file join $pkgdir critcl-rt.tcl] w] + puts $fd $txt + close $fd + + lappend v::meta [list included critcl-rt.tcl] + return +} + +proc ::critcl::app::DummyCritclPackage {} { + # This command provides conditional no-ops for any of the critcl + # procedures exported by the regular package, so that a .tcl file + # with embedded C can also be its own companion file declaring Tcl + # procedures etc. These dummy procedures are defined if and only + # if their regular counterpart is not present. + + # Note: We are generating code checking each and every relevant + # command individually to avoid trouble with different versions of + # critcl which may export a differing set of procedures. This way + # we will not miss anything just because we assumed that the + # presence of critcl::FOO also implies having critcl::BAR, or not. + + # Append dummy Critcl procs + # XXX This should be made conditional on the .tcl actually using itself as companion. + append txt "\n\# Dummy implementation of the critcl package, if not present\n" + + foreach name [lsort [namespace eval ::critcl {namespace export}]] { + switch $name { + compiled { set result 1 } + compiling { set result 0 } + done { set result 1 } + check { set result 0 } + failed { set result 0 } + load { set result 1 } + Ignore { append txt [DummyCritclCommand $name { + namespace eval ::critcl::v {} + set ::critcl::v::ignore([file normalize [lindex $args 0]]) . + }] + continue + } + default { + append txt [DummyCritclCommand $name {}] + continue + } + } + append txt [DummyCritclCommand $name "return $result"] + } + + return $txt +} + +proc ::critcl::app::DummyCritclCommand {name result} { + append txt "if \{!\[llength \[info commands ::critcl::$name\]\]\} \{\n" + append txt " namespace eval ::critcl \{\}\n" + append txt " proc ::critcl::$name \{args\} \{$result\}\n" + append txt "\}\n" + return $txt +} + +proc ::critcl::app::PlatformGeneric {} { + # Return a clone of the platform::generic command, from the + # currently loaded platform package. The generated package cannot + # assume that the deployment environment contains this package. To + # avoid trouble if the DP has the package the definition is made + # conditional, i.e. the clone is skipped if the command is already + # present. + + set body [info body ::platform::generic] + + append txt "\n# Define a clone of platform::generic, if needed\n" + append txt "if \{!\[llength \[info commands ::platform::generic\]\]\} \{\n" + append txt " namespace eval ::platform \{\}\n" + append txt " proc ::platform::generic \{\} \{" + append txt [join [split $body \n] "\n "] + append txt "\}\n" + append txt "\}\n\n" + + return $txt +} + +proc ::critcl::app::AssembleTEA {} { + LogLn {Assembling TEA hierarchy...} + + set libdir [CreateLibDirectory] + set libname [file rootname [file tail $v::outname]] + set pkgdir [file join $libdir $libname] + + LogLn "\tPackage: $pkgdir" + + file mkdir $pkgdir + + # Get a proper version number + set ver 0.0 + if {[llength $v::ver]} { + set ver [lindex $v::ver 0] + } + # Get a proper organization this is licensed by + set org Unknown + if {[llength $v::org]} { + set org [lindex $v::org 0] + } + + PlaceTEASupport $pkgdir $libname $ver $org + PlaceCritclSupport $pkgdir + PlaceInputFiles $pkgdir + + # Last, meta data for the TEA setup. + CreateTeapotMetadata $pkgdir + return +} + +proc ::critcl::app::CreateLibDirectory {} { + set libdir [file normalize $v::libdir] + if {[file isfile $libdir]} { + critcl::error "can't package $v::shlname - $libdir is not a directory" + } elseif {![file isdirectory $libdir]} { + file mkdir $libdir + } + + return $libdir +} + +proc ::critcl::app::CreateIncludeDirectory {} { + set incdir [file normalize $v::incdir] + if {[file isfile $incdir]} { + ::critcl::error "can't package $v::shlname headers - $incdir is not a directory" + } elseif {![file isdirectory $incdir]} { + file mkdir $incdir + } + + return $incdir +} + +proc ::critcl::app::PlaceTEASupport {pkgdir pkgname pversion porg} { + # Create the configure.in file in the generated TEA + # hierarchy. + + LogLn "\tPlacing TEA support..." + + foreach {pmajor pminor} [split $pversion .] break + if {$pminor eq {}} { set pminor 0 } + if {$pmajor eq {}} { set pmajor 0 } + + variable mydir + set tea [file join $mydir tea] + + if {![file exists $tea]} { + critcl::error "can't find Critcl's TEA support files" + } + + # Copy the raw support files over. + foreach f [glob -directory $tea *] { + file copy $f $pkgdir + + if {[file tail $f] eq "tclconfig"} { + foreach f [glob -directory $tea/tclconfig *] { + lappend v::meta [list included tclconfig/[file tail $f]] + } + } else { + lappend v::meta [list included [file tail $f]] + } + } + + # Basic map for the placeholders in the templates + + set now [clock seconds] + set year [clock format $now -format {%Y}] + set now [clock format $now] + set map [list \ + @@CRITCL@@ "\"$::argv0 $::argv\"" \ + @@PNAME@@ $pkgname \ + @@PMAJORV@@ $pmajor \ + @@PMINORV@@ $pminor \ + @@PFILES@@ "\\\n\t[join $v::teasrc " \\\n\t"]" \ + @@PORG@@ $porg \ + @@YEAR@@ $year \ + @@NOW@@ $now] + set cmap $map + set mmap $map + + # Extend map with stubs API data + + if {![llength $v::imported]} { + lappend cmap @@API@@ {} + lappend mmap @@API@@ {} @@APIUSE@@ {} + } else { + set macros {} + # Creating the --with-foo-include options for imported APIs. + + lappend macros "#-----------------------------------------------------------------------" + lappend macros "## TEA stubs header setup" + lappend macros "" + foreach api $v::imported { + set capi [string map {:: _} $api] + + lappend macros "CRITCL_TEA_PUBLIC_PACKAGE_HEADERS(\[$capi\])" + lappend mvardef "CRITCL_API_${capi}_INCLUDE = @CRITCL_API_${capi}_INCLUDE@" + lappend mvaruse "-I \$(CRITCL_API_${capi}_INCLUDE)" + } + lappend cmap @@API@@ \n[join $macros \n]\n + lappend mmap @@API@@ \n[join $mvardef \n]\n + lappend mmap @@APIUSE@@ " \\\n\t\t[join $mvaruse " \\\n\t\t"]" + } + + # Extend map with custom user configuration data. + + if {![llength $v::config]} { + lappend cmap @@UCONFIG@@ {} + lappend mmap @@UCONFIG@@ {} @@UCONFIGUSE@@ {} + } else { + + # Note: While we could assume that the user-specified + # configuration options of a single file are consistent with + # each other here we have a union of options from multiple + # files. No such assumption can be made. Thus, we unique the + # list, and then check that each option name left has a unique + # definition as well. + + set ok 1 + array set udef {} + set uclist [lsort -unique $v::config] + foreach uc $uclist { + set oname [lindex $uc 0] + if {[info exists udef($oname)]} { + LogLn "\t Inconsistent definition for $oname" + LogLn "\t (1) $uc" + LogLn "\t (2) $udef($oname)" + set ok 0 + continue + } + set udef($oname) $uc + } + if {!$ok} { + ::critcl::error "Conflicting user-specified configuration settings." + } + + # Creating the --(with,enable,disable)-foo options for + # user-specified configuration options. + + lappend macros "#-----------------------------------------------------------------------" + lappend macros "## TEA user option setup" + lappend macros "" + foreach uc $uclist { + lassign $uc oname odesc otype odefault + + if {$otype eq "bool"} { + set odefault [expr {$odefault ? "yes" : "no"}] + if {$odesc eq {}} { + set odesc "--enable-$oname" + } + append odesc " (default: $odefault)" + + lappend macros "CRITCL_TEA_BOOL_CONFIG(\[$oname\],\n\t\[$odefault\],\n\t\[$odesc\])" + } else { + if {$odesc eq {}} { + set odesc "--with-$oname" + } + append odesc " (default: $odefault, of [join $otype {, }])" + + lappend macros "CRITCL_TEA_WITH_CONFIG(\[$oname\],\n\t\[[join $otype { }]\],\n\t\[$odefault\],\n\t\[$odesc\])" + } + + lappend mvardef "CRITCL_UCONFIG_${oname} = @CRITCL_UCONFIG_${oname}@" + lappend mvaruse "\$(CRITCL_UCONFIG_${oname})" + } + lappend cmap @@UCONFIG@@ \n[join $macros \n]\n + lappend mmap @@UCONFIG@@ \n[join $mvardef \n]\n + lappend mmap @@UCONFIGUSE@@ " \\\n\t\t[join $mvaruse " \\\n\t\t"]" + } + + # Postprocess a few files (configure.in, Makefile.in). + + Map [file join $pkgdir configure.in] $cmap + Map [file join $pkgdir Makefile.in] $mmap + Map [file join $pkgdir Config.in] $map + + # At last locate a suitable autoconf (2.59+), and generate + # configure from the configure.in. + + set here [pwd] + cd $pkgdir + if {$::tcl_platform(platform) eq "windows"} { + # msys/mingw, cygwin, or other unix emulation on windows. + exec sh [LocateAutoconf 1] + } else { + exec [LocateAutoconf 0] + } + file delete -force autom4te.cache + + lappend v::meta [list included configure] + + cd $here + + return +} + +proc ::critcl::app::Map {path map} { + set fd [open $path r] + set txt [read $fd] + close $fd + + set txt [string map $map $txt] + + set fd [open $path w] + puts -nonewline $fd $txt + close $fd + + return +} + +proc ::critcl::app::PlaceCritclSupport {pkgdir} { + LogLn "\tPlacing Critcl support..." + + set c [file join $pkgdir critcl] + set l [file join $c lib] + file mkdir $l + + # Locate the critcl packages, and their forward compatibility + # support packages, and copy them into the TEA hierarchy for use + # by the generated Makefile. + foreach {pkg dir} { + critcl critcl + critcl::app app-critcl + critcl::util critcl-util + critcl::class critcl-class + critcl::iassoc critcl-iassoc + critcl::bitmap critcl-bitmap + critcl::cutil critcl-cutil + critcl::emap critcl-emap + critcl::enum critcl-enum + critcl::literals critcl-literals + critcl::platform critcl-platform + stubs::container stubs_container + stubs::gen stubs_genframe + stubs::gen::decl stubs_gen_decl + stubs::gen::lib stubs_gen_lib + stubs::gen::macro stubs_gen_macro + stubs::gen::slot stubs_gen_slot + stubs::gen::header stubs_gen_header + stubs::gen::init stubs_gen_init + stubs::reader stubs_reader + stubs::writer stubs_writer + } { + set cmd [package ifneeded $pkg [package require $pkg]] + set location [file dirname [lindex $cmd end]] + + # Squash any soft-links, which Tcl would copy as links. + set location [file dirname [file normalize $location/__]] + file copy $location $l/$dir + } + + # Generate a suitable main.tcl. Note that this main file sources + # the critcl packages directly, to ensure that the build uses the + # code put into the generated TEA hierarchy, and is not influenced + # by whatever is installed outside. + + set pfiles {} + lappend pfiles stubs_container/container stubs_reader/reader + lappend pfiles stubs_genframe/genframe stubs_gen_decl/gen_decl + lappend pfiles stubs_gen_macro/gen_macro stubs_gen_slot/gen_slot + lappend pfiles stubs_gen_header/gen_header stubs_gen_init/gen_init + lappend pfiles stubs_gen_lib/gen_lib stubs_writer/writer + lappend pfiles critcl/critcl app-critcl/critcl critcl-util/util + lappend pfiles critcl-class/class critcl-iassoc/iassoc + lappend pfiles critcl-bitmap/bitmap critcl-cutil/cutil + lappend pfiles critcl-literals/literals critcl-platform/platform + lappend pfiles critcl-emap/emap critcl-enum/enum + + set fd [open [file join $pkgdir critcl main.tcl] w] + puts $fd [join \ + [list \ + "# Required packages: cmdline, md5" \ + "# Optional: tcllibc, Trf, md5c, cryptkit (md5 acceleration)" \ + "# Enforce usage of the local critcl packages." \ + "foreach p \{\n\t[join $pfiles \n\t]\n\} \{" \ + { source [file dirname [info script]]/lib/$p.tcl} \ + "\}" \ + {critcl::app::main $argv}] \n] + close $fd + + # Add to set of included files. + lappend v::meta [list included critcl/main.tcl] + foreach p $pfiles { + lappend v::meta [list included critcl/lib/$p.tcl] + } + return +} + +proc ::critcl::app::PlaceInputFiles {pkgdir} { + LogLn "\tPlacing input files..." + + # Main critcl source file(s), plus companions + + foreach f $v::src { + #LogLn "\tB $f" + + set dst [file join src [file tail $f]] + lappend v::meta [list included $dst] + + set dst [file join $pkgdir $dst] + file mkdir [file dirname $dst] + file copy $f $dst + } + + foreach {f cf} $v::cfiles { + set base [file dirname $f] + foreach f [lsort -unique $cf] { + set fs [file join $base $f] + + #LogLn "\tC $fs" + + set dst [file join src $f] + lappend v::meta [list included $dst] + + set dst [file join $pkgdir $dst] + + file mkdir [file dirname $dst] + file copy $fs $dst + } + } + return +} + +proc ::critcl::app::LocateAutoconf {iswin} { + set ac [auto_execok autoconf] + + if {$ac eq {}} { + return -code error "autoconf 2.59 or higher required, not found" + } + + if {$iswin} { + # msys/mingw, cygwin, or other unix emulation on windows. + set cmd [linsert $ac 0 exec sh] + } else { + set cmd [linsert $ac 0 exec] + } + + set v [lindex [split [eval [linsert $cmd end --version]] \n] 0 end] + + if {![package vsatisfies $v 2.59]} { + return -code error "$ac $v is not 2.59 or higher, as required" + } + + return $ac +} + +# # ## ### ##### ######## ############# ##################### + +namespace eval ::critcl::app { + # Path of the application package directory. + variable myself [file normalize [info script]] + variable mydir [file dirname $myself] + + variable options { + I.arg L.arg cache.arg clean config.arg debug.arg force help + keep libdir.arg pkg show showall target.arg targets + test tea showtarget includedir.arg enable.arg disable.arg + v -version + } + + # Application state + namespace eval v { + # - -- --- ----- -------- ------------- --------------------- + # Data collected from the command line. + + variable verbose 0 ;# Level of chattering written during a run. + variable src {} ;# List of files to process. + + variable actualplatform {} ;# Target platform, with x-compile information resolved. + + variable shlname "" ;# Name of the shlib to generate (-pkg, -tea). + variable outname "" ;# Name of the shlib dir to use (-pkg, -tea). + variable libdir lib ;# Place for the package (-pkg, -tea). + variable incdir include ; # Directory to put the -pkg include files into (stubs export), + # and search in (stubs import) + variable keep 0 ;# Boolean flag. Default: Do not keep generated .c files. + variable debug {} ;# List of debug modes to activate. + variable cache {} ;# User specified path to the directory for the result cache. + variable uc {} ;# List. User specified configuration data. + + # Build mode. Default is to fill the result + # cache. Alternatives are building a package (-pkg), or + # assembling/repackaging for TEWA (-tea). + + variable mode cache ;# pkg, tea + + # - -- --- ----- -------- ------------- --------------------- + # Data accumulated while processing the input files. + + variable failed 0 ;# Number of build failures encountered. + variable clibraries {} ;# External libraries used. To link the final shlib against. + variable ldflags {} ;# Linker flags. + variable objects {} ;# The object files to link. + variable edecls {} ;# Initialization function decls for the pieces (C code block). + variable initnames {} ;# Initialization function calls for the pieces (C code block). + variable tsources {} ;# Tcl companion sources. + variable mintcl 8.4 ;# Minimum version of Tcl required to run the package. + variable preload {} ;# List of libraries declared for preload. + variable license {} ;# Accumulated licenses, if any. + variable pkgs {} ;# List of package names for the pieces. + variable inits {} ;# Init function names for the pieces, list. + variable meta {} ;# All meta data declared by the input files. + + # critcl::scan results + variable org {} ;# Organization package is licensed by + variable ver {} ;# Version of the package. + variable cfiles {} ;# Companion files (.tcl, .c, .h, etc). + variable teasrc {} ;# Input file(s) transformed for use in the Makefile.in. + variable imported {} ;# List of stubs APIs imported from elsewhere. + variable config {} ;# List of user-specified configuration settings. + # variable meta ;# See above. + } +} + +# # ## ### ##### ######## ############# ##################### +return diff --git a/src/vfs/critcl.vfs/lib/app-critcl/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/app-critcl/pkgIndex.tcl new file mode 100644 index 00000000..e45086a7 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::app 3.2.1 [list source [file join $dir critcl.tcl]] diff --git a/src/vfs/critcl.vfs/lib/app-critcl/runtime.tcl b/src/vfs/critcl.vfs/lib/app-critcl/runtime.tcl new file mode 100644 index 00000000..e6b95918 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/runtime.tcl @@ -0,0 +1,134 @@ +# +# Critcl - build C extensions on-the-fly +# +# Copyright (c) 2001-2007 Jean-Claude Wippler +# Copyright (c) 2002-2007 Steve Landers +# +# See http://wiki.tcl.tk/critcl +# +# This is the Critcl runtime that loads the appropriate +# shared library when a package is requested +# + +namespace eval ::critcl::runtime {} + +proc ::critcl::runtime::loadlib {dir package version libname initfun tsrc mapping args} { + # XXX At least parts of this can be done by the package generator, + # XXX like listing the Tcl files to source. The glob here allows + # XXX code-injection after-the-fact, by simply adding a .tcl in + # XXX the proper place. + set path [file join $dir [MapPlatform $mapping]] + set ext [info sharedlibextension] + set lib [file join $path $libname$ext] + set provide [list] + + # Now the runtime equivalent of a series of 'preFetch' commands. + if {[llength $args]} { + set preload [file join $path preload$ext] + foreach p $args { + set prelib [file join $path $p$ext] + if {[file readable $preload] && [file readable $prelib]} { + lappend provide [list load $preload];# XXX Move this out of the loop, do only once. + lappend provide [list ::critcl::runtime::preload $prelib] + } + } + } + + lappend provide [list load $lib $initfun] + foreach t $tsrc { + lappend loadcmd "::critcl::runtime::Fetch \$dir [list $t]" + } + lappend provide "package provide $package $version" + package ifneeded $package $version [join $provide "\n"] + return +} + +proc ::critcl::runtime::preFetch {path ext dll} { + set preload [file join $path preload$ext] + if {![file readable $preload]} return + + set prelib [file join $path $dll$ext] + if {![file readable $prelib]} return + + load $preload ; # Defines next command. + ::critcl::runtime::preload $prelib + return +} + +proc ::critcl::runtime::Fetch {dir t} { + # The 'Ignore' disables compile & run functionality. + + # Background: If the regular critcl package is already loaded, and + # this prebuilt package uses its defining .tcl file also as a + # 'tsources' then critcl might try to collect data and build it + # because of the calls to its API, despite the necessary binaries + # already being present, just not in the critcl cache. That is + # redundant in the best case, and fails in the worst case (no + # compiler), preventing the use o a perfectly fine package. The + # 'ignore' call now tells critcl that it should ignore any calls + # made to it by the sourced files, and thus avoids that trouble. + + # The other case, the regular critcl package getting loaded after + # this prebuilt package is irrelevant. At that point the tsources + # were already run, and used the dummy procedures defined in the + # critcl-rt.tcl, which ignore the calls by definition. + + set t [file join $dir tcl $t] + ::critcl::Ignore $t + uplevel #0 [list source $t] + return +} + +proc ::critcl::runtime::precopy {dll} { + # This command is only used on Windows when preloading out of a + # VFS that doesn't support direct loading (usually, a Starkit) + # - we preserve the dll name so that dependencies are satisfied + # - The critcl::runtime::preload command is defined in the supporting + # "preload" package, implemented in "critcl/lib/critcl/critcl_c/preload.c" + + global env + if {[info exists env(TEMP)]} { + set dir $env(TEMP) + } elseif {[info exists env(TMP)]} { + set dir $env(TMP) + } elseif {[file exists $env(HOME)]} { + set dir $env(HOME) + } else { + set dir . + } + set dir [file join $dir TCL[pid]] + set i 0 + while {[file exists $dir]} { + append dir [incr i] + } + set new [file join $dir [file tail $dll]] + file mkdir $dir + file copy $dll $new + return $new +} + +proc ::critcl::runtime::MapPlatform {{mapping {}}} { + # A sibling of critcl::platform that applies the platform mapping + + set platform [::platform::generic] + set version $::tcl_platform(osVersion) + if {[string match "macosx-*" $platform]} { + # "normalize" the osVersion to match OSX release numbers + set v [split $version .] + set v1 [lindex $v 0] + set v2 [lindex $v 1] + incr v1 -4 + set version 10.$v1.$v2 + } else { + # Strip trailing non-version info + regsub -- {-.*$} $version {} version + } + foreach {config map} $mapping { + if {![string match $config $platform]} continue + set minver [lindex $map 1] + if {[package vcompare $version $minver] < 0} continue + set platform [lindex $map 0] + break + } + return $platform +} diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/Config.in b/src/vfs/critcl.vfs/lib/app-critcl/tea/Config.in new file mode 100644 index 00000000..f71888e4 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/Config.in @@ -0,0 +1,188 @@ +## -*- tcl -*- Critcl configuration file +# # ## ### ##### ######## ############# ##################### +## For +# @@PNAME@@ @@PMAJORV@@.@@PMINORV@@ +# +# Copyright (c) @@YEAR@@ @@PORG@@ +# +# Generated by @@CRITCL@@ +# At @@NOW@@ + +# This specific file gets filled by the TEA configure(.in) with the +# compiler information it found when run, and the accompanying +# Makefile(.in) uses it to overide critcl's default configuration +# settings. In this way we manage to get a proper TEA setup of flags +# and such, bypassing all of critcl's own selection logic. critcl is +# essentially 'just' used as a custom compiler driver, whereas a +# standard TEA Makefile would have all the relevant commands listed +# explicitly in its rules. + +# # ## ### ##### ######## ############# ##################### +## First, keep the GCC specific defaults. + +compile gcc -c -fPIC +version gcc -v +link gcc -shared +include -I +preproc_define gcc -E -dM +preproc_enum gcc -E +tclstubs -DUSE_TCL_STUBS +tkstubs -DUSE_TK_STUBS +debug_memory -DTCL_MEM_DEBUG +debug_symbols -g +object .o +output -o [list $outfile] +ldoutput +link_debug +link_release +link_preload --unresolved-symbols=ignore-in-shared-libs +strip -Wl,-s +optimize -O2 +noassert -DNDEBUG +threadflags -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 \ + -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_READDIR_R=1 \ + -DTCL_THREADS=1 + + +# # ## ### ##### ######## ############# ##################### +## Second, define settings based on the system information found by +## configure(.in), converted into something usable by critcl. See the +## section below for the raw settings. + +TEA platform @CRITCL_PLATFORM@ +TEA compile @CRITCL_CC@ +TEA version @CRITCL_VERSION@ +TEA link @CRITCL_LINK@ +TEA preproc_define @CRITCL_CPP_DEFINE@ +TEA preproc_enum @CRITCL_CPP_ENUM@ +TEA debug_symbols @CFLAGS_DEBUG@ +TEA object .@OBJEXT@ +TEA output @CRITCL_CC_OUTPUT@ +TEA ldoutput @CRITCL_LD_OUTPUT@ +TEA link_debug @CRITCL_LD_DBG@ +TEA link_release @CRITCL_LD_REL@ +TEA link_preload --unresolved-symbols=ignore-in-shared-libs +TEA strip +TEA optimize @CFLAGS_OPTIMIZE@ + + +# # ## ### ##### ######## ############# ##################### +## Third, the exact raw settings generated by configure(.in), +## as found in build_dir/config.status. To help debugging the +## munging, when its wrong. +## +## The lines marked with ** are those which are of especially high +## interest. + +#** CC = (@CC@) +#** CFLAGS = (@CFLAGS@) +#** CFLAGS_DEBUG = (@CFLAGS_DEBUG@) +#** CFLAGS_OPTIMIZE = (@CFLAGS_OPTIMIZE@) +#** CFLAGS_WARNING = (@CFLAGS_WARNING@) +#** CPP = (@CPP@) +#** CPPFLAGS = (@CPPFLAGS@) +#** DEFS = (@DEFS@) +#** LDFLAGS = (@LDFLAGS@) +#** LDFLAGS_DEFAULT = (@LDFLAGS_DEFAULT@) +#** LIBS = (@LIBS@) +#** MAKE_LIB = (@MAKE_LIB@) +#** MAKE_SHARED_LIB = (@MAKE_SHARED_LIB@) +#** MAKE_STATIC_LIB = (@MAKE_STATIC_LIB@) +#** MAKE_STUB_LIB = (@MAKE_STUB_LIB@) +#** MATH_LIBS = (@MATH_LIBS@) +#** OBJEXT = (@OBJEXT@) +#** SHLIB_CFLAGS = (@SHLIB_CFLAGS@) +#** SHLIB_LD = (@SHLIB_LD@) +#** SHLIB_LD_LIBS = (@SHLIB_LD_LIBS@) +#** SHLIB_SUFFIX = (@SHLIB_SUFFIX@) +#** STLIB_LD = (@STLIB_LD@) +#** TCL_EXTRA_CFLAGS = (@TCL_EXTRA_CFLAGS@) +#** TCL_INCLUDES = (@TCL_INCLUDES@) +#** TCL_LD_FLAGS = (@TCL_LD_FLAGS@) +#** TCL_LIBS = (@TCL_LIBS@) +#** TCL_SHLIB_LD_LIBS = (@TCL_SHLIB_LD_LIBS@) +#** TCL_THREADS = (@TCL_THREADS@) + +# AR = (@AR@) +# CELIB_DIR = (@CELIB_DIR@) +# CFLAGS_DEFAULT = (@CFLAGS_DEFAULT@) +# CLEANFILES = (@CLEANFILES@) +# CYGPATH = (@CYGPATH@) +# ECHO_C = (@ECHO_C@) +# ECHO_N = (@ECHO_N@) +# ECHO_T = (@ECHO_T@) +# EGREP = (@EGREP@) +# EXEEXT = (@EXEEXT@) +# GREP = (@GREP@) +# INSTALL_DATA = (@INSTALL_DATA@) +# INSTALL_PROGRAM = (@INSTALL_PROGRAM@) +# INSTALL_SCRIPT = (@INSTALL_SCRIPT@) +# LD_LIBRARY_PATH_VAR = (@LD_LIBRARY_PATH_VAR@) +# LIBOBJS = (@LIBOBJS@) +# LTLIBOBJS = (@LTLIBOBJS@) +# PACKAGE_BUGREPORT = (@PACKAGE_BUGREPORT@) +# PACKAGE_NAME = (@PACKAGE_NAME@) +# PACKAGE_STRING = (@PACKAGE_STRING@) +# PACKAGE_TARNAME = (@PACKAGE_TARNAME@) +# PACKAGE_VERSION = (@PACKAGE_VERSION@) +# PATH_SEPARATOR = (@PATH_SEPARATOR@) +# PKG_CFLAGS = (@PKG_CFLAGS@) +# PKG_HEADERS = (@PKG_HEADERS@) +# PKG_INCLUDES = (@PKG_INCLUDES@) +# PKG_LIBS = (@PKG_LIBS@) +# PKG_LIB_FILE = (@PKG_LIB_FILE@) +# PKG_OBJECTS = (@PKG_OBJECTS@) +# PKG_SOURCES = (@PKG_SOURCES@) +# PKG_STUB_LIB_FILE = (@PKG_STUB_LIB_FILE@) +# PKG_STUB_OBJECTS = (@PKG_STUB_OBJECTS@) +# PKG_STUB_SOURCES = (@PKG_STUB_SOURCES@) +# PKG_TCL_SOURCES = (@PKG_TCL_SOURCES@) +# RANLIB = (@RANLIB@) +# RANLIB_STUB = (@RANLIB_STUB@) +# SET_MAKE = (@SET_MAKE@) +# SHARED_BUILD = (@SHARED_BUILD@) +# SHELL = (@SHELL@) +# TCLSH_PROG = (@TCLSH_PROG@) +# TCL_BIN_DIR = (@TCL_BIN_DIR@) +# TCL_DBGX = (@TCL_DBGX@) +# TCL_DEFS = (@TCL_DEFS@) +# TCL_LIB_FILE = (@TCL_LIB_FILE@) +# TCL_LIB_FLAG = (@TCL_LIB_FLAG@) +# TCL_LIB_SPEC = (@TCL_LIB_SPEC@) +# TCL_PATCH_LEVEL = (@TCL_PATCH_LEVEL@) +# TCL_SRC_DIR = (@TCL_SRC_DIR@) +# TCL_STUB_LIB_FILE = (@TCL_STUB_LIB_FILE@) +# TCL_STUB_LIB_FLAG = (@TCL_STUB_LIB_FLAG@) +# TCL_STUB_LIB_SPEC = (@TCL_STUB_LIB_SPEC@) +# TCL_VERSION = (@TCL_VERSION@) +# VC_MANIFEST_EMBED_DLL = (@VC_MANIFEST_EMBED_DLL@) +# VC_MANIFEST_EMBED_EXE = (@VC_MANIFEST_EMBED_EXE@) + +# ac_ct_CC = (@ac_ct_CC@) +# bindir = (@bindir@) +# build_alias = (@build_alias@) +# datadir = (@datadir@) +# datarootdir = (@datarootdir@) +# docdir = (@docdir@) +# dvidir = (@dvidir@) +# exec_prefix = (@exec_prefix@) +# host_alias = (@host_alias@) +# htmldir = (@htmldir@) +# includedir = (@includedir@) +# infodir = (@infodir@) +# libdir = (@libdir@) +# libexecdir = (@libexecdir@) +# localedir = (@localedir@) +# localstatedir = (@localstatedir@) +# mandir = (@mandir@) +# oldincludedir = (@oldincludedir@) +# pdfdir = (@pdfdir@) +# prefix = (@prefix@) +# program_transform_name = (@program_transform_name@) +# psdir = (@psdir@) +# sbindir = (@sbindir@) +# sharedstatedir = (@sharedstatedir@) +# sysconfdir = (@sysconfdir@) +# target_alias = (@target_alias@) + +# # ## ### ##### ######## ############# ##################### diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/Makefile.in b/src/vfs/critcl.vfs/lib/app-critcl/tea/Makefile.in new file mode 100644 index 00000000..3173aa50 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/Makefile.in @@ -0,0 +1,145 @@ +# Makefile.in -- +# +# This file is a Makefile for "@@PNAME@@ @@PMAJORV@@.@@PMINORV@@". If this +# is "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. +# +# Copyright (c) @@YEAR@@ @@PORG@@ +# +# Generated by @@CRITCL@@ +# At @@NOW@@ +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +#======================================================================== +# Nothing of the variables below this line need to be changed. Please +# check the TARGETS section below to make sure the make targets are +# correct. +#======================================================================== + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir = @libdir@ +mandir = @mandir@ +bindir = @bindir@ + +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedir = @sharedstatedir@ +statedir = @localstatedir@ +includedir = @includedir@ +oldincludedir = @oldincludedir@ + +DESTDIR = +pkglibdir = $(libdir)/@PACKAGE_NAME@@PACKAGE_VERSION@ +top_builddir = . + +PACKAGE = @PACKAGE_NAME@ +VERSION = @PACKAGE_VERSION@ +CYGPATH = @CYGPATH@ + +TCLSH_PROG = @TCLSH_PROG@ +CRITCL = `$(CYGPATH) $(srcdir)/critcl/main.tcl` + +CONFIG_CLEAN_FILES = +@@API@@ +@@UCONFIG@@ +#======================================================================== +# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with +# this package that need to be installed, if any. +#======================================================================== + +PKG_TCL_SOURCES = @@PFILES@@ + +#======================================================================== +# Start of user-definable TARGETS section +#======================================================================== + +all: + @echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + @echo Please run '"make install"' to build and install the package. + @echo Critcl has no separate build-step. + +doc: + @echo No documentation to build. + +install: + @echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; \ + cat $(top_builddir)/Config | grep -v '^#' ; \ + echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; \ + rm -rf $(top_builddir)/results-tea ; \ + $(TCLSH_PROG) $(CRITCL) \ + -I $(prefix)/include \ + -I $(exec_prefix)/include \ + -I $(includedir)@@APIUSE@@ \ + @@UCONFIGUSE@@ \ + -keep -cache $(top_builddir)/results-tea \ + -target TEA -config $(top_builddir)/Config \ + -libdir $(DESTDIR)$(libdir) \ + -includedir $(DESTDIR)$(includedir) \ + -pkg $(PACKAGE)$(VERSION) \ + $(PKG_TCL_SOURCES) ; \ + echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; \ + cat $(top_builddir)/results-tea/*.log + echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; \ + +install-auto: show-auto + @rm -rf $(top_builddir)/results-auto ; \ + $(TCLSH_PROG) $(CRITCL) \ + -I $(prefix)/include \ + -I $(exec_prefix)/include \ + -I $(includedir)@@APIUSE@@ \ + @@UCONFIGUSE@@ \ + -keep -cache $(top_builddir)/results-auto \ + -libdir $(DESTDIR)$(libdir) \ + -includedir $(DESTDIR)$(includedir) \ + -pkg $(PACKAGE)$(VERSION) \ + $(PKG_TCL_SOURCES) ; \ + echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; \ + cat $(top_builddir)/results-auto/*.log + echo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; \ + +install-doc: + @echo No documentation to install. + +show: + @$(TCLSH_PROG) $(CRITCL) \ + -keep -cache $(top_builddir)/results-tea \ + -target TEA -config $(top_builddir)/Config \ + -libdir $(DESTDIR)$(libdir) \ + -pkg -show + +show-auto: + @$(TCLSH_PROG) $(CRITCL) \ + -keep -cache $(top_builddir)/results-auto \ + -libdir $(DESTDIR)$(libdir) \ + -pkg -show + +clean: + rm -rf doc *-doc + +distclean: clean + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -rm -f config.status + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +.PHONY: all binaries clean depend distclean doc install installdirs libraries test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/aclocal.m4 b/src/vfs/critcl.vfs/lib/app-critcl/tea/aclocal.m4 new file mode 100644 index 00000000..e4db369f --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/aclocal.m4 @@ -0,0 +1,180 @@ +# +# Include the TEA standard macro set +# + +builtin(include,tclconfig/tcl.m4) + +# +# Add here whatever m4 macros you want to define for your package +# + +#------------------------------------------------------------------------ +# CRITCL_TEA_PUBLIC_PACKAGE_HEADERS -- +# +# Locate the installed public FOO header files +# +# Arguments: +# Name of the package to search headers for. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-[$1]-include switch to configure. +# Result is cached. +# +# Substs the following vars: +# CRITCL_API_$1_INCLUDE +#------------------------------------------------------------------------ + +AC_DEFUN([CRITCL_TEA_PUBLIC_PACKAGE_HEADERS],[ + # CRITCL_TEA_PUBLIC_PACKAGE_HEADERS: $1 + AC_MSG_CHECKING([for $1 public headers]) + AC_ARG_WITH([$1-include], [ --with-$1-include directory containing the public $1 header files], [with_$1_include=${withval}]) + AC_CACHE_VAL(ac_cv_c_$1_header, [ + # Use the value from --with-$1-include, if it was given + + if test x"[$]{with_$1_include}" != x ; then + if test -f "[$]{with_$1_include}/$1Decls.h" ; then + ac_cv_c_$1_header=[$]{with_$1_include} + else + AC_MSG_ERROR([[$]{with_$1_include} directory does not contain $1Decls.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If $1 was built as a framework, attempt to use + # the framework's Headers directory + case [$]{$1_DEFS} in + *$1_FRAMEWORK*) + list="`ls -d [$]{$1_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Check order: pkg --prefix location, Tcl's --prefix location, + # relative to directory of $1Config.sh. + + eval "temp_includedir=[$]{includedir}" + list="[$]list \ + `ls -d [$]{temp_includedir} 2>/dev/null` \ + `ls -d [$]{$1_PREFIX}/include 2>/dev/null` \ + `ls -d [$]{$1_BIN_DIR}/../include 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + + if test "[$]{TEA_PLATFORM}" != "windows" -o "[$]GCC" = "yes"; then + list="[$]list /usr/local/include /usr/include" + if test x"[$]{$1_INCLUDE_SPEC}" != x ; then + d=`echo "[$]{$1_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="[$]list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in [$]list ; do + if test -f "[$]i/$1/$1Decls.h" ; then + ac_cv_c_$1_header=[$]i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + if test x"[$]{ac_cv_c_$1_header}" = x ; then + AC_MSG_ERROR([$1Decls.h not found. Please specify its location with --with-$1-include]) + else + AC_MSG_RESULT([[$]{ac_cv_c_$1_header}]) + fi + + # Convert to a native path and substitute into the transfer variable. + # NOTE: Anything going into actual TEA would have to use A TEA_xx + # transfer variable, instead of critcl. + INCLUDE_DIR_NATIVE=`[$]{CYGPATH} [$]{ac_cv_c_$1_header}` + CRITCL_API_$1_INCLUDE="\"[$]{INCLUDE_DIR_NATIVE}\"" + AC_SUBST([CRITCL_API_$1_INCLUDE]) +]) + +#------------------------------------------------------------------------ +# CRITCL_TEA_WITH_CONFIG -- +# +# Declare a --with-FOO option, with default and legal values. +# +# Arguments: +# Name of the option. +# List of legal values. +# Default value. +# Option description. +# +# Requires: +# Results: +# Adds a --with-[$1] switch to configure. +# +# Substs the following vars: +# CRITCL_UCONFIG_$1 +#------------------------------------------------------------------------ + +AC_DEFUN([CRITCL_TEA_WITH_CONFIG],[ + # CRITCL_TEA_WITH_CONFIG: $1 + AC_ARG_WITH([$1], + AC_HELP_STRING([--with-$1], + [$4]), + [with_uc_$1=${withval}]) + + # Use default if user did not specify anything. + if test x"[$]{with_uc_$1}" = x ; then + with_uc_$1="$3" + fi + + AC_MSG_CHECKING([Validating $1]) + tcl_ok=no + for x in $2 + do + if test "[$]x" = "[$]with_uc_$1" ; then + tcl_ok=yes + break + fi + done + if test "[$]tcl_ok" = "no" ; then + AC_MSG_ERROR([Illegal value [$]with_uc_$1, expected one of: $2]) + else + AC_MSG_RESULT([[$]with_uc_$1]) + fi + + CRITCL_UCONFIG_$1="-with-$1 \"[$]with_uc_$1\"" + AC_SUBST([CRITCL_UCONFIG_$1]) +]) + +#------------------------------------------------------------------------ +# CRITCL_TEA_BOOL_CONFIG -- +# +# Declare a --disable/enable-FOO option, with default. +# +# Arguments: +# Name of the option. +# Default value. +# Option description. +# +# Requires: +# Results: +# Adds a --enable-[$1] switch to configure. +# +# Substs the following vars: +# CRITCL_UCONFIG_$1 +#------------------------------------------------------------------------ + +AC_DEFUN([CRITCL_TEA_BOOL_CONFIG],[ + # CRITCL_TEA_BOOL_CONFIG: $1 + AC_ARG_ENABLE([$1], + AC_HELP_STRING([--enable-$1],[$3]), + [bool_uc_$1=${enableval}] + [bool_uc_$1="$2"]) + + if test "bool_uc_$1" = "yes" ; then + CRITCL_UCONFIG_$1="-enable $1" + else + CRITCL_UCONFIG_$1="-disable $1" + fi + + AC_SUBST([CRITCL_UCONFIG_$1]) +]) diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/configure.in b/src/vfs/critcl.vfs/lib/app-critcl/tea/configure.in new file mode 100644 index 00000000..331b523d --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/configure.in @@ -0,0 +1,151 @@ +# Configure for +# @@PNAME@@ @@PMAJORV@@.@@PMINORV@@ +# +# Copyright (c) @@YEAR@@ @@PORG@@ +# +# Generated by @@CRITCL@@ +# At @@NOW@@ + +AC_INIT([@@PNAME@@],[@@PMAJORV@@.@@PMINORV@@]) + +TEA_INIT([3.9]) + +AC_CONFIG_AUX_DIR(tclconfig) + +#-------------------------------------------------------------------- +# Configure script for package '@@PNAME@@'. +# TEA compliant. +#-------------------------------------------------------------------- + +#-------------------------------------------------------------------- +# Load the tclConfig.sh file +#-------------------------------------------------------------------- + +TEA_PATH_TCLCONFIG +TEA_LOAD_TCLCONFIG + +#----------------------------------------------------------------------- +## Std TEA setup + +TEA_PREFIX +TEA_SETUP_COMPILER +TEA_PUBLIC_TCL_HEADERS +#TEA_PRIVATE_TCL_HEADERS +TEA_ENABLE_THREADS +TEA_ENABLE_SHARED +TEA_CONFIG_CFLAGS +TEA_ENABLE_SYMBOLS +AC_DEFINE(USE_TCL_STUBS) +TEA_MAKE_LIB +TEA_PROG_TCLSH +@@API@@ +@@UCONFIG@@ +#----------------------------------------------------------------------- +## Convert the TEA settings determined by the macros in the last +## section into something critcl can use throughts configuration. + +AC_MSG_RESULT([critcl config: derived from core TEA]) + +#AC_MSG_RESULT([critcl config: CC............. ${CC}]) +#AC_MSG_RESULT([critcl config: CFLAGS......... ${CFLAGS}]) +#AC_MSG_RESULT([critcl config: SHLIB_LD....... ${SHLIB_LD}]) +#AC_MSG_RESULT([critcl config: LIBS........... ${LIBS}| +#AC_MSG_RESULT([critcl config: MATH_LIBS...... ${MATH_LIBS}]) +#AC_MSG_RESULT([critcl config: CFLAGS_DEFAULT. ${CFLAGS_DEFAULT}]) +#AC_MSG_RESULT([critcl config: CFLAGS_WARNING. ${CFLAGS_WARNING}]) +#AC_MSG_RESULT([critcl config: SHLIB_CFLAGS... ${SHLIB_CFLAGS}]) +#AC_MSG_RESULT([critcl config: LDFLAGS_DEFAULT ${LDFLAGS_DEFAULT}]) + +#----------------------------------------------------------------------- +## 1. Basic/foundational translation. + +CRITCL_CC="$(eval echo ${CC} -c ${CFLAGS})" +CRITCL_VERSION="${CC} -v" +CRITCL_LINK="$(eval echo $(eval echo ${SHLIB_LD} ${LIBS} ${MATH_LIBS}))" +CRITCL_PLATFORM="$(${TCLSH_PROG} ${srcdir}/critcl/main.tcl -showtarget)" +CRITCL_LD_DBG="" +CRITCL_LD_REL="" +CRITCL_CC_OUTPUT="-o [[list \$outfile]]" +CRITCL_LD_OUTPUT="" + +if test "${GCC}" = "yes" +then + CRITCL_CPP_DEFINE="${CPP} -dM" +else + CRITCL_CPP_DEFINE="${CPP}" + + if test "${TEA_PLATFORM}" = "windows" + then + # windows, no gcc => msvc + CRITCL_CC_OUTPUT="[[list -Fo\$outfile]]" + CRITCL_LD_OUTPUT="-dll [[list -out:\$outfile]]" + CRITCL_LD_DBG="-debug:full -debugtype:cv -verbose:lib" + CRITCL_LD_REL="-release -opt:ref -opt:icf,3 -ws:aggressive -verbose:lib" + if test "$do64bit" = "no" ; then + # 32bit + CRITCL_LD_DBG="$CRITCL_LD_DBG -nodefaultlib:libc" + fi + fi +fi +CRITCL_CPP_ENUM="${CPP}" + +#----------------------------------------------------------------------- +## 2. Fine tuning the commands, this now is platform specific. + +case $(uname -s) in +Darwin*) + AC_MSG_RESULT([critcl config: darwin specific tune-up]) + + # - Critcl, due to essentially generating its private + # lib{tcl,tk}stub.a does generate common symbols for the + # stubs tables. Use of -fno-common then prevents linking the + # object files. + # + # - A version 0.0 as pulled from TEA package version is not + # liked by the Darwin gcc either (Example: crimp). + + CRITCL_CC="$(echo "$CRITCL_CC" |sed -e 's,-fno-common,,g')" + CRITCL_LINK="$(echo "$CRITCL_LINK"|sed -e 's,-fno-common,,g')" + CRITCL_LINK="$(echo "$CRITCL_LINK"|sed -e 's,-current_version 0\.0,,g')" + CRITCL_LINK="$(echo "$CRITCL_LINK"|sed -e 's,-compatibility_version 0\.0,,g')" + ;; +*) + ;; +esac + +#----------------------------------------------------------------------- +## Conversion results + +AC_MSG_RESULT([critcl config: platform.......... $CRITCL_PLATFORM]) +AC_MSG_RESULT([critcl config: compile........... $CRITCL_CC]) +AC_MSG_RESULT([critcl config: link.............. $CRITCL_LINK]) +AC_MSG_RESULT([critcl config: cpp define........ $CRITCL_CPP_DEFINE]) +AC_MSG_RESULT([critcl config: cpp enum.......... $CRITCL_CPP_ENUM]) +AC_MSG_RESULT([critcl config: version inquiry... $CRITCL_VERSION]) +AC_MSG_RESULT([critcl config: cc output......... $CRITCL_CC_OUTPUT]) +AC_MSG_RESULT([critcl config: ld output......... $CRITCL_LD_OUTPUT]) +AC_MSG_RESULT([critcl config: ld debug.......... $CRITCL_LD_DBG]) +AC_MSG_RESULT([critcl config: ld release........ $CRITCL_LD_REL]) + +#----------------------------------------------------------------------- + +AC_SUBST(CRITCL_CC) +AC_SUBST(CRITCL_VERSION) +AC_SUBST(CRITCL_LINK) +AC_SUBST(CRITCL_PLATFORM) +AC_SUBST(CRITCL_CPP_DEFINE) +AC_SUBST(CRITCL_CPP_ENUM) +AC_SUBST(CRITCL_CC_OUTPUT) +AC_SUBST(CRITCL_LD_OUTPUT) +AC_SUBST(CRITCL_LD_DBG) +AC_SUBST(CRITCL_LD_REL) +#AC_SUBST(CRITCL_) +#AC_SUBST() + +#-------------------------------------------------------------------- +# Finally, substitute all of the various values into the Makefile. +# You may alternatively have a special pkgIndex.tcl.in or other files +# which require substituting th AC variables in. Include these here. +#-------------------------------------------------------------------- + +AC_OUTPUT([Makefile Config]) diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/README.txt b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/README.txt new file mode 100644 index 00000000..715cb9dd --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/README.txt @@ -0,0 +1,26 @@ +These files comprise the basic building blocks for a Tcl Extension +Architecture (TEA) extension. For more information on TEA see: + + http://www.tcl.tk/doc/tea/ + +This package is part of the Tcl project at SourceForge, but sources +and bug/patch database are hosted on fossil here: + + https://core.tcl-lang.org/tclconfig + +This package 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. + +CONTENTS +======== +The following is a short description of the files you will find in +the sample extension. + +README.txt This file + +install-sh Program used for copying binaries and script files + to their install locations. + +tcl.m4 Collection of Tcl autoconf macros. Included by a package's + aclocal.m4 to define TEA_* macros. diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/install-sh b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/install-sh new file mode 100644 index 00000000..ec298b53 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/install-sh @@ -0,0 +1,541 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2020-11-14.01; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. + -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -p) cpprog="$cpprog -p";; + + -s) stripcmd=$stripprog;; + + -S) backupsuffix="$2" + shift;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/license.terms b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/license.terms new file mode 100644 index 00000000..d8049cd9 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/license.terms @@ -0,0 +1,40 @@ +This 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-7014 (b) (3) 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. diff --git a/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/tcl.m4 b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/tcl.m4 new file mode 100644 index 00000000..9ac67c22 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/app-critcl/tea/tclconfig/tcl.m4 @@ -0,0 +1,4091 @@ +# tcl.m4 -- +# +# This file provides a set of autoconf macros to help TEA-enable +# a Tcl extension. +# +# Copyright (c) 1999-2000 Ajuba Solutions. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +AC_PREREQ([2.69]) + +# Possible values for key variables defined: +# +# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') +# TEA_PLATFORM - windows unix +# TEA_TK_EXTENSION - True if this is a Tk extension +# + +#------------------------------------------------------------------------ +# TEA_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([TEA_PATH_TCLCONFIG], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + # + # 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, + AS_HELP_STRING([--with-tcl], + [directory containing tcl configuration (tclConfig.sh)]), + [with_tclconfig="${withval}"]) + AC_ARG_WITH(tcl8, + AS_HELP_STRING([--with-tcl8], + [Compile for Tcl8 in Tcl9 environment]), + [with_tcl8="${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 "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + 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 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 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 + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `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 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/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.5 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 "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + 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 +]) + +#------------------------------------------------------------------------ +# TEA_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([TEA_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, + AS_HELP_STRING([--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 "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + 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` \ + ; 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/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib/tk8.6 2>/dev/null` \ + `ls -d /usr/lib/tk8.5 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/local/lib/tk8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tk8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `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 "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + 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 +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TCLCONFIG -- +# +# Load the tclConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TCL_BIN_DIR +# +# Results: +# +# Substitutes the following vars: +# TCL_BIN_DIR +# TCL_SRC_DIR +# TCL_LIB_FILE +# TCL_ZIP_FILE +# TCL_ZIPFS_SUPPORT +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_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}" + 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 + + 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) + + AC_MSG_CHECKING([platform]) + hold_cc=$CC; CC="$TCL_CC" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + #ifdef _WIN32 + #error win32 + #endif + ]])],[ + # first test we've already retrieved platform (cross-compile), fallback to unix otherwise: + TEA_PLATFORM="${TEA_PLATFORM-unix}" + CYGPATH=echo + ],[ + TEA_PLATFORM="windows" + AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) + ]) + CC=$hold_cc + AC_MSG_RESULT($TEA_PLATFORM) + + # The BUILD_$pkg is to define the correct extern storage class + # handling when making this package + AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], + [Building extension source?]) + # Do this here as we have fully defined TEA_PLATFORM now + if test "${TEA_PLATFORM}" = "windows" ; then + EXEEXT=".exe" + CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" + fi + + # TEA specific: + AC_SUBST(CLEANFILES) + AC_SUBST(TCL_LIBS) + AC_SUBST(TCL_DEFS) + AC_SUBST(TCL_EXTRA_CFLAGS) + AC_SUBST(TCL_LD_FLAGS) + AC_SUBST(TCL_SHLIB_LD_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_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([TEA_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 + + # 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 + + # TEA specific: Ensure windowingsystem is defined + if test "${TEA_PLATFORM}" = "unix" ; then + case ${TK_DEFS} in + *MAC_OSX_TK*) + AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) + TEA_WINDOWINGSYSTEM="aqua" + ;; + *) + TEA_WINDOWINGSYSTEM="x11" + ;; + esac + elif test "${TEA_PLATFORM}" = "windows" ; then + TEA_WINDOWINGSYSTEM="win32" + fi + + 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) + + # TEA specific: + AC_SUBST(TK_LIBS) + AC_SUBST(TK_XINCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_TCLSH +# Determine the fully qualified path name of the tclsh executable +# in the Tcl build directory or the tclsh installed in a bin +# 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 tclsh found is always +# associated with a tclConfig.sh file. This tclsh should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# TCLSH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_TCLSH], [ + AC_MSG_CHECKING([for tclsh]) + if test -f "${TCL_BIN_DIR}/Makefile" ; then + # tclConfig.sh is in Tcl build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" + fi + else + TCLSH_PROG="${TCL_BIN_DIR}/tclsh" + fi + else + # tclConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" + else + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" + fi + list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${TCLSH_PROG}" ; then + REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" + fi + AC_MSG_RESULT([${TCLSH_PROG}]) + AC_SUBST(TCLSH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_WISH +# Determine the fully qualified path name of the wish executable +# in the Tk build directory or the wish installed in a bin +# directory. This macro will correctly determine the name +# of the wish executable even if wish has not yet been +# built in the build directory. The wish found is always +# associated with a tkConfig.sh file. This wish should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# WISH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_WISH], [ + AC_MSG_CHECKING([for wish]) + if test -f "${TK_BIN_DIR}/Makefile" ; then + # tkConfig.sh is in Tk build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" + elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" + fi + else + WISH_PROG="${TK_BIN_DIR}/wish" + fi + else + # tkConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" + else + WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" + fi + list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TK_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${WISH_PROG}" ; then + REAL_TK_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" + fi + AC_MSG_RESULT([${WISH_PROG}]) + AC_SUBST(WISH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SHARED -- +# +# Allows the building of shared libraries +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-shared=yes|no +# --enable-stubs=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 +# STUBS_BUILD Value if 1 or 0 +# USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs +# USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs +# USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs +# AND TEA_WINDOWING_SYSTEM != "" +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ENABLE_SHARED], [ + AC_MSG_CHECKING([how to build libraries]) + AC_ARG_ENABLE(shared, + AS_HELP_STRING([--enable-shared], + [build and link with shared libraries (default: on)]), + [shared_ok=$enableval], [shared_ok=yes]) + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + shared_ok=$enableval + else + shared_ok=yes + fi + + AC_ARG_ENABLE(stubs, + AS_HELP_STRING([--enable-stubs], + [build and link with stub libraries. Always true for shared builds (default: on)]), + [stubs_ok=$enableval], [stubs_ok=yes]) + + if test "${enable_stubs+set}" = set; then + enableval="$enable_stubs" + stubs_ok=$enableval + else + stubs_ok=yes + fi + + # Stubs are always enabled for shared builds + if test "$shared_ok" = "yes" ; then + AC_MSG_RESULT([shared]) + SHARED_BUILD=1 + STUBS_BUILD=1 + else + AC_MSG_RESULT([static]) + SHARED_BUILD=0 + AC_DEFINE(STATIC_BUILD, 1, [This a static build]) + if test "$stubs_ok" = "yes" ; then + STUBS_BUILD=1 + else + STUBS_BUILD=0 + fi + fi + if test "${STUBS_BUILD}" = "1" ; then + AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) + AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) + if test "${TEA_WINDOWINGSYSTEM}" != ""; then + AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) + fi + fi + + AC_SUBST(SHARED_BUILD) + AC_SUBST(STUBS_BUILD) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_THREADS -- +# +# Specify if thread support should be enabled. If "yes" is specified +# as an arg (optional), threads are enabled by default, "no" means +# threads are disabled. "yes" is the default. +# +# TCL_THREADS is checked so that if you are compiling an extension +# against a threaded core, your extension must be compiled threaded +# as well. +# +# Note that it is legal to have a thread enabled extension run in a +# threaded or non-threaded Tcl core, but a non-threaded extension may +# only run in a non-threaded Tcl core. +# +# 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([TEA_ENABLE_THREADS], [ + AC_ARG_ENABLE(threads, + AS_HELP_STRING([--enable-threads], + [build with threads (default: on)]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then + TCL_THREADS=1 + + if test "${TEA_PLATFORM}" != "windows" ; then + # We are always OK on Windows, so check what this platform wants: + + # 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([Do not know how to find pthread lib on your system - thread support disabled]) + fi + fi + fi + fi + fi + 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?]) + AC_MSG_RESULT([yes (default)]) + else + AC_MSG_RESULT([no]) + fi + # TCL_THREADS sanity checking. See if our request for building with + # threads is the same as the way Tcl was built. If not, warn the user. + case ${TCL_DEFS} in + *THREADS=1*) + if test "${TCL_THREADS}" = "0"; then + AC_MSG_WARN([ + Building ${PACKAGE_NAME} without threads enabled, but building against Tcl + that IS thread-enabled. It is recommended to use --enable-threads.]) + fi + ;; + esac + AC_SUBST(TCL_THREADS) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SYMBOLS -- +# +# Specify if debugging symbols should be used. +# Memory (TCL_MEM_DEBUG) debugging can also be enabled. +# +# Arguments: +# none +# +# TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives +# the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. +# Requires the following vars to be set in the Makefile: +# CFLAGS_DEFAULT +# LDFLAGS_DEFAULT +# +# 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) -DNDEBUG" if false +# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true +# Sets to $(LDFLAGS_OPTIMIZE) if false +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_SYMBOLS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_CONFIG_CFLAGS]) + AC_MSG_CHECKING([for build with symbols]) + AC_ARG_ENABLE(symbols, + AS_HELP_STRING([--enable-symbols], + [build with debugging symbols (default: off)]), + [tcl_ok=$enableval], [tcl_ok=no]) + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" + LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" + AC_MSG_RESULT([no]) + AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?]) + else + CFLAGS_DEFAULT="${CFLAGS_DEBUG}" + LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" + 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" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + AC_MSG_RESULT([enabled symbols mem debugging]) + else + AC_MSG_RESULT([enabled $tcl_ok debugging]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_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([TEA_ENABLE_LANGINFO], [ + AC_ARG_ENABLE(langinfo, + AS_HELP_STRING([--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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#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 +]) + +#-------------------------------------------------------------------- +# TEA_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. +# +# Arguments: +# none +# +# Results: +# Defines the following var: +# +# system - System/platform/version identification code. +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_SYSTEM], [ + AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + 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 + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then + tcl_cv_sys_version=NetBSD-Debian + fi + fi + fi + ]) + system=$tcl_cv_sys_version +]) + +#-------------------------------------------------------------------- +# TEA_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, DL_LIBS - removed for TEA, only needed by core. +# 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. +# 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 defaults to +# "${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. +# LIB_SUFFIX - Specifies everything that comes after the "libfoo" +# in a static or shared library name, using the $PACKAGE_VERSION variable +# to put the version in the right place. This is used +# by platforms that need non-standard library names. +# Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs +# to have a version after the .so, and ${PACKAGE_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 +# ${PACKAGE_VERSION}${SHLIB_SUFFIX}. +# 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([TEA_CONFIG_CFLAGS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + + # Step 0.a: Enable 64 bit support? + + AC_MSG_CHECKING([if 64bit support is requested]) + AC_ARG_ENABLE(64bit, + AS_HELP_STRING([--enable-64bit], + [enable 64bit support (default: off)]), + [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, + AS_HELP_STRING([--enable-64bit-vis], + [enable 64bit Sparc VIS support (default: off)]), + [do64bitVIS=$enableval], [do64bitVIS=no]) + AC_MSG_RESULT([$do64bitVIS]) + # Force 64bit on with VIS + AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) + + # Step 0.c: Check if visibility support is available. Do this here so + # that platform specific alternatives can be used below if this fails. + + AC_CACHE_CHECK([if compiler supports visibility "hidden"], + tcl_cv_cc_visibility_hidden, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + extern __attribute__((__visibility__("hidden"))) void f(void); + void f(void) {}]], [[f();]])],[tcl_cv_cc_visibility_hidden=yes], + [tcl_cv_cc_visibility_hidden=no]) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ + AC_DEFINE(MODULE_SCOPE, + [extern __attribute__((__visibility__("hidden")))], + [Compiler support for module scope symbols]) + AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) + ]) + + # Step 0.d: Disable -rpath support? + + AC_MSG_CHECKING([if rpath support is requested]) + AC_ARG_ENABLE(rpath, + AS_HELP_STRING([--disable-rpath], + [disable rpath support (default: on)]), + [doRpath=$enableval], [doRpath=yes]) + AC_MSG_RESULT([$doRpath]) + + # Set the variable "system" to hold the name and version number + # for the system. + + TEA_CONFIG_SYSTEM + + # Require ranlib early so we can override it in special cases below. + + AC_REQUIRE([AC_PROG_RANLIB]) + + # Set configuration options based on system name and version. + # This is similar to Tcl's unix/tcl.m4 except that we've added a + # "windows" case and removed some core-only vars. + + do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' + # When ld needs options to work in 64-bit mode, put them in + # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] + # is disabled by the user. [Bug 1016796] + LDFLAGS_ARCH="" + UNSHARED_LIB_SUFFIX="" + # TEA specific: use PACKAGE_VERSION instead of VERSION + TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' + ECHO_VERSION='`echo ${PACKAGE_VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + AS_IF([test "$GCC" = yes], [ + CFLAGS_OPTIMIZE=-O2 + CFLAGS_WARNING="-Wall" + ], [ + CFLAGS_OPTIMIZE=-O + CFLAGS_WARNING="" + ]) + AC_CHECK_TOOL(AR, ar) + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) + case $system in + # TEA specific: + windows) + MACHINE="X86" + if test "$do64bit" != "no" ; then + case "$do64bit" in + amd64|x64|yes) + MACHINE="AMD64" ; # default to AMD64 64-bit build + ;; + arm64|aarch64) + MACHINE="ARM64" + ;; + ia64) + MACHINE="IA64" + ;; + esac + fi + + if test "$GCC" != "yes" ; then + if test "${SHARED_BUILD}" = "0" ; then + runtime=-MT + else + runtime=-MD + fi + case "x`echo \${VisualStudioVersion}`" in + x1[[4-9]]*) + lflags="${lflags} -nodefaultlib:libucrt.lib" + TEA_ADD_LIBS([ucrt.lib]) + ;; + *) + ;; + esac + + if test "$do64bit" != "no" ; then + CC="cl.exe" + RC="rc.exe" + lflags="${lflags} -nologo -MACHINE:${MACHINE} " + LINKBIN="link.exe" + CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + # Avoid 'unresolved external symbol __security_cookie' + # errors, c.f. http://support.microsoft.com/?id=894573 + TEA_ADD_LIBS([bufferoverflowU.lib]) + else + RC="rc" + lflags="${lflags} -nologo" + LINKBIN="link" + CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + fi + fi + + if test "$GCC" = "yes"; then + # mingw gcc mode + AC_CHECK_TOOL(RC, windres) + CFLAGS_DEBUG="-g" + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + SHLIB_LD='${CC} -shared' + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" + LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" + + AC_CACHE_CHECK(for cross-compile version of gcc, + ac_cv_cross, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #ifdef _WIN32 + #error cross-compiler + #endif + ]], [[]])], + [ac_cv_cross=yes], + [ac_cv_cross=no]) + ) + if test "$ac_cv_cross" = "yes"; then + case "$do64bit" in + amd64|x64|yes) + CC="x86_64-w64-mingw32-${CC}" + LD="x86_64-w64-mingw32-ld" + AR="x86_64-w64-mingw32-ar" + RANLIB="x86_64-w64-mingw32-ranlib" + RC="x86_64-w64-mingw32-windres" + ;; + arm64|aarch64) + CC="aarch64-w64-mingw32-clang" + LD="aarch64-w64-mingw32-ld" + AR="aarch64-w64-mingw32-ar" + RANLIB="aarch64-w64-mingw32-ranlib" + RC="aarch64-w64-mingw32-windres" + ;; + *) + CC="i686-w64-mingw32-${CC}" + LD="i686-w64-mingw32-ld" + AR="i686-w64-mingw32-ar" + RANLIB="i686-w64-mingw32-ranlib" + RC="i686-w64-mingw32-windres" + ;; + esac + fi + + else + SHLIB_LD="${LINKBIN} -dll ${lflags}" + # link -lib only works when -lib is the first arg + STLIB_LD="${LINKBIN} -lib ${lflags}" + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' + PATHTYPE=-w + # For information on what debugtype is most useful, see: + # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp + # and also + # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx + # This essentially turns it all on. + LDFLAGS_DEBUG="-debug -debugtype:cv" + LDFLAGS_OPTIMIZE="-release" + LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" + LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" + fi + + SHLIB_SUFFIX=".dll" + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' + + TCL_LIB_VERSIONS_OK=nodots + ;; + AIX-*) + AS_IF([test "$GCC" != "yes"], [ + # 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]) + ]) + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + SHLIB_SUFFIX=".so" + + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -q64" + LDFLAGS_ARCH="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + ]) + ]) + + AS_IF([test "`uname -m`" = ia64], [ + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + AS_IF([test "$GCC" = yes], [ + CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' + ], [ + CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"' + ]) + LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' + ], [ + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared -Wl,-bexpall' + ], [ + SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" + LDFLAGS="$LDFLAGS -brtl" + ]) + SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" + CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + BeOS*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -nostart' + SHLIB_SUFFIX=".so" + + #----------------------------------------------------------- + # 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" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + CYGWIN_*) + SHLIB_CFLAGS="" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".dll" + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" + EXEEXT=".exe" + do64bit_ok=yes + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + dgux*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + Haiku*) + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' + 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?]) + # TEA specific: Needed by Tcl, but not most extensions + #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) + #LIBS="$LIBS -lxnet" # Use the XOPEN network library + + AS_IF([test "`uname -m`" = ia64], [ + SHLIB_SUFFIX=".so" + ], [ + SHLIB_SUFFIX=".sl" + ]) + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + 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" + ]) + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + CFLAGS="$CFLAGS -z" + ]) + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = "yes"], [ + AS_IF([test "$GCC" = yes], [ + case `${CC} -dumpmachine` in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD='${CC} -shared' + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ;; + esac + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS +DD64" + LDFLAGS_ARCH="+DD64" + ]) + ]) ;; + HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) + SHLIB_SUFFIX=".sl" + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + SHLIB_LD_LIBS="" + 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" + ]) ;; + IRIX-5.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AC_LIBOBJ(mkstemp) + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) + ;; + IRIX-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) + AS_IF([test "$GCC" = yes], [ + CFLAGS="$CFLAGS -mabi=n32" + LDFLAGS="$LDFLAGS -mabi=n32" + ], [ + 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" + ]) + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) + + # Check to enable 64-bit flags for compiler/linker + + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported by gcc]) + ], [ + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + ]) + ]) + ;; + Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + # TEA specific: + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + + case $system in + DragonFly-*|FreeBSD-*) + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the LDFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) + ;; + esac + + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + AS_IF([test $do64bit = yes], [ + AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -m64" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [tcl_cv_cc_m64=yes],[tcl_cv_cc_m64=no]) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_m64 = yes], [ + CFLAGS="$CFLAGS -m64" + do64bit_ok=yes + ]) + ]) + + # 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. + + AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) + ;; + Lynx*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + CFLAGS_OPTIMIZE=-02 + SHLIB_LD='${CC} -shared' + LD_FLAGS="-Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) + ;; + OpenBSD-*) + arch=`arch -s` + case "$arch" in + alpha|sparc64) + SHLIB_CFLAGS="-fPIC" + ;; + *) + SHLIB_CFLAGS="-fpic" + ;; + esac + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' + LDFLAGS="$LDFLAGS -Wl,-export-dynamic" + CFLAGS_OPTIMIZE="-O2" + # On OpenBSD: Compile with -pthread + # Don't link with -lpthread + LIBS=`echo $LIBS | sed s/-lpthread//` + CFLAGS="$CFLAGS -pthread" + # OpenBSD doesn't do version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.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} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ;; + 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}'`" + AS_IF([test $do64bit = yes], [ + 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_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [tcl_cv_cc_arch_ppc64=yes],[tcl_cv_cc_arch_ppc64=no]) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + do64bit_ok=yes + ]);; + 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_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [tcl_cv_cc_arch_x86_64=yes],[tcl_cv_cc_arch_x86_64=no]) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ + CFLAGS="$CFLAGS -arch x86_64" + do64bit_ok=yes + ]);; + *) + AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; + esac + ], [ + # Check for combined 32-bit and 64-bit fat build + AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ + && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ + fat_32_64=yes]) + ]) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' + AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], + [tcl_cv_ld_single_module=yes],[tcl_cv_ld_single_module=no]) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_single_module = yes], [ + SHLIB_LD="${SHLIB_LD} -Wl,-single_module" + ]) + # TEA specific: link shlib with current and compatibility version flags + vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` + SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" + SHLIB_SUFFIX=".dylib" + 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_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], + [tcl_cv_ld_search_paths_first=yes],[tcl_cv_ld_search_paths_first=no]) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + ]) + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [__private_extern__], + [Compiler support for module scope symbols]) + tcl_cv_cc_visibility_hidden=yes + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + # TEA specific: for combined 32 & 64 bit fat builds of Tk + # extensions, verify that 64-bit build is possible. + AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ + AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_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 + CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" + LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[XrmInitialize();]])], + [tcl_cv_lib_x11_64=yes],[tcl_cv_lib_x11_64=no]) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ + AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_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 + CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" + LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[Tk_InitStubs(NULL, "", 0);]])], + [tcl_cv_lib_tk_64=yes],[tcl_cv_lib_tk_64=no]) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + # remove 64-bit arch flags from CFLAGS et al. if configuration + # does not support 64-bit. + AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ + AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' + done]) + ]) + ;; + OS/390-*) + 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-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + AS_IF([test "$SHARED_BUILD" = 1], [ + SHLIB_LD='ld -shared -expect_unresolved "*"' + ], [ + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + ]) + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ + CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) + # see pthread_intro(3) for pthread support on osf1, k.furukawa + CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + AS_IF([test "$GCC" = yes], [ + LIBS="$LIBS -lpthread -lmach -lexc" + ], [ + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + ;; + 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" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SCO_SV-3.2*) + AS_IF([test "$GCC" = yes], [ + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" + ], [ + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + ]) + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + 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" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + 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 + AS_IF([test "$do64bit" = yes], [ + arch=`isainfo` + AS_IF([test "$arch" = "sparcv9 sparc"], [ + AS_IF([test "$GCC" = yes], [ + AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ + AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -m64 -mcpu=v9" + LDFLAGS="$LDFLAGS -m64 -mcpu=v9" + SHLIB_CFLAGS="-fPIC" + ]) + ], [ + do64bit_ok=yes + AS_IF([test "$do64bitVIS" = yes], [ + CFLAGS="$CFLAGS -xarch=v9a" + LDFLAGS_ARCH="-xarch=v9a" + ], [ + CFLAGS="$CFLAGS -xarch=v9" + LDFLAGS_ARCH="-xarch=v9" + ]) + # Solaris 64 uses this as well + #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" + ]) + ], [AS_IF([test "$arch" = "amd64 i386"], [ + AS_IF([test "$GCC" = yes], [ + 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 + ], [ + 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 + ]) + ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) + ]) + + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "$do64bit_ok" = yes], [ + AS_IF([test "$arch" = "sparcv9 sparc"], [ + # We need to specify -static-libgcc or we need to + # add the path to the sparv9 libgcc. + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + 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" + ], [AS_IF([test "$arch" = "amd64 i386"], [ + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" + ])]) + ]) + ], [ + case $system in + SunOS-5.[[1-9]][[0-9]]*) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; + *) + 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}"' + ]) + ;; + UNIX_SV* | UnixWare-5*) + SHLIB_CFLAGS="-KPIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + # 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_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], + [tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no]) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_Bexport = yes], [ + LDFLAGS="$LDFLAGS -Wl,-Bexport" + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + esac + + AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ + AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) + ]) + +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. + AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) + + # Add in the arch flags late to ensure it wasn't removed. + # Not necessary in TEA, but this is aligned with core + LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" + + # 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. + + AS_IF([test "$GCC" = yes], [ + case $system in + AIX-*) ;; + BSD/OS*) ;; + CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;; + IRIX*) ;; + NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; + Darwin-*) ;; + SCO_SV-3.2*) ;; + windows) ;; + *) SHLIB_CFLAGS="-fPIC" ;; + esac]) + + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [extern], + [No Compiler support for module scope symbols]) + ]) + + AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) + AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) + + if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then + AC_CACHE_CHECK(for SEH support in compiler, + tcl_cv_seh, + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#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_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +# 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#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 + 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + 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_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have ?])],) + + AC_SUBST(CFLAGS_DEBUG) + AC_SUBST(CFLAGS_OPTIMIZE) + AC_SUBST(CFLAGS_WARNING) + AC_SUBST(LDFLAGS_DEBUG) + AC_SUBST(LDFLAGS_OPTIMIZE) + + AC_SUBST(STLIB_LD) + AC_SUBST(SHLIB_LD) + + AC_SUBST(SHLIB_LD_LIBS) + AC_SUBST(SHLIB_CFLAGS) + + AC_SUBST(LD_LIBRARY_PATH_VAR) + + # These must be called after we do the basic CFLAGS checks and + # verify any possible 64-bit or similar switches are necessary + TEA_TCL_EARLY_FLAGS + TEA_TCL_64BIT_FLAGS +]) + +#-------------------------------------------------------------------- +# TEA_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([TEA_SERIAL_PORT], [ + AC_CHECK_HEADERS(sys/modem.h) + AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#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_RUN_IFELSE([AC_LANG_SOURCE([[ +#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_RUN_IFELSE([AC_LANG_SOURCE([[ +#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_RUN_IFELSE([AC_LANG_SOURCE([[ +#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_RUN_IFELSE([AC_LANG_SOURCE([[ +#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_RUN_IFELSE([AC_LANG_SOURCE([[ +#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 +]) + +#-------------------------------------------------------------------- +# TEA_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. +# +# This should be called after TEA_CONFIG_CFLAGS as setting the +# LIBS line can confuse some configure macro magic. +# +# Arguments: +# none +# +# Results: +# +# Sets the following vars: +# XINCLUDES +# XLIBSW +# PKG_LIBS (appends to) +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_PATH_X], [ + if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then + TEA_PATH_UNIX_X + fi +]) + +AC_DEFUN([TEA_PATH_UNIX_X], [ + AC_PATH_X + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[],[not_really_there="yes"]) + else + if test ! -r $x_includes/X11/Xlib.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_PREPROC_IFELSE([AC_LANG_SOURCE([[#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/Xlib.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 + # TEA specific: + if test x"${XLIBSW}" != x ; then + PKG_LIBS="${PKG_LIBS} ${XLIBSW}" + fi +]) + +#-------------------------------------------------------------------- +# TEA_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([TEA_BLOCKING_STYLE], [ + AC_CHECK_HEADERS(sys/ioctl.h) + AC_CHECK_HEADERS(sys/filio.h) + TEA_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]) + ;; + *) + AC_MSG_RESULT([O_NONBLOCK]) + ;; + esac +]) + +#-------------------------------------------------------------------- +# TEA_TIME_HANDLER +# +# 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([TEA_TIME_HANDLER], [ + AC_CHECK_HEADERS(sys/time.h) + AC_HEADER_TIME + AC_STRUCT_TIMEZONE + + AC_CHECK_FUNCS(gmtime_r localtime_r mktime) + + AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#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 +]) + +#-------------------------------------------------------------------- +# TEA_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([TEA_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_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + 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 + AC_LIBOBJ([fixstrtod]) + USE_COMPAT=1 + AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_LINK_LIBS +# +# Search for the libraries needed to link the Tcl shell. +# Things like the math library (-lm), socket stuff (-lsocket vs. +# -lnsl), zlib (-lz) and libtommath (-ltommath) are dealt with here. +# +# Arguments: +# None. +# +# Results: +# +# Might append to the following vars: +# LIBS +# MATH_LIBS +# +# Might define the following vars: +# HAVE_NET_ERRNO_H +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_LINK_LIBS], [ + #-------------------------------------------------------------------- + # On a few very rare systems, all of the libm.a stuff is + # already in libc.a. Set compiler flags accordingly. + #-------------------------------------------------------------------- + + AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") + + #-------------------------------------------------------------------- + # 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"])]) + AC_CHECK_FUNC(mp_log_u32, , [AC_CHECK_LIB(tommath, mp_log_u32, + [LIBS="$LIBS -ltommath"])]) + AC_CHECK_FUNC(deflateSetHeader, , [AC_CHECK_LIB(z, deflateSetHeader, + [LIBS="$LIBS -lz"])]) +]) + +#-------------------------------------------------------------------- +# TEA_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 +# _FILE_OFFSET_BITS +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_EARLY_FLAG],[ + AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])], + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ ]m4_default([$4],[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, m4_default([$4],[1]), [Add the ]$1[ flag when building]) + tcl_flags="$tcl_flags $1" + fi +]) + +AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ + AC_MSG_CHECKING([for required early compiler flags]) + tcl_flags="" + TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], + [char *p = (char *)strtoll; char *q = (char *)strtoull;]) + if test "${TCL_MAJOR_VERSION}" -ne 8 ; then + TEA_TCL_EARLY_FLAG(_FILE_OFFSET_BITS,[#include ], + [switch (0) { case 0: case (sizeof(off_t)==sizeof(long long)): ; }],64) + fi + if test "x${tcl_flags}" = "x" ; then + AC_MSG_RESULT([none]) + else + AC_MSG_RESULT([${tcl_flags}]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_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_DIR64 +# HAVE_STRUCT_STAT64 +# HAVE_TYPE_OFF64_T +# _TIME_BITS +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__int64 value = (__int64) 0;]])], + [tcl_type_64bit=__int64],[tcl_type_64bit="long long"]) + # See if we could 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[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, [Do 'long' and 'long long' have the same size (64-bit)?]) + AC_MSG_RESULT([yes]) + elif test "${tcl_cv_type_64bit}" = "__int64" \ + -a "${TEA_PLATFORM}" = "windows" ; then + # TEA specific: We actually want to use the default tcl.h checks in + # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* + AC_MSG_RESULT([using Tcl header defaults]) + 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 + if test "${TCL_MAJOR_VERSION}" -ne 8 ; then + AC_CACHE_CHECK([for 64-bit time_t], tcl_cv_time_t_64,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])], + [tcl_cv_time_t_64=yes],[tcl_cv_time_t_64=no])]) + if test "x${tcl_cv_time_t_64}" = "xno" ; then + # Note that _TIME_BITS=64 requires _FILE_OFFSET_BITS=64 + # which SC_TCL_EARLY_FLAGS has defined if necessary. + AC_CACHE_CHECK([if _TIME_BITS=64 enables 64-bit time_t], tcl_cv__time_bits,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _TIME_BITS 64 +#include ]], + [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])], + [tcl_cv__time_bits=yes],[tcl_cv__time_bits=no])]) + if test "x${tcl_cv__time_bits}" = "xyes" ; then + AC_DEFINE(_TIME_BITS, 64, [_TIME_BITS=64 enables 64-bit time_t.]) + fi + fi + fi + + AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#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 DIR64], tcl_cv_DIR64,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include ]], [[struct dirent64 *p; DIR64 d = opendir64("."); + p = readdir64(d); rewinddir64(d); closedir64(d);]])], + [tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])]) + if test "x${tcl_cv_DIR64}" = "xyes" ; then + AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in ?]) + fi + + AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#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 +]) + +## +## Here ends the standard Tcl configuration bits and starts the +## TEA specific functions +## + +#------------------------------------------------------------------------ +# TEA_INIT -- +# +# Init various Tcl Extension Architecture (TEA) variables. +# This should be the first called TEA_* macro. +# +# Arguments: +# none +# +# Results: +# +# Defines and substs the following vars: +# CYGPATH +# EXEEXT +# Defines only: +# TEA_VERSION +# TEA_INITED +# TEA_PLATFORM (windows or unix) +# +# "cygpath" is used on windows to generate native path names for include +# files. These variables should only be used with the compiler and linker +# since they generate native path names. +# +# EXEEXT +# Select the executable extension based on the host type. This +# is a lightweight replacement for AC_EXEEXT that doesn't require +# a compiler. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_INIT], [ + TEA_VERSION="3.13" + + AC_MSG_CHECKING([TEA configuration]) + if test x"${PACKAGE_NAME}" = x ; then + AC_MSG_ERROR([ +The PACKAGE_NAME variable must be defined by your TEA configure.ac]) + fi + AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) + + # If the user did not set CFLAGS, set it now to keep macros + # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". + if test "${CFLAGS+set}" != "set" ; then + CFLAGS="" + fi + + case "`uname -s`" in + *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*) + AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *CYGWIN_*) + EXEEXT=".exe" + # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG + ;; + *) + CYGPATH=echo + # Maybe we are cross-compiling.... + case ${host_alias} in + *mingw32*) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *) + EXEEXT="" + TEA_PLATFORM="unix" + ;; + esac + ;; + esac + + # Check if exec_prefix is set. If not use fall back to prefix. + # Note when adjusted, so that TEA_PREFIX can correct for this. + # This is needed for recursive configures, since autoconf propagates + # $prefix, but not $exec_prefix (doh!). + if test x$exec_prefix = xNONE ; then + exec_prefix_default=yes + exec_prefix=$prefix + fi + + AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) + + AC_SUBST(EXEEXT) + AC_SUBST(CYGPATH) + + # This package name must be replaced statically for AC_SUBST to work + AC_SUBST(PKG_LIB_FILE) + AC_SUBST(PKG_LIB_FILE8) + AC_SUBST(PKG_LIB_FILE9) + # Substitute STUB_LIB_FILE in case package creates a stub library too. + AC_SUBST(PKG_STUB_LIB_FILE) + + # We AC_SUBST these here to ensure they are subst'ed, + # in case the user doesn't call TEA_ADD_... + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) + AC_SUBST(PKG_TCL_SOURCES) + AC_SUBST(PKG_HEADERS) + AC_SUBST(PKG_INCLUDES) + AC_SUBST(PKG_LIBS) + AC_SUBST(PKG_CFLAGS) + + # Configure the installer. + TEA_INSTALLER +]) + +#------------------------------------------------------------------------ +# TEA_ADD_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_SOURCES +# PKG_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_SOURCES], [ + vars="$@" + for i in $vars; do + case $i in + [\$]*) + # allow $-var names + PKG_SOURCES="$PKG_SOURCES $i" + PKG_OBJECTS="$PKG_OBJECTS $i" + ;; + *) + # check for existence - allows for generic/win/unix VPATH + # To add more dirs here (like 'src'), you have to update VPATH + # in Makefile.in as well + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find source file '$i']) + fi + PKG_SOURCES="$PKG_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_OBJECTS="$PKG_OBJECTS $j" + ;; + esac + done + AC_SUBST(PKG_SOURCES) + AC_SUBST(PKG_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_STUB_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_STUB_SOURCES +# PKG_STUB_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_STUB_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence - allows for generic/win/unix VPATH + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find stub source file '$i']) + fi + PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" + done + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_TCL_SOURCES -- +# +# Specify one or more Tcl source files. These should be platform +# independent runtime files. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_TCL_SOURCES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_TCL_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) + fi + PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" + done + AC_SUBST(PKG_TCL_SOURCES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_HEADERS -- +# +# Specify one or more source headers. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_HEADERS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_HEADERS], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find header file '${srcdir}/$i']) + fi + PKG_HEADERS="$PKG_HEADERS $i" + done + AC_SUBST(PKG_HEADERS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_INCLUDES -- +# +# Specify one or more include dirs. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_INCLUDES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_INCLUDES], [ + vars="$@" + for i in $vars; do + PKG_INCLUDES="$PKG_INCLUDES $i" + done + AC_SUBST(PKG_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_LIBS -- +# +# Specify one or more libraries. Users should check for +# the right platform before adding to their list. For Windows, +# libraries provided in "foo.lib" format will be converted to +# "-lfoo" when using GCC (mingw). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_LIBS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_LIBS], [ + vars="$@" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.[[lL]][[iI]][[bB]][$]/-l\1/'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + AC_SUBST(PKG_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CFLAGS -- +# +# Specify one or more CFLAGS. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_CFLAGS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CFLAGS], [ + PKG_CFLAGS="$PKG_CFLAGS $@" + AC_SUBST(PKG_CFLAGS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CLEANFILES -- +# +# Specify one or more CLEANFILES. +# +# Arguments: +# one or more file names to clean target +# +# Results: +# +# Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CLEANFILES], [ + CLEANFILES="$CLEANFILES $@" +]) + +#------------------------------------------------------------------------ +# TEA_PREFIX -- +# +# Handle the --prefix=... option by defaulting to what Tcl gave +# +# Arguments: +# none +# +# Results: +# +# If --prefix or --exec-prefix was not specified, $prefix and +# $exec_prefix will be set to the values given to Tcl when it was +# configured. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_PREFIX], [ + if test "${prefix}" = "NONE"; then + prefix_default=yes + if test x"${TCL_PREFIX}" != x; then + AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) + prefix=${TCL_PREFIX} + else + AC_MSG_NOTICE([--prefix defaulting to /usr/local]) + prefix=/usr/local + fi + fi + if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ + -o x"${exec_prefix_default}" = x"yes" ; then + if test x"${TCL_EXEC_PREFIX}" != x; then + AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) + exec_prefix=${TCL_EXEC_PREFIX} + else + AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) + exec_prefix=$prefix + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER_CC -- +# +# Do compiler checks the way we want. This is just a replacement +# for AC_PROG_CC in TEA configure.ac files to make them cleaner. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER_CC], [ + # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) + # in this macro, they need to go into TEA_SETUP_COMPILER instead. + + AC_PROG_CC + AC_PROG_CPP + + #-------------------------------------------------------------------- + # Checks to see if the make program sets the $MAKE variable. + #-------------------------------------------------------------------- + + AC_PROG_MAKE_SET + + #-------------------------------------------------------------------- + # Find ranlib + #-------------------------------------------------------------------- + + AC_CHECK_TOOL(RANLIB, ranlib) + + #-------------------------------------------------------------------- + # Determines the correct binary file extension (.o, .obj, .exe etc.) + #-------------------------------------------------------------------- + + AC_OBJEXT + AC_EXEEXT +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER -- +# +# Do compiler checks that use the compiler. This must go after +# TEA_SETUP_COMPILER_CC, which does the actual compiler check. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER], [ + # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. + AC_REQUIRE([TEA_SETUP_COMPILER_CC]) + + #------------------------------------------------------------------------ + # 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" -a -n "$GCC"; then + AC_CACHE_CHECK([if the compiler understands -pipe], + tcl_cv_cc_pipe, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[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 + + #-------------------------------------------------------------------- + # Common compiler flag setup + #-------------------------------------------------------------------- + + AC_C_BIGENDIAN +]) + +#------------------------------------------------------------------------ +# TEA_MAKE_LIB -- +# +# Generate a line that can be used to build a shared/unshared library +# in a platform independent manner. +# +# Arguments: +# none +# +# Requires: +# +# Results: +# +# Defines the following vars: +# CFLAGS - Done late here to note disturb other AC macros +# MAKE_LIB - Command to execute to build the Tcl library; +# differs depending on whether or not Tcl is being +# compiled as a shared library. +# MAKE_SHARED_LIB Makefile rule for building a shared library +# MAKE_STATIC_LIB Makefile rule for building a static library +# MAKE_STUB_LIB Makefile rule for building a stub library +# VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL +# VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_MAKE_LIB], [ + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then + MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" + 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+ + VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" + VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" + MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" + TEA_ADD_CLEANFILES([*.manifest]) + ]) + MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" + else + MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" + MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" + fi + + if test "${SHARED_BUILD}" = "1" ; then + MAKE_LIB="${MAKE_SHARED_LIB} " + else + MAKE_LIB="${MAKE_STATIC_LIB} " + fi + + #-------------------------------------------------------------------- + # Shared libraries and static libraries have different names. + # Use the double eval to make sure any variables in the suffix is + # substituted. (@@@ Might not be necessary anymore) + #-------------------------------------------------------------------- + + PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" + PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" + if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" == x; then + PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" + else + PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" + AC_DEFINE(TCL_MAJOR_VERSION, 8, [Compile for Tcl8?]) + fi + if test "${TEA_PLATFORM}" = "windows" ; then + if test "${SHARED_BUILD}" = "1" ; then + # We force the unresolved linking of symbols that are really in + # the private libraries of Tcl and Tk. + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" + fi + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" + if test "$GCC" = "yes"; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" + fi + eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + else + if test "$GCC" = "yes"; then + PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX} + fi + eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} + fi + # These aren't needed on Windows (either MSVC or gcc) + RANLIB=: + RANLIB_STUB=: + else + RANLIB_STUB="${RANLIB}" + if test "${SHARED_BUILD}" = "1" ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" + fi + eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + RANLIB=: + else + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi + + # These are escaped so that only CFLAGS is picked up at configure time. + # The other values will be substituted at make time. + CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" + if test "${SHARED_BUILD}" = "1" ; then + CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" + fi + + AC_SUBST(MAKE_LIB) + AC_SUBST(MAKE_SHARED_LIB) + AC_SUBST(MAKE_STATIC_LIB) + AC_SUBST(MAKE_STUB_LIB) + AC_SUBST(RANLIB_STUB) + AC_SUBST(VC_MANIFEST_EMBED_DLL) + AC_SUBST(VC_MANIFEST_EMBED_EXE) +]) + +#------------------------------------------------------------------------ +# TEA_LIB_SPEC -- +# +# Compute the name of an existing object library located in libdir +# from the given base name and produce the appropriate linker flags. +# +# Arguments: +# basename The base name of the library without version +# numbers, extensions, or "lib" prefixes. +# extra_dir Extra directory in which to search for the +# library. This location is used first, then +# $prefix/$exec-prefix, then some defaults. +# +# Requires: +# TEA_INIT and TEA_PREFIX must be called first. +# +# Results: +# +# Defines the following vars: +# ${basename}_LIB_NAME The computed library name. +# ${basename}_LIB_SPEC The computed linker flags. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LIB_SPEC], [ + AC_MSG_CHECKING([for $1 library]) + + # Look in exec-prefix for the library (defined by TEA_PREFIX). + + tea_lib_name_dir="${exec_prefix}/lib" + + # Or in a user-specified location. + + if test x"$2" != x ; then + tea_extra_lib_dir=$2 + else + tea_extra_lib_dir=NONE + fi + + for i in \ + `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do + if test -f "$i" ; then + tea_lib_name_dir=`dirname $i` + $1_LIB_NAME=`basename $i` + $1_LIB_PATH_NAME=$i + break + fi + done + + if test "${TEA_PLATFORM}" = "windows"; then + $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" + else + # Strip off the leading "lib" and trailing ".a" or ".so" + + tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` + $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" + fi + + if test "x${$1_LIB_NAME}" = x ; then + AC_MSG_ERROR([not found]) + else + AC_MSG_RESULT([${$1_LIB_SPEC}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TCL_HEADERS -- +# +# Locate the private Tcl include files +# +# Arguments: +# +# Requires: +# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has +# already been called. +# +# Results: +# +# Substitutes the following vars: +# TCL_TOP_DIR_NATIVE +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ + # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} + AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) + AC_MSG_CHECKING([for Tcl private include files]) + + TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` + TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" + + # Check to see if tclPort.h isn't already with the public headers + # Don't look for tclInt.h because that resides with tcl.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tclh}/tclWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tclh}/tclUnixPort.h"; then + result="private headers found with public headers" + else + TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" + if test "${TEA_PLATFORM}" = "windows"; then + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" + else + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TCL_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -d "${TCL_BIN_DIR}/Headers" -a \ + -d "${TCL_BIN_DIR}/PrivateHeaders"; then + TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" + else + TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TCL_INCLUDES}" + else + if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then + AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) + fi + result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" + fi + fi + + AC_SUBST(TCL_TOP_DIR_NATIVE) + + AC_SUBST(TCL_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TCL_HEADERS -- +# +# Locate the installed public Tcl header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tclinclude switch to configure. +# Result is cached. +# +# Substitutes the following vars: +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ + AC_MSG_CHECKING([for Tcl public headers]) + + AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tclh, [ + # Use the value from --with-tclinclude, if it was given + + if test x"${with_tclinclude}" != x ; then + if test -f "${with_tclinclude}/tcl.h" ; then + ac_cv_c_tclh=${with_tclinclude} + else + AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers directory + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tcl is not installed, + # and in that situation, look there before installed locations. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TCL_INCLUDE_SPEC}" != x ; then + d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tcl.h" ; then + ac_cv_c_tclh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tclh}" = x ; then + AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tclh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` + + TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TCL_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TK_HEADERS -- +# +# Locate the private Tk include files +# +# Arguments: +# +# Requires: +# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has +# already been called. +# +# Results: +# +# Substitutes the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ + # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} + AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) + AC_MSG_CHECKING([for Tk private include files]) + + TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` + TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" + + # Check to see if tkPort.h isn't already with the public headers + # Don't look for tkInt.h because that resides with tk.h in the core + # sources, but the Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tkh}/tkWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tkh}/tkUnixPort.h"; then + result="private headers found with public headers" + else + TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" + TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" + if test "${TEA_PLATFORM}" = "windows"; then + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" + else + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TK_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" + # Detect and add ttk subdir + if test -d "${TK_SRC_DIR}/generic/ttk"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" + fi + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -d "${TK_BIN_DIR}/Headers" -a \ + -d "${TK_BIN_DIR}/PrivateHeaders"; then + TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" + else + TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TK_INCLUDES}" + else + if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then + AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) + fi + result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" + fi + fi + + AC_SUBST(TK_TOP_DIR_NATIVE) + AC_SUBST(TK_XLIB_DIR_NATIVE) + + AC_SUBST(TK_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TK_HEADERS -- +# +# Locate the installed public Tk header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tkinclude switch to configure. +# Result is cached. +# +# Substitutes the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ + AC_MSG_CHECKING([for Tk public headers]) + + AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tkh, [ + # Use the value from --with-tkinclude, if it was given + + if test x"${with_tkinclude}" != x ; then + if test -f "${with_tkinclude}/tk.h" ; then + ac_cv_c_tkh=${with_tkinclude} + else + AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers directory. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tk is not installed, + # and in that situation, look there before installed locations. + if test -f "${TK_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tk's --prefix location, + # relative to directory of tkConfig.sh, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TK_PREFIX}/include 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TK_INCLUDE_SPEC}" != x ; then + d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tk.h" ; then + ac_cv_c_tkh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tkh}" = x ; then + AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tkh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` + + TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TK_INCLUDES) + + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + # On Windows and Aqua, we need the X compat headers + AC_MSG_CHECKING([for X11 header files]) + if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then + INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" + TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + AC_SUBST(TK_XINCLUDES) + fi + AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_CONFIG -- +# +# Locate the ${1}Config.sh file and perform a sanity check on +# the ${1} compile flags. These are used by packages like +# [incr Tk] that load *Config.sh files from more than Tcl and Tk. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-$1=... +# +# Defines the following vars: +# $1_BIN_DIR Full path to the directory containing +# the $1Config.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CONFIG], [ + # + # Ok, lets find the $1 configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-$1 + # + + if test x"${no_$1}" = x ; then + # we reset no_$1 in case something fails here + no_$1=true + AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) + AC_MSG_CHECKING([for $1 configuration]) + AC_CACHE_VAL(ac_cv_c_$1config,[ + + # First check to see if --with-$1 was specified. + if test x"${with_$1config}" != x ; then + case ${with_$1config} in + */$1Config.sh ) + if test -f ${with_$1config}; then + AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) + with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` + fi;; + esac + if test -f "${with_$1config}/$1Config.sh" ; then + ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` + else + AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) + fi + fi + + # then check for a private $1 installation + if test x"${ac_cv_c_$1config}" = x ; then + for i in \ + ../$1 \ + `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../$1 \ + `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../../$1 \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ${srcdir}/../$1 \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + if test -f "$i/unix/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i/unix; pwd)` + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_$1config}" = 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/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + done + fi + ]) + + if test x"${ac_cv_c_$1config}" = x ; then + $1_BIN_DIR="# no $1 configs found" + AC_MSG_WARN([Cannot find $1 configuration definitions]) + exit 0 + else + no_$1= + $1_BIN_DIR=${ac_cv_c_$1config} + AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG -- +# +# Load the $1Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1_BIN_DIR +# +# Results: +# +# Substitutes the following vars: +# $1_SRC_DIR +# $1_LIB_FILE +# $1_LIB_SPEC +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_CONFIG], [ + AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) + + if test -f "${$1_BIN_DIR}/$1Config.sh" ; then + AC_MSG_RESULT([loading]) + . "${$1_BIN_DIR}/$1Config.sh" + else + AC_MSG_RESULT([file not found]) + fi + + # + # If the $1_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 $1_LIB_SPEC will be set to the value + # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC + # instead of $1_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + # + + if test -f "${$1_BIN_DIR}/Makefile" ; then + AC_MSG_WARN([Found Makefile - using build library specs for $1]) + $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} + $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} + $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} + $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} + $1_LIBRARY_PATH=${$1_LIBRARY_PATH} + fi + + AC_SUBST($1_VERSION) + AC_SUBST($1_BIN_DIR) + AC_SUBST($1_SRC_DIR) + + AC_SUBST($1_LIB_FILE) + AC_SUBST($1_LIB_SPEC) + + AC_SUBST($1_STUB_LIB_FILE) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_PATH) + + # Allow the caller to prevent this auto-check by specifying any 2nd arg + AS_IF([test "x$2" = x], [ + # Check both upper and lower-case variants + # If a dev wanted non-stubs libs, this function could take an option + # to not use _STUB in the paths below + AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], + [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], + [TEA_LOAD_CONFIG_LIB($1_STUB)]) + ]) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG_LIB -- +# +# Helper function to load correct library from another extension's +# ${PACKAGE}Config.sh. +# +# Results: +# Adds to LIBS the appropriate extension library +#------------------------------------------------------------------------ +AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ + AC_MSG_CHECKING([For $1 library for LIBS]) + # This simplifies the use of stub libraries by automatically adding + # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, + # but this is called before CONFIG_CFLAGS. More importantly, this adds + # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. + if test "x${$1_LIB_SPEC}" != "x" ; then + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then + TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) + AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) + else + TEA_ADD_LIBS([${$1_LIB_SPEC}]) + AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) + fi + else + AC_MSG_RESULT([file not found]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_EXPORT_CONFIG -- +# +# Define the data to insert into the ${PACKAGE}Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1 +# +# Results: +# Substitutes the following vars: +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_EXPORT_CONFIG], [ + #-------------------------------------------------------------------- + # These are for $1Config.sh + #-------------------------------------------------------------------- + + # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) + eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" + if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then + eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}" + eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}" + else + eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`" + eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`" + fi + $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" + $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" + $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" + $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" + $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" + $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" + + AC_SUBST($1_BUILD_LIB_SPEC) + AC_SUBST($1_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_PATH) + AC_SUBST($1_STUB_LIB_PATH) + + AC_SUBST(MAJOR_VERSION) + AC_SUBST(MINOR_VERSION) + AC_SUBST(PATCHLEVEL) +]) + + +#------------------------------------------------------------------------ +# TEA_INSTALLER -- +# +# Configure the installer. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# INSTALL +# INSTALL_DATA_DIR +# INSTALL_DATA +# INSTALL_PROGRAM +# INSTALL_SCRIPT +# INSTALL_LIBRARY +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_INSTALLER], [ + INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' + INSTALL_DATA_DIR='${INSTALL} -d -m 755' + INSTALL_DATA='${INSTALL} -m 644' + INSTALL_PROGRAM='${INSTALL} -m 755' + INSTALL_SCRIPT='${INSTALL} -m 755' + + TEA_CONFIG_SYSTEM + case $system in + HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; + *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; + esac + + AC_SUBST(INSTALL) + AC_SUBST(INSTALL_DATA_DIR) + AC_SUBST(INSTALL_DATA) + AC_SUBST(INSTALL_PROGRAM) + AC_SUBST(INSTALL_SCRIPT) + AC_SUBST(INSTALL_LIBRARY) +]) + +### +# Tip 430 - ZipFS Modifications +### +#------------------------------------------------------------------------ +# TEA_ZIPFS_SUPPORT +# Locate a zip encoder installed on the system path, or none. +# +# Arguments: +# none +# +# Results: +# Substitutes the following vars: +# MACHER_PROG +# ZIP_PROG +# ZIP_PROG_OPTIONS +# ZIP_PROG_VFSSEARCH +# ZIP_INSTALL_OBJS +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ZIPFS_SUPPORT], [ + MACHER_PROG="" + ZIP_PROG="" + ZIP_PROG_OPTIONS="" + ZIP_PROG_VFSSEARCH="" + ZIP_INSTALL_OBJS="" + + AC_MSG_CHECKING([for macher]) + AC_CACHE_VAL(ac_cv_path_macher, [ + search_path=`echo ${PATH} | sed -e 's/:/ /g'` + for dir in $search_path ; do + for j in `ls -r $dir/macher 2> /dev/null` \ + `ls -r $dir/macher 2> /dev/null` ; do + if test x"$ac_cv_path_macher" = x ; then + if test -f "$j" ; then + ac_cv_path_macher=$j + break + fi + fi + done + done + ]) + if test -f "$ac_cv_path_macher" ; then + MACHER_PROG="$ac_cv_path_macher" + AC_MSG_RESULT([$MACHER_PROG]) + AC_MSG_RESULT([Found macher in environment]) + fi + AC_MSG_CHECKING([for zip]) + AC_CACHE_VAL(ac_cv_path_zip, [ + search_path=`echo ${PATH} | sed -e 's/:/ /g'` + for dir in $search_path ; do + for j in `ls -r $dir/zip 2> /dev/null` \ + `ls -r $dir/zip 2> /dev/null` ; do + if test x"$ac_cv_path_zip" = x ; then + if test -f "$j" ; then + ac_cv_path_zip=$j + break + fi + fi + done + done + ]) + if test -f "$ac_cv_path_zip" ; then + ZIP_PROG="$ac_cv_path_zip" + AC_MSG_RESULT([$ZIP_PROG]) + ZIP_PROG_OPTIONS="-rq" + ZIP_PROG_VFSSEARCH="*" + AC_MSG_RESULT([Found INFO Zip in environment]) + # Use standard arguments for zip + else + # It is not an error if an installed version of Zip can't be located. + # We can use the locally distributed minizip instead + ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}" + ZIP_PROG_OPTIONS="-o -r" + ZIP_PROG_VFSSEARCH="*" + ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}" + AC_MSG_RESULT([No zip found on PATH. Building minizip]) + fi + AC_SUBST(MACHER_PROG) + AC_SUBST(ZIP_PROG) + AC_SUBST(ZIP_PROG_OPTIONS) + AC_SUBST(ZIP_PROG_VFSSEARCH) + AC_SUBST(ZIP_INSTALL_OBJS) +]) + +# Local Variables: +# mode: autoconf +# End: diff --git a/src/vfs/critcl.vfs/lib/critcl-bitmap/bitmap.tcl b/src/vfs/critcl.vfs/lib/critcl-bitmap/bitmap.tcl new file mode 100644 index 00000000..fa54c5e2 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-bitmap/bitmap.tcl @@ -0,0 +1,228 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# n/a + +# CriTcl Utility Package for bitmap en- and decoder. +# Based on i-assoc. + +package provide critcl::bitmap 1.1.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.2 +package require critcl::iassoc + +namespace eval ::critcl::bitmap {} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Embed C Code + +proc critcl::bitmap::def {name dict {exclusions {}}} { + # dict: Tcl symbolic name -> (C bit-mask (1)) + # + # (Ad 1) Can be numeric, or symbolic, as long as it is a C int + # expression in the end. + # + # (Ad exclusions) + # Excluded bit-masks cannot be converted back to Tcl + # symbols. These are usually masks with multiple bits + # set. Conversion back delivers the individual elements + # instead of the combined mask. + # + # If no exclusions are specified the generated code is + # simpler, i.e. not containing anything for dealing with + # exclusions at runtime. + + # For the C level opt array we want the elements sorted alphabetically. + set symbols [lsort -dict [dict keys $dict]] + set i 0 + foreach s $symbols { + set id($s) $i + incr i + } + set last $i + + set hasexcl [llength $exclusions] + set excl {} + foreach e $exclusions { + dict set excl $e . + } + + dict for {sym mask} $dict { + set receivable [expr {![dict exists $excl $mask]}] + + set map [list @ID@ $id($sym) @SYM@ $sym @MASK@ $mask @RECV@ $receivable] + + if {$hasexcl} { + append init \n[critcl::at::here!][string map $map { + data->c [@ID@] = "@SYM@"; + data->mask [@ID@] = @MASK@; + data->recv [@ID@] = @RECV@; + data->tcl [@ID@] = Tcl_NewStringObj ("@SYM@", -1); + Tcl_IncrRefCount (data->tcl [@ID@]); + }] + } else { + append init \n[critcl::at::here!][string map $map { + data->c [@ID@] = "@SYM@"; + data->mask [@ID@] = @MASK@; + data->tcl [@ID@] = Tcl_NewStringObj ("@SYM@", -1); + Tcl_IncrRefCount (data->tcl [@ID@]); + }] + } + + append final \n[critcl::at::here!][string map $map { + Tcl_DecrRefCount (data->tcl [@ID@]); + }] + } + append init \n " data->c \[$last\] = NULL;" + + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + lappend map @LAST@ $last + + # I. Generate a header file for inclusion by other parts of the + # package, i.e. csources. Include the header here as well, for + # the following blocks of code. + # + # Declaration of the en- and decoder functions. + + critcl::include [critcl::make ${name}.h \n[critcl::at::here!][string map $map { + #ifndef @NAME@_HEADER + #define @NAME@_HEADER + + /* Encode a flag list into the corresponding bitset */ + extern int + @NAME@_encode (Tcl_Interp* interp, + Tcl_Obj* flags, + int* result); + + /* Decode a bitset into the corresponding flag list */ + extern Tcl_Obj* + @NAME@_decode (Tcl_Interp* interp, + int mask); + + #endif + }]] + + # II: Generate the interp association holding the various + # conversion maps. + + if {$hasexcl} { + critcl::iassoc def ${name}_iassoc {} \n[critcl::at::here!][string map $map { + const char* c [@LAST@+1]; /* Bit name, C string */ + Tcl_Obj* tcl [@LAST@]; /* Bit name, Tcl_Obj*, sharable */ + int mask [@LAST@]; /* Bit mask */ + int recv [@LAST@]; /* Flag, true for receivable event */ + }] $init $final + } else { + critcl::iassoc def ${name}_iassoc {} \n[critcl::at::here!][string map $map { + const char* c [@LAST@+1]; /* Bit name, C string */ + Tcl_Obj* tcl [@LAST@]; /* Bit name, Tcl_Obj*, sharable */ + int mask [@LAST@]; /* Bit mask */ + }] $init $final + } + + # III: Generate encoder function: Conversion of list of flag names + # into corresponding bitset. + + critcl::ccode \n[critcl::at::here!][string map $map { + int + @NAME@_encode (Tcl_Interp* interp, + Tcl_Obj* flags, + int* result) + { + @NAME@_iassoc_data context = @NAME@_iassoc (interp); + Tcl_Size lc, i; + int mask, id; + Tcl_Obj** lv; + + if (Tcl_ListObjGetElements (interp, flags, &lc, &lv) != TCL_OK) { /* OK tcl9 */ + return TCL_ERROR; + } + + mask = 0; + for (i = 0; i < lc; i++) { + if (Tcl_GetIndexFromObj (interp, lv[i], context->c, "@NAME@", 0, + &id) != TCL_OK) { + Tcl_SetErrorCode (interp, "@UNAME@", "FLAG", NULL); + return TCL_ERROR; + } + mask |= context->mask [id]; + } + + *result = mask; + return TCL_OK; + } + }] + + # IV: Generate decoder function: Convert bitset into the + # corresponding list of flag names. + + if {$hasexcl} { + critcl::ccode \n[critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@_decode (Tcl_Interp* interp, int mask) + { + int i; + @NAME@_iassoc_data context = @NAME@_iassoc (interp); + Tcl_Obj* res = Tcl_NewListObj (0, NULL); + + for (i = 0; i < @LAST@; i++) { + if (!context->recv[i]) continue; + if (!(mask & context->mask[i])) continue; + (void) Tcl_ListObjAppendElement (interp, res, context->tcl [i]); + } + return res; + } + }] + } else { + critcl::ccode \n[critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@_decode (Tcl_Interp* interp, int mask) + { + int i; + @NAME@_iassoc_data context = @NAME@_iassoc (interp); + Tcl_Obj* res = Tcl_NewListObj (0, NULL); + + for (i = 0; i < @LAST@; i++) { + if (!(mask & context->mask[i])) continue; + (void) Tcl_ListObjAppendElement (interp, res, context->tcl [i]); + } + return res; + } + }] + } + + # V. Define convenient argument- and result-type definitions + # wrapping the de- and encoder functions for use by cprocs. + + critcl::argtype $name \n[critcl::at::here!][string map $map { + if (@NAME@_encode (interp, @@, &@A) != TCL_OK) return TCL_ERROR; + }] int int + + critcl::resulttype $name \n[critcl::at::here!][string map $map { + /* @NAME@_decode result is 0-refcount */ + Tcl_SetObjResult (interp, @NAME@_decode (interp, rv)); + return TCL_OK; + }] int +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::bitmap { + namespace export def + catch { namespace ensemble create } +} + +namespace eval ::critcl { + namespace export bitmap + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-bitmap/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-bitmap/pkgIndex.tcl new file mode 100644 index 00000000..2accc5bd --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-bitmap/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::bitmap 1.1.1 [list source [file join $dir bitmap.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-callback/c/callback.c b/src/vfs/critcl.vfs/lib/critcl-callback/c/callback.c new file mode 100644 index 00000000..04007bf4 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-callback/c/callback.c @@ -0,0 +1,114 @@ +/* + * Callback - Implementation + */ + +#include + +#include +#include +#include + +TRACE_ON; + +/* + * API + */ + +critcl_callback_p +critcl_callback_new (Tcl_Interp* interp, Tcl_Size objc, Tcl_Obj** objv, Tcl_Size nargs) +{ + TRACE_FUNC ("((Interp*) %p, objc %d, (Tcl_Obj**) %p, nargs %d)", + interp, objc, objv, nargs); + + critcl_callback_p c = ALLOC (critcl_callback); + int total = objc + nargs; + c->nfixed = objc; + c->nargs = nargs; + c->command = NALLOC (Tcl_Obj*, total); + c->interp = interp; + + int i; + for (i = 0; i < objc; i++) { + TRACE ("D [%3d] = (TclObj*) %p = '%s'", i, objv [i], Tcl_GetString (objv [i])); + c->command [i] = objv [i]; + Tcl_IncrRefCount (objv [i]); + } + for (; i < total; i++) { + TRACE ("D [%3d] = n/a", i); + c->command [i] = 0; + } + + TRACE_RETURN ("(critcl_callback_p) %p", c); +} + +void +critcl_callback_extend (critcl_callback_p callback, Tcl_Obj* argument) +{ + TRACE_FUNC ("((critcl_callback_p) %p, (Tcl_Obj*) %p)", callback, argument); + ASSERT (callback->nargs > 0, "No arguments left to use for extension"); + + TRACE ("E [%3d] = (TclObj*) %p = '%s'", callback->nfixed, argument, Tcl_GetString (argument)); + + callback->command [callback->nfixed] = argument; + Tcl_IncrRefCount (argument); + + callback->nargs --; + callback->nfixed ++; + + TRACE_RETURN_VOID; +} + +void +critcl_callback_destroy (critcl_callback_p callback) +{ + TRACE_FUNC ("((critcl_callback_p) %p)", callback); + + int i; + for (i = callback->nfixed-1; i > 0; i--) { + Tcl_DecrRefCount (callback->command [i]); + } + FREE (callback->command); + FREE (callback); + + TRACE_RETURN_VOID; +} + +int +critcl_callback_invoke (critcl_callback_p callback, Tcl_Size objc, Tcl_Obj** objv) +{ + TRACE_FUNC ("((critcl_callback_p) %p, objc %d, (Tcl_Obj**) %p)", callback, objc, objv); + ASSERT (objc <= callback->nargs, "Too many arguments"); + + Tcl_Size i, j; + + for (i = 0; i < callback->nfixed; i++) { + TRACE ("I [%3d] = (TclObj*) %p = '%s'", i, callback->command [i], Tcl_GetString (callback->command [i])); + Tcl_IncrRefCount (callback->command [i]); + } + for (i = callback->nfixed, j = 0 ; j < objc; i++, j++) { + TRACE ("I [%3d] = (TclObj*) %p = '%s'", i, objv [j], Tcl_GetString (objv [j])); + Tcl_IncrRefCount (objv [j]); + callback->command [i] = objv [j]; + } + + int res = Tcl_EvalObjv (callback->interp, i, callback->command, TCL_EVAL_GLOBAL); /* OK tcl9 */ + + for (i = 0; i < callback->nfixed; i++) { + Tcl_DecrRefCount (callback->command [i]); + } + for (j = 0 ; j < objc; j++) { + Tcl_DecrRefCount (objv [j]); + } + + TRACE ("R (Tcl_Obj*) %p = '%s'", Tcl_GetObjResult (callback->interp), + Tcl_GetString (Tcl_GetObjResult (callback->interp))); + TRACE_RETURN ("(int) %d", res); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-callback/c/callback.h b/src/vfs/critcl.vfs/lib/critcl-callback/c/callback.h new file mode 100644 index 00000000..77e86b27 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-callback/c/callback.h @@ -0,0 +1,22 @@ +#ifndef CRITCL_CALLBACK_H +#define CRITCL_CALLBACK_H + +/* + * critcl callback class - declarations + * + * Opaque instance information and Tcl 8/9 compatibility layer. + */ + +#include /* tcl.h + Portability Tcl <=8.6 */ + +typedef struct critcl_callback* critcl_callback_p; + +#endif + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-callback/c/callback_int.h b/src/vfs/critcl.vfs/lib/critcl-callback/c/callback_int.h new file mode 100644 index 00000000..7e1b60ca --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-callback/c/callback_int.h @@ -0,0 +1,28 @@ +#ifndef CRITCL_CALLBACK_INT_H +#define CRITCL_CALLBACK_INT_H +/* + * critcl callback class - internal declarations + * + * Instance information. + */ + +#include + +typedef struct critcl_callback { + + Tcl_Size nfixed; // Number of elements in the command prefix + Tcl_Size nargs; // Number of elements to reserve for the command arguments + Tcl_Obj** command; // Array for the command elements, prefix and arguments + Tcl_Interp* interp; // The Tcl interpreter to run the command in + +} critcl_callback; + +#endif + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-callback/callback.tcl b/src/vfs/critcl.vfs/lib/critcl-callback/callback.tcl new file mode 100644 index 00000000..46e55f37 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-callback/callback.tcl @@ -0,0 +1,109 @@ +# callback.tcl - +# +# C support package for the management of callbacks into Tcl. +# +# __Note__, this package does not expose anything at Tcl level. It +# only provides stubs (i.e. functions) and data structures providing +# C-level callback managers. + +package provide critcl::callback 1.1 + +package require critcl 3.2 +critcl::buildrequirement { + package require critcl::cutil ;# assertions, allocation support, tracing +} + +if {![critcl::compiling]} { + error "Unable to build `critcl::callback`, no proper compiler found." +} + +# # ## ### ##### ######## ############# +## Build configuration +# (1) Assertions, and tracing +# (2) Debugging symbols, memory tracking + +critcl::cutil::assertions off +critcl::cutil::tracer off + +#critcl::debug symbols + +#Activate when in need of memory debugging - Valgrind is an alternative +#critcl::debug symbols memory + +critcl::config lines 1 +critcl::config trace 0 + +# # ## ### ##### ######## ############# +## Administrivia + +critcl::license \ + {Andreas Kupries} \ + {Under a BSD license.} + +critcl::summary \ + {Critcl utility package providing functions and structures to manage callbacks into Tcl, from C} + +critcl::description \ + {Part of Critcl} + +critcl::subject critcl callbacks {management of callbacks} +critcl::subject {Tcl callbacks from C} + +# # ## ### ##### ######## ############# +## Implementation. + +critcl::cutil::alloc + +# # ## ### ##### ######## ############# + +critcl::cheaders c/*.h +critcl::csources c/*.c + +# Stubs definitions. + +critcl::api header c/callback.h + +# Create a new callback instance with prefix objc/objv and space for +# `nargs` arguments. The callback keeps the objv elements as is and +# signal this by incrementing their reference counts. The callback +# will be run in the provided interpreter, at the global level and +# namespace. + +critcl::api function critcl_callback_p critcl_callback_new { + Tcl_Interp* interp + Tcl_Size objc + Tcl_Obj** objv + Tcl_Size nargs +} + +# Modify the specified callback by placing the argument into the first +# free argument slot. This extends the prefix part of the callback, +# and reduces the argument part, by one. + +critcl::api function void critcl_callback_extend { + critcl_callback_p callback + Tcl_Obj* argument +} + +# Release all memory associated with the callback instance. For the +# objv elements saved during construction (see above) this is signaled +# by decrementing their reference counts. + +critcl::api function void critcl_callback_destroy { + critcl_callback_p callback +} + +# Invoke the callback using the objc/objv elements as the arguments. +# The operation will panic or crash if more arguments are provided +# than the callback has space for. See the `nargs` parameter of the +# constructor function above. Less arguments then constructed for +# however are ok. + +critcl::api function int critcl_callback_invoke { + critcl_callback_p callback + Tcl_Size objc + Tcl_Obj** objv +} + +## +return diff --git a/src/vfs/critcl.vfs/lib/critcl-class/class.h b/src/vfs/critcl.vfs/lib/critcl-class/class.h new file mode 100644 index 00000000..339c95c1 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-class/class.h @@ -0,0 +1,468 @@ +/* + * For package "@package@". + * Implementation of Tcl Class "@class@". + * + * Flags: @buildflags@ + */ + +#ifndef @stem@_IMPLEMENTATION +#define @stem@_IMPLEMENTATION (1) +/* # # ## ### ##### ######## ############# ##################### */ + +@includes@ +#line 14 "class.h" +/* + * Instance method names and enumeration. + */ + +static CONST char* @stem@_methodnames [] = { +@method_names@ +#line 21 "class.h" + NULL +}; + +typedef enum @stem@_methods { +@method_enumeration@ +#line 27 "class.h" +} @stem@_methods; + +/* + * Class method names and enumeration. + */ + +static CONST char* @stem@_class_methodnames [] = { + "create", + "new",@class_method_names@ +#line 37 "class.h" + NULL +}; + +typedef enum @stem@_classmethods { + @stem@_CM_create, + @stem@_CM_new@class_method_enumeration@ +#line 44 "class.h" +} @stem@_classmethods; + +/* + * Class structures I. Class variables. + */ + +typedef struct @classtype@__ { +@ctypedecl@ +#line 53 "class.h" +} @classtype@__; +typedef struct @classtype@__* @classtype@; + +/* + * Class structures II. Creation management. + */ + +typedef struct @classtype@_mgr_ { +@classmgrstruct@ +#line 63 "class.h" + @classtype@__ user; /* User-specified class variables */ +} @classtype@_mgr_; +typedef struct @classtype@_mgr_* @classtype@_mgr; + +/* + * Instance structure. + */ + +@itypedecl@ +#line 73 "class.h" + +/* # # ## ### ##### ######## User: General support */ +@support@ +#line 77 "class.h" +/* # # ## ### ##### ######## */ + +/* + * Class support functions. + */ + +static void +@stem@_ClassRelease (ClientData cd, Tcl_Interp* interp) +{ + @classtype@_mgr classmgr = (@classtype@_mgr) cd; + @classtype@ class = &classmgr->user; + @classdestructor@ +#line 90 "class.h" + ckfree((char*) cd); +} + +static @classtype@_mgr +@stem@_Class (Tcl_Interp* interp) +{ +#define KEY "@package@/@class@" + + Tcl_InterpDeleteProc* proc = @stem@_ClassRelease; + @classtype@_mgr classmgr; + @classtype@ class; + + classmgr = Tcl_GetAssocData (interp, KEY, &proc); + if (classmgr) { + return classmgr; + } + + classmgr = (@classtype@_mgr) ckalloc (sizeof (@classtype@_mgr_)); +@classmgrsetup@ +#line 110 "class.h" + class = &classmgr->user; + + @classconstructor@ +#line 114 "class.h" + + Tcl_SetAssocData (interp, KEY, proc, (ClientData) classmgr); + return classmgr; + error: + ckfree ((char*) classmgr); + return NULL; +#undef KEY +} +@classmgrnin@ +#line 124 "class.h" +/* # # ## ### ##### ######## */ + +static @instancetype@ +@stem@_Constructor (Tcl_Interp* interp, + @classtype@ class, + Tcl_Size objcskip, + Tcl_Size objc, + Tcl_Obj*const* objv) +{ +@ivardecl@; + /* # # ## ### ##### ######## User: Constructor */ + @constructor@ +#line 137 "class.h" + /* # # ## ### ##### ######## */ + return instance; +@ivarerror@; +#line 141 "class.h" +} + +static void +@stem@_PostConstructor (Tcl_Interp* interp, + @instancetype@ instance, + Tcl_Command cmd, + Tcl_Obj* fqn) +{ + /* # # ## ### ##### ######## User: Post Constructor */ + @postconstructor@ +#line 152 "class.h" + /* # # ## ### ##### ######## */ +} + +static void +@stem@_Destructor (ClientData clientData) +{ + @instancetype@ instance = (@instancetype@) clientData; + /* # # ## ### ##### ######## User: Destructor */ + @destructor@ +#line 162 "class.h" + /* # # ## ### ##### ######## */ +@ivarrelease@; +#line 165 "class.h" +} + +/* # # ## ### ##### ######## User: Methods */ +@method_implementations@ +#line 170 "class.h" +/* # # ## ### ##### ######## */ + +/* + * Instance command, method dispatch + */ + +static int +@stem@_InstanceCommand (ClientData clientData, + Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + @instancetype@ instance = (@instancetype@) clientData; + int mcode; + + if (objc < 2) { + Tcl_WrongNumArgs (interp, objc, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } else if (Tcl_GetIndexFromObj (interp, objv [1], + (const char**) @stem@_methodnames, + "option", 0, &mcode) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Dispatch to methods. They check the #args in detail before performing + * the requested functionality + */ + + switch ((@stem@_methods) mcode) { +@method_dispatch@ +#line 202 "class.h" + } + /* Not coming to this place */ + return TCL_ERROR; +} + +@cconscmd@ +#line 209 "class.h" +@capiclassvaraccess@ +#line 211 "class.h" +@tclconscmd@ +#line 213 "class.h" +/* # # ## ### ##### ######## User: Class Methods */ +@class_method_implementations@ +#line 216 "class.h" +@classcommand@ +#line 218 "class.h" +/* # # ## ### ##### ######## ############# ##################### */ +#endif /* @stem@_IMPLEMENTATION */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + +#line 230 "class.h" + const char* name; /* Class name, for debugging */ + long int counter; /* Id generation counter */ + char buf [sizeof("@class@")+20]; /* Stash for the auto-generated object names. */ + + classmgr->name = "@stem@"; + classmgr->counter = 0; + +#line 238 "class.h" +static CONST char* +@stem@_NewInstanceName (@classtype@_mgr classmgr) +{ + classmgr->counter ++; + sprintf (classmgr->buf, "@class@%ld", classmgr->counter); + return classmgr->buf; +} + +#line 247 "class.h" +/* # # ## ### ##### ######## */ +/* + * Tcl API :: Class command, class method, especially instance construction. + */ + +int +@stem@_ClassCommand (ClientData clientData, + Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + @classtype@_mgr classmgr; + @classtype@ class; + int mcode; + + if (objc < 2) { + Tcl_WrongNumArgs (interp, 0, objv, "method ?args...?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj (interp, objv [1], + (const char**) @stem@_class_methodnames, + "option", 0, &mcode) != TCL_OK) { + return TCL_ERROR; + } + + classmgr = @stem@_Class (interp); + if (!classmgr) { + return TCL_ERROR; + } + class = &classmgr->user; + + /* + * Dispatch to methods. They check the #args in detail before performing + * the requested functionality + */ + + switch ((@stem@_classmethods) mcode) { + case @stem@_CM_create: return @stem@_CM_createCmd (classmgr, interp, objc, objv); break; + case @stem@_CM_new: return @stem@_CM_newCmd (classmgr, interp, objc, objv); break;@class_method_dispatch@ +#line 288 "class.h" + } + /* Not coming to this place */ + return TCL_ERROR; +} + +#line 294 "class.h" +/* # # ## ### ##### ########: Predefined class methods */ +static int +@stem@_NewInstance (const char* name, + @classtype@_mgr classmgr, + Tcl_Interp* interp, + Tcl_Size objcskip, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + @instancetype@ instance; + Tcl_Obj* fqn; + Tcl_CmdInfo ci; + Tcl_Command cmd; + + /* + * Compute the fully qualified command name to use, putting + * the command into the current namespace if necessary. + */ + + if (!Tcl_StringMatch (name, "::*")) { + /* Relative name. Prefix with current namespace */ + + Tcl_Eval (interp, "namespace current"); + fqn = Tcl_GetObjResult (interp); + fqn = Tcl_DuplicateObj (fqn); + Tcl_IncrRefCount (fqn); + + if (!Tcl_StringMatch (Tcl_GetString (fqn), "::")) { + Tcl_AppendToObj (fqn, "::", -1); + } + Tcl_AppendToObj (fqn, name, -1); + } else { + fqn = Tcl_NewStringObj (name, -1); + Tcl_IncrRefCount (fqn); + } + Tcl_ResetResult (interp); + + /* + * Check if the commands exists already, and bail out if so. + * We will not overwrite an existing command. + */ + + if (Tcl_GetCommandInfo (interp, Tcl_GetString (fqn), &ci)) { + Tcl_Obj* err; + + err = Tcl_NewObj (); + Tcl_AppendToObj (err, "command \"", -1); + Tcl_AppendObjToObj (err, fqn); + Tcl_AppendToObj (err, "\" already exists, unable to create @class@ instance", -1); + + Tcl_DecrRefCount (fqn); + Tcl_SetObjResult (interp, err); + return TCL_ERROR; + } + + /* + * Construct instance state, and command. + */ + + instance = @stem@_Constructor (interp, &classmgr->user, objcskip, objc, objv); + if (!instance) { + return TCL_ERROR; + } + + cmd = Tcl_CreateObjCommand2 (interp, Tcl_GetString (fqn), + @stem@_InstanceCommand, + (ClientData) instance, + @stem@_Destructor); + + @stem@_PostConstructor (interp, instance, cmd, fqn); + + Tcl_SetObjResult (interp, fqn); + Tcl_DecrRefCount (fqn); + return TCL_OK; +} + +static int +@stem@_CM_createCmd (@classtype@_mgr classmgr, + Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + /* create ... */ + char* name; + + if (objc < 3) { + Tcl_WrongNumArgs (interp, 1, objv, "name ?args...?"); + return TCL_ERROR; + } + + name = Tcl_GetString (objv [2]); + + objc -= 3; + objv += 3; + + return @stem@_NewInstance (name, classmgr, interp, 3, objc, objv); +} + +static int +@stem@_CM_newCmd (@classtype@_mgr classmgr, + Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + /* new ... */ + const char* name; + + if (objc < 2) { + Tcl_WrongNumArgs (interp, 1, objv, "?args...?"); + return TCL_ERROR; + } + + objc -= 2; + objv += 2; + + name = @stem@_NewInstanceName (classmgr); + return @stem@_NewInstance (name, classmgr, interp, 2, objc, objv); +} + +#line 414 "class.h" +/* # # ## ### ##### ######## */ +/* + * C API :: Instance (de)construction, dispatch + */ + +typedef struct @instancetype@__ @capiprefix@; +typedef struct @capiprefix@* @capiprefix@_p; + +@capiprefix@_p +@capiprefix@_new (Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + @classtype@_mgr classmgr = @stem@_Class (interp); + @instancetype@ instance; + + /* + * Construct instance state + */ + + instance = @stem@_Constructor (interp, &classmgr->user, 0, objc, objv); + if (!instance) { + return NULL; + } + + @stem@_PostConstructor (interp, instance, 0, 0); + + return (@capiprefix@_p) instance; +} + +void +@capiprefix@_destroy (@capiprefix@_p instance) +{ + @stem@_Destructor (instance); +} + +int +@capiprefix@_invoke (@capiprefix@_p instance, + Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv) +{ + Tcl_Obj** v = (Tcl_Obj**) ckalloc ((objc+1)*sizeof (Tcl_Obj*)); + Tcl_Obj* i = Tcl_NewStringObj ("@capiprefix@", sizeof ("@capiprefix@")-1); + Tcl_IncrRefCount (i); + + v[0] = i; + memcpy (v+1, objv, objc * sizeof (Tcl_Obj*)); + + int r = @stem@_InstanceCommand (instance, interp, objc+1, v); + + Tcl_DecrRefCount (i); + ckfree ((char*) v); + return r; +} diff --git a/src/vfs/critcl.vfs/lib/critcl-class/class.tcl b/src/vfs/critcl.vfs/lib/critcl-class/class.tcl new file mode 100644 index 00000000..5f4d91bd --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-class/class.tcl @@ -0,0 +1,1171 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# @mdgen OWNER: class.h + +# CriTcl Utility Commands. Specification of a command representing a +# class made easy, with code for object command and method dispatch +# generated. + +package provide critcl::class 1.2.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.1.17 ; # Need 'meta?' to get the package name. + # Need 'name2c' returning 4 values. + # Need 'Deline' helper. + # Need cproc -tracename +package require critcl::util ; # Use the package's Get/Put commands. + +namespace eval ::critcl::class {} + +# # ## ### ##### ######## ############# ##################### +## API: Generate the declaration and implementation files for the class. + +proc ::critcl::class::define {classname script} { + variable state + + # Structure of the specification database + # + # TODO: Separate the spec::Process results from the template placeholders. + # TODO: Explain the various keys + # + # NOTE: All toplevel keys go into the map + # used to configure the template file (class.h). + # See `GenerateCode` and `MakeMap`. + # + # The various `Process*` procedures are responsible + # for converting the base specification delivered by + # `spec::Process` into the placeholders expected by + # template + ## + # state = dict << + # tcl-api -> bool + # c-api -> bool + # capiprefix -> string + # buildflags -> string + # classmgrstruct -> string + # classmgrsetup -> string + # classmgrnin -> string + # classcommand -> string + # tclconscmd -> string + # package -> string + # class -> string + # stem -> string + # classtype -> string (C type class structure) + # (class)method -> dict << + # names -> list (string) + # def -> (name) -> << + # enum + # case + # code + # syntax + # >> + # typedef -> ^instancetype + # menum -> + # typekey -> + # prefix -> ''|'class_' (see *1*) + # startn -> + # starte -> + # >> + # (class)variable -> dict << + # names -> list (string) + # def -> (name) -> << + # ctype -> + # loc -> + # comment -> + # >> + # >> + # stop -> bool|presence + # includes -> string (C code fragment) + # include -> + # instancetype -> + # ivardecl -> string (C code fragment) + # ivarrelease -> string (C code fragment) + # ivarerror -> string (C code fragment) + # itypedecl -> string (C code fragment, instance type) + # ctypedecl -> string (C code fragment, class type) + # *1*, (class_)method.prefix use + # (class_)method_names + # (class_)method_enumeration + # (class_)method_dispatch + # (class_)method_implementations + # >> + + catch { unset state } + + # Arguments: + # - name of the Tcl command representing the class. + # May contain namespace qualifiers. Represented by a ccommand. + # - script specifying the state structure and methods. + + #puts "=== |$classname|" + #puts "--- $script" + + # Pull the package we are working on out of the system. + + set package [critcl::meta? name] + set qpackage [expr {[string match ::* $package] + ? "$package" + : "::$package"}] + lassign [uplevel 1 [list ::critcl::name2c $classname]] ns cns classname cclassname + lassign [uplevel 1 [list ::critcl::name2c $qpackage]] pns pcns package cpackage + + #puts "%%% pNS |$pns|" + #puts "%%% Pkg |$package|" + #puts "%%% pCNS |$pcns|" + #puts "%%% cPkg |$cpackage|" + + #puts "%%% NS |$ns|" + #puts "%%% CName |$classname|" + #puts "%%% CNS |$cns|" + #puts "%%% CCName|$cclassname|" + + set stem ${pcns}${cpackage}_$cns$cclassname + + dict set state tcl-api 1 + dict set state c-api 0 + dict set state capiprefix $cns$cclassname + dict set state package $pns$package + dict set state class $ns$classname + dict set state stem $stem + dict set state classtype ${stem}_CLASS + dict set state method names {} + dict set state classmethod names {} + + # Check if the 'info frame' information for 'script' passes through properly. + spec::Process $script + + #puts "@@@ <<$state>>" + + ProcessFlags + ProcessIncludes + ProcessExternalType + ProcessInstanceVariables + ProcessClassVariables + + ProcessMethods method + ProcessMethods classmethod + + ProcessFragment classconstructor "\{\n" " " "\}" + ProcessFragment classdestructor "\{\n" " " "\}" + ProcessFragment constructor "\{\n" " " "\}" + ProcessFragment postconstructor "\{\n" " " "\}" + ProcessFragment destructor "\{\n" " " "\}" + ProcessFragment support "" \n "" + + GenerateCode + + unset state + return +} + +proc ::critcl::class::ProcessFlags {} { + variable state + set flags {} + foreach key {tcl-api c-api} { + if {![dict get $state $key]} continue + lappend flags $key + } + if {![llength $flags]} { + return -code error "No APIs to generate found. Please activate at least one API." + } + + dict set state buildflags [join $flags {, }] + critcl::msg "\n\tClass flags: $flags" + return +} + +proc ::critcl::class::ProcessIncludes {} { + variable state + if {[dict exists $state include]} { + ProcessFragment include "#include <" "\n" ">" + dict set state includes [dict get $state include] + dict unset state include + } else { + dict set state includes {/* No inclusions */} + } + return +} + +proc ::critcl::class::ProcessExternalType {} { + variable state + if {![dict exists $state instancetype]} return + + # Handle external C type for instances. + set itype [dict get $state instancetype] + dict set state ivardecl " $itype instance" + dict set state ivarrelease "" + dict set state ivarerror "error:\n return NULL;" + dict set state itypedecl "/* External type for instance state: $itype */" + + # For ProcessMethods + dict set state method typedef $itype + return +} + +proc ::critcl::class::ProcessInstanceVariables {} { + variable state + + if {![dict exists $state variable]} { + if {![dict exists $state instancetype]} { + # We have neither external type, nor instance variables. + # Fake ourselves out, recurse. + dict set state variable names {} + ProcessInstanceVariables itype + return + } + + # For ProcessMethods + dict set state method menum M_EMPTY + dict set state method typekey @instancetype@ + dict set state method prefix {} + dict set state method startn {} + dict set state method starte {} + return + } + + # Convert the set of instance variables (which can be empty) into + # a C instance structure type declaration, plus variable name. + + set itype [dict get $state stem]_INSTANCE + + set decl {} + lappend decl "typedef struct ${itype}__ \{" + + foreach fname [dict get $state variable names] { + set ctype [dict get $state variable def $fname ctype] + set vloc [dict get $state variable def $fname loc] + set comment [dict get $state variable def $fname comment] + + set field "$vloc $ctype $fname;" + if {$comment ne {}} { + append field " /* $comment */" + } + lappend decl $field + } + + lappend decl "\} ${itype}__;" + lappend decl "typedef struct ${itype}__* $itype;" + + dict set state instancetype $itype + dict set state ivardecl " $itype instance = ($itype) ckalloc (sizeof (${itype}__))" + dict set state ivarerror "error:\n ckfree ((char*) instance);\n return NULL;" + dict set state ivarrelease " ckfree ((char*) instance)" + dict set state itypedecl [join $decl \n] + + # For ProcessMethods + dict set state method typedef $itype + dict set state method menum M_EMPTY + dict set state method typekey @instancetype@ + dict set state method prefix {} + dict set state method startn {} + dict set state method starte {} + return +} + +proc ::critcl::class::ProcessClassVariables {} { + variable state + + # For ProcessMethods + dict set state classmethod typedef [dict get $state classtype] + dict set state classmethod menum {} + dict set state classmethod typekey @classtype@ + dict set state classmethod prefix class_ + dict set state classmethod startn "\n" + dict set state classmethod starte ",\n" + dict set state ctypedecl {} + + dict set state capiclassvaraccess {} + + if {![dict exists $state classvariable]} { + # Some compilers are unable to handle a structure without + # members (notably ANSI C89 Solaris, AIX). Taking the easy way + # out here, adding a dummy element. A more complex solution + # would be to ifdef the empty structure out of the system. + + dict set state ctypedecl {int __dummy__;} + return + } + + # Convert class variables into class type field declarations. + + set decl {} + lappend decl "/* # # ## ### ##### ######## User: Class variables */" + + if {[dict get $state c-api]} { + lappend acc "/* # # ## ### ##### ######## User: C-API :: Class variable accessors */\n" + } + + foreach fname [dict get $state classvariable names] { + set ctype [dict get $state classvariable def $fname ctype] + set vloc [dict get $state classvariable def $fname loc] + set comment [dict get $state classvariable def $fname comment] + + set field "$vloc$ctype $fname;" + if {$comment ne {}} { + append field " /* $comment */" + } + lappend decl $field + + # If needed, generate accessor functions for all class variables, + # i.e setters and getters. + + if {[dict get $state c-api]} { + lappend acc "$ctype @capiprefix@_${fname}_get (Tcl_Interp* interp) \{" + lappend acc " return @stem@_Class (interp)->user.$fname;" + lappend acc "\}" + lappend acc "" + lappend acc "void @capiprefix@_${fname}_set (Tcl_Interp* interp, $ctype v) \{" + lappend acc " @stem@_Class (interp)->user.$fname = v;" + lappend acc "\}" + } + } + + lappend decl "/* # # ## ### ##### ######## */" + + dict set state ctypedecl " [join $decl "\n "]\n" + + if {[dict get $state c-api]} { + dict set state capiclassvaraccess [join $acc \n] + } + return +} + +proc ::critcl::class::Max {v s} { + upvar 1 $v max + set l [string length $s] + if {$l < $max} return + set max $l + return +} + +proc ::critcl::class::ProcessMethods {key} { + variable state + # Process method declarations. Ensure that the names are listed in + # alphabetical order, to be nice. + + # From Process(Instance|Class)Variables + set pfx [dict get $state $key prefix] + set stn [dict get $state $key startn] + set ste [dict get $state $key starte] + + if {[dict exists $state $key names] && + [llength [dict get $state $key names]]} { + set map [list @stem@ [dict get $state stem] \ + [dict get $state $key typekey] \ + [dict get $state $key typedef]] + + set maxe 0 + set maxn 0 + foreach name [lsort -dict [dict get $state $key names]] { + Max maxn $name + Max maxe [dict get $state $key def $name enum] + } + incr maxn 3 + + foreach name [lsort -dict [dict get $state $key names]] { + set enum [string map $map [dict get $state $key def $name enum]] + set case [string map $map [dict get $state $key def $name case]] + set code [string map $map [dict get $state $key def $name code]] + set syntax [string map $map [dict get $state $key def $name syntax]] + + lappend names "[format %-${maxn}s \"$name\",] $syntax" + lappend enums "[format %-${maxe}s $enum] $syntax" + regexp {(:.*)$} $case tail + set case "case [format %-${maxe}s $enum]$tail" + lappend cases $case + lappend codes $code + } + + dict set state ${pfx}method_names "${stn} [join $names "\n "]" + dict set state ${pfx}method_enumeration "${ste} [join $enums ",\n "]" + dict set state ${pfx}method_dispatch "${stn}\t[join $cases \n\t]" + dict set state ${pfx}method_implementations [join $codes \n\n] + } else { + set enums [dict get $state $key menum] + if {[llength $enums]} { + set enums "${ste} [join $enums ",\n "]" + } + + dict set state ${pfx}method_names {} + dict set state ${pfx}method_enumeration $enums + dict set state ${pfx}method_dispatch {} + dict set state ${pfx}method_implementations {} + } + + + dict unset state $key + return +} + +proc ::critcl::class::ProcessFragment {key prefix sep suffix} { + # Process code fragments into a single block, if any. + # Ensure it exists, even if empty. Required by template. + # Optional in specification. + + variable state + if {![dict exists $state $key]} { + set new {} + } else { + set new ${prefix}[join [dict get $state $key] $suffix$sep$prefix]$suffix + } + dict set state $key $new + return +} + +proc ::critcl::class::GenerateCode {} { + variable state + + set stem [dict get $state stem] + set class [dict get $state class] + set hdr ${stem}_class.h + set header [file join [critcl::cache] $hdr] + + file mkdir [critcl::cache] + set template [critcl::Deline [Template class.h]] + #puts T=[string length $template] + + # Note, the template file is many files/parts, separated by ^Z + lassign [split $template \x1a] \ + template mgrstruct mgrsetup newinsname classcmd tclconscmd \ + cconscmd + + # Configure the flag-dependent parts of the template + + if {[dict get $state tcl-api]} { + dict set state classmgrstruct $mgrstruct + dict set state classmgrsetup $mgrsetup + dict set state classmgrnin $newinsname + dict set state classcommand $classcmd + dict set state tclconscmd $tclconscmd + } else { + dict set state classmgrstruct {} + dict set state classmgrsetup {} + dict set state classmgrnin {} + dict set state classcommand {} + dict set state tclconscmd {} + } + + if {[dict get $state c-api]} { + dict set state cconscmd $cconscmd + } else { + dict set state cconscmd {} + } + + critcl::util::Put $header [string map [MakeMap] $template] + + critcl::ccode "#include <$hdr>" + if {[dict get $state tcl-api]} { + uplevel 2 [list critcl::ccommand $class ${stem}_ClassCommand] + } + return +} + +proc ::critcl::class::MakeMap {} { + variable state + + # First set of substitutions. + set premap {} + dict for {k v} $state { + lappend premap @${k}@ $v + } + + # Resolve the substitutions used in the fragments of code to + # generate the final map. + set map {} + foreach {k v} $premap { + lappend map $k [string map $premap $v] + } + + return $map +} + +proc ::critcl::class::Template {path} { + variable selfdir + set path $selfdir/$path + critcl::msg "\tClass templates: $path" + return [Get $path] +} + +proc ::critcl::class::Get {path} { + if {[catch { + set c [open $path r] + fconfigure $c -eofchar {} + set d [read $c] + close $c + }]} { + set d {} + } + return $d +} + +proc ::critcl::class::Dedent {pfx text} { + set result {} + foreach l [split $text \n] { + lappend result [regsub ^$pfx $l {}] + } + join $result \n +} + +# # ## ### ##### ######## ############# ##################### +## +# Internal: All the helper commands providing access to the system +# state to the specification commands (see next section) +## +# # ## ### ##### ######## ############# ##################### + +proc ::critcl::class::CAPIPrefix {name} { + variable state + dict set state capiprefix $name + return +} + +proc ::critcl::class::Flag {key flag} { + critcl::msg " ($key = $flag)" + variable state + dict set state $key $flag + return +} + +proc ::critcl::class::Include {header} { + # Name of an API to include in the generated code. + variable state + dict lappend state include $header + return +} + +proc ::critcl::class::ExternalType {name} { + # Declaration of the C type to use for the object state. This + # type is expected to be declared externally. It allows us to use + # a 3rd party structure directly. Cannot be specified if instance + # and/or class variables for our own structures have been declared + # already. + + variable state + + if {[dict exists $state variable]} { + return -code error "Invalid external instance type. Instance variables already declared." + } + if {[dict exists $state classvariable]} { + return -code error "Invalid external instance type. Class variables already declared." + } + + dict set state instancetype $name + return +} + +proc ::critcl::class::Variable {ctype name comment vloc} { + # Declaration of an instance variable. In other words, a field in + # the C structure for instances. Cannot be specified if an + # external "type" has been specified already. + + variable state + + if {[dict exists $state instancetype]} { + return -code error \ + "Invalid instance variable. External instance type already declared." + } + + if {[dict exists $state variable def $name]} { + return -code error "Duplicate definition of instance variable \"$name\"" + } + + # Create the automatic instance variable to hold the instance + # command token. + + if {![dict exists $state stop] && + (![dict exists $state variable] || + ![llength [dict get $state variable names]]) + } { + # To make it easier on us we reuse the existing definition + # commands to set everything up. To avoid infinite recursion + # we set a flag stopping us from re-entering this block. + + dict set state stop 1 + critcl::at::here ; Variable Tcl_Command cmd { + Automatically generated. Holds the token for the instance command, + for use by the automatically created destroy method. + } [critcl::at::get] + dict unset state stop + + PostConstructor "[critcl::at::here!]\tinstance->cmd = cmd;\n" + + # And the destroy method using the above instance variable. + critcl::at::here ; MethodExplicit destroy proc {} void { + Tcl_DeleteCommandFromToken(interp, instance->cmd); + } + } + + dict update state variable f { + dict lappend f names $name + } + dict set state variable def $name ctype $ctype + dict set state variable def $name loc $vloc + dict set state variable def $name comment [string trim $comment] + return +} + +proc ::critcl::class::ClassVariable {ctype name comment vloc} { + # Declaration of a class variable. In other words, a field in the + # C structure for the class. Cannot be specified if a an external + # "type" has been specified already. + + variable state + + if {[dict exists $state instancetype]} { + return -code error \ + "Invalid class variable. External instance type already declared." + } + + if {[dict exists $state classvariable def $name]} { + return -code error "Duplicate definition of class variable \"$name\"" + } + + dict update state classvariable c { + dict lappend c names $name + } + dict set state classvariable def $name ctype $ctype + dict set state classvariable def $name loc $vloc + dict set state classvariable def $name comment [string trim $comment] + + if {[llength [dict get $state classvariable names]] == 1} { + # On declaration of the first class variable we declare an + # instance variable which provides the instances with a + # reference to their class (structure). + critcl::at::here ; Variable @classtype@ class { + Automatically generated. Reference to the class (variables) + from the instance. + } [critcl::at::get] + Constructor "[critcl::at::here!]\tinstance->class = class;\n" + } + return +} + +proc ::critcl::class::Constructor {code} { + CodeFragment constructor $code + return +} + +proc ::critcl::class::PostConstructor {code} { + CodeFragment postconstructor $code + return +} + +proc ::critcl::class::Destructor {code} { + CodeFragment destructor $code + return +} + +proc ::critcl::class::ClassConstructor {code} { + CodeFragment classconstructor $code + return +} + +proc ::critcl::class::ClassDestructor {code} { + CodeFragment classdestructor $code + return + } + +proc ::critcl::class::Support {code} { + CodeFragment support $code + return +} + +proc ::critcl::class::MethodExternal {name function details} { + MethodCheck method instance $name + + set map {} + if {[llength $details]} { + set details [join $details {, }] + lappend map objv "objv, $details" + set details " ($details)" + } + + MethodDef method instance $name [MethodEnum method $name] {} $function $map \ + "/* $name : External function @function@$details */" + return +} + +proc ::critcl::class::MethodExplicit {name mtype arguments args} { + # mtype in {proc, command} + MethodCheck method instance $name + variable state + + set bloc [critcl::at::get] + set enum [MethodEnum method $name] + set function ${enum}_Cmd + set cdimport "[critcl::at::here!] @instancetype@ instance = (@instancetype@) clientdata;" + set tname "[dict get $state class] M $name" + + if {$mtype eq "proc"} { + # Method is cproc. + # |args| == 2, args => rtype, body + # arguments is (argtype argname...) + # (See critcl::cproc for full details) + + # Force availability of the interp in methods. + if {[lindex $arguments 0] ne "Tcl_Interp*"} { + set arguments [linsert $arguments 0 Tcl_Interp* interp] + } + + lassign $args rtype body + + set body $bloc[string trimright $body] + set cargs [critcl::argnames $arguments] + if {[llength $cargs]} { set cargs " $cargs" } + set syntax "/* Syntax: $name$cargs */" + set body "\n $syntax\n$cdimport\n $body" + + set code [critcl::collect { + critcl::cproc $function $arguments $rtype $body \ + -cname 1 -pass-cdata 1 -arg-offset 1 -tracename $tname + }] + + } else { + # Method is ccommand. + # |args| == 1, args => body + lassign $args body + + if {$arguments ne {}} {set arguments " cmd<<$arguments>>"} + set body $bloc[string trimright $body] + set syntax "/* Syntax: $name$arguments */" + set body "\n $syntax\n$cdimport\n $body" + + set code [critcl::collect { + critcl::ccommand $function {} $body \ + -cname 1 -tracename $tname + }] + } + + MethodDef method instance $name $enum $syntax $function {} $code + return +} + +proc ::critcl::class::ClassMethodExternal {name function details} { + MethodCheck classmethod class $name + + set map {} + if {[llength $details]} { + lappend map objv "objv, [join $details {, }]" + } + + MethodDef classmethod "&classmgr->user" $name [MethodEnum classmethod $name] {} $function $map \ + "/* $name : External function @function@ */" + return +} + +proc ::critcl::class::ClassMethodExplicit {name mtype arguments args} { + # mtype in {proc, command} + MethodCheck classmethod class $name + variable state + + set bloc [critcl::at::get] + set enum [MethodEnum classmethod $name] + set function ${enum}_Cmd + set cdimport "[critcl::at::here!] @classtype@ class = (@classtype@) clientdata;" + set tname "[dict get $state class] CM $name" + + if {$mtype eq "proc"} { + # Method is cproc. + # |args| == 2, args => rtype, body + # arguments is (argtype argname...) + # (See critcl::cproc for full details) + + # Force availability of the interp in methods. + if {[lindex $arguments 0] ne "Tcl_Interp*"} { + set arguments [linsert $arguments 0 Tcl_Interp* interp] + } + + lassign $args rtype body + + set body $bloc[string trimright $body] + set cargs [critcl::argnames $arguments] + if {[llength $cargs]} { set cargs " $cargs" } + set syntax "/* Syntax: $name$cargs */" + set body "\n $syntax\n$cdimport\n $body" + + set code [critcl::collect { + critcl::cproc $function $arguments $rtype $body \ + -cname 1 -pass-cdata 1 -arg-offset 1 \ + -tracename $tname + }] + + } else { + # Method is ccommand. + # |args| == 1, args => body + lassign $args body + + if {$arguments ne {}} {set arguments " cmd<<$arguments>>"} + set body $bloc[string trimright $body] + set syntax "/* Syntax: $name$arguments */" + set body "\n $syntax\n$cdimport\n $body" + + set code [critcl::collect { + critcl::ccommand $function {} $body \ + -cname 1 -tracename $tname + }] + } + + MethodDef classmethod class $name $enum $syntax $function {} $code + return +} + +proc ::critcl::class::MethodCheck {section label name} { + variable state + if {[dict exists $state $section def $name]} { + return -code error "Duplicate definition of $label method \"$name\"" + } + return +} + +proc ::critcl::class::MethodEnum {section name} { + variable state + # Compute a C enum identifier from the (class) method name. + + # To avoid trouble we have to remove any non-alphabetic + # characters. A serial number is required to distinguish methods + # which would, despite having different names, transform to the + # same C enum identifier. + + regsub -all -- {[^a-zA-Z0-9_]} $name _ name + regsub -all -- {_+} $name _ name + + set serial [llength [dict get $state $section names]] + set M [expr {$section eq "method" ? "M" : "CM"}] + + return @stem@_${M}_${serial}_[string toupper $name] +} + +proc ::critcl::class::MethodDef {section var name enum syntax function xmap code} { + variable state + + set case "case $enum: return @function@ ($var, interp, objc, objv); break;" + set case [string map $xmap $case] + + set map [list @function@ $function] + + dict update state $section m { + dict lappend m names $name + } + dict set state $section def $name enum $enum + dict set state $section def $name case [string map $map $case] + dict set state $section def $name code [string map $map $code] + dict set state $section def $name syntax [string map $map $syntax] + return +} + +proc ::critcl::class::CodeFragment {section code} { + variable state + set code [string trim $code \n] + if {$code ne {}} { + dict lappend state $section $code + } + return +} + +# # ## ### ##### ######## ############# ##################### +## +# Internal: Namespace holding the class specification commands. The +# associated state resides in the outer namespace, as do all the +# procedures actually accessing that state (see above). Treat it like +# a sub-package, with a proper API. +## +# # ## ### ##### ######## ############# ##################### + +namespace eval ::critcl::class::spec {} + +proc ::critcl::class::spec::Process {script} { + # Note how this script is evaluated within the 'spec' namespace, + # providing it with access to the specification methods. + + # Point the global namespace resolution into the spec namespace, + # to ensure that the commands are properly found even if the + # script moved through helper commands and other namespaces. + + # Note that even this will not override the builtin 'variable' + # command with ours, which is why ours is now called + # 'insvariable'. + + namespace eval :: [list namespace path [list [namespace current] ::]] + + eval $script + + namespace eval :: {namespace path {}} + return +} + +proc ::critcl::class::spec::tcl-api {flag} { + ::critcl::class::Flag tcl-api $flag +} + +proc ::critcl::class::spec::c-api {flag {name {}}} { + ::critcl::class::Flag c-api $flag + if {$name eq {}} return + ::critcl::class::CAPIPrefix $name +} + +proc ::critcl::class::spec::include {header} { + ::critcl::class::Include $header +} + +proc ::critcl::class::spec::type {name} { + ::critcl::class::ExternalType $name +} + +proc ::critcl::class::spec::insvariable {ctype name {comment {}} {constructor {}} {destructor {}}} { + ::critcl::at::caller + set vloc [critcl::at::get*] + ::critcl::at::incrt $comment ; set cloc [::critcl::at::get*] + ::critcl::at::incrt $constructor ; set dloc [::critcl::at::get] + + + ::critcl::class::Variable $ctype $name $comment $vloc + + if {$constructor ne {}} { + ::critcl::class::Constructor $cloc$constructor + } + if {$destructor ne {}} { + ::critcl::class::Destructor $dloc$destructor + } + + return +} + +proc ::critcl::class::spec::constructor {code {postcode {}}} { + ::critcl::at::caller ; set cloc [::critcl::at::get*] + ::critcl::at::incrt $code ; set ploc [::critcl::at::get] + + if {$code ne {}} { + ::critcl::class::Constructor $cloc$code + } + if {$postcode ne {}} { + ::critcl::class::PostConstructor $ploc$postcode + } + return +} + +proc ::critcl::class::spec::destructor {code} { + ::critcl::class::Destructor [::critcl::at::caller!]$code + return +} + +proc ::critcl::class::spec::method {name op detail args} { + # Syntax + # (1) method as ... + # (2) method proc + # (3) method command + # name op detail args__________ + + # op = as|proc|cmd|command + + # op == proc + # detail = argument list, syntax as per cproc. + # args[0] = r(esult)type + # args[1] = body + + # op == command + # detail = argument syntax. not used in code, purely descriptive. + # args[0] = body + + switch -exact -- $op { + as { + # The instance method is an external C function matching + # an ObjCmd in signature, possibly with additional + # parameters at the end. + # + # detail = name of that function + # args = values for the additional parameters, if any. + + ::critcl::class::MethodExternal $name $detail $args + return + } + proc { + if {[llength $args] != 2} { + return -code error "wrong#args" + } + } + cmd - command { + set op command + if {[llength $args] != 1} { + return -code error "wrong#args" + } + } + default { + return -code error "Illegal method type \"$op\", expected one of cmd, command, or proc" + } + } + + ::critcl::at::caller + ::critcl::at::incrt $detail + + eval [linsert $args 0 ::critcl::class::MethodExplicit $name $op [string trim $detail]] + #::critcl::class::MethodExplicit $name $op [string trim $detail] {*}$args + return +} + +proc ::critcl::class::spec::classvariable {ctype name {comment {}} {constructor {}} {destructor {}}} { + ::critcl::at::caller + set vloc [critcl::at::get*] + ::critcl::at::incrt $comment ; set cloc [::critcl::at::get*] + ::critcl::at::incrt $constructor ; set dloc [::critcl::at::get] + + ::critcl::class::ClassVariable $ctype $name $comment $vloc + + if {$constructor ne {}} { + ::critcl::class::ClassConstructor $cloc$constructor + } + if {$destructor ne {}} { + ::critcl::class::ClassDestructor $dloc$destructor + } + return +} + +proc ::critcl::class::spec::classconstructor {code} { + ::critcl::class::ClassConstructor [::critcl::at::caller!]$code + return +} + +proc ::critcl::class::spec::classdestructor {code} { + ::critcl::class::ClassDestructor [::critcl::at::caller!]$code + return +} + +proc ::critcl::class::spec::classmethod {name op detail args} { + # Syntax + # (1) classmethod as ... + # (2) classmethod proc + # (3) classmethod command + # name op detail args__________ + + # op = as|proc|cmd|command + + # op == proc + # detail = argument syntax per cproc. + # args[0] = r(esult)type + # args[1] = body + + # op == command + # detail = argument syntax. not used in code, purely descriptive. + # args[0] = body + + switch -exact -- $op { + as { + # The class method is an external C function matching an + # ObjCmd in signature, possibly with additional parameters + # at the end. + # + # detail = name of that function + # args = values for the additional parameters, if any. + + ::critcl::class::ClassMethodExternal $name $detail $args + return + } + proc { + if {[llength $args] != 2} { + return -code error "wrong#args" + } + } + cmd - command { + set op command + if {[llength $args] != 1} { + return -code error "wrong#args" + } + } + default { + return -code error "Illegal method type \"$op\", expected one of cmd, command, or proc" + } + } + + ::critcl::at::caller + ::critcl::at::incrt $detail + eval [linsert $args 0 ::critcl::class::ClassMethodExplicit $name $op [string trim $detail]] + # ::critcl::class::ClassMethodExplicit $name $op [string trim $detail] {*}$args + return +} + +proc ::critcl::class::spec::support {code} { + ::critcl::class::Support [::critcl::at::caller!]$code + return +} + +proc ::critcl::class::spec::method_introspection {} { + ::critcl::class::spec::classvariable Tcl_Obj* methods { + Cache for the list of method names. + } { + class->methods = ComputeMethodList (@stem@_methodnames); + Tcl_IncrRefCount (class->methods); + } { + Tcl_DecrRefCount (class->methods); + class->methods = NULL; + } + + # The ifdef/define/endif block below ensures that the supporting + # code will be defined only once, even if multiple classes + # activate method-introspection. Note that what we cannot prevent + # is the appearance of multiple copies of the code below in the + # generated output, only that it is compiled multiple times. + + ::critcl::class::spec::support { +#ifndef CRITCL_CLASS__HAVE_COMPUTE_METHOD_LIST +#define CRITCL_CLASS__HAVE_COMPUTE_METHOD_LIST +static Tcl_Obj* +ComputeMethodList (CONST char** table) +{ + Tcl_Size n, i; + char** item; + Tcl_Obj** lv; + Tcl_Obj* result; + + item = (char**) table; + n = 0; + while (*item) { + n ++; + item ++; + } + + lv = (Tcl_Obj**) ckalloc (n * sizeof (Tcl_Obj*)); + i = 0; + while (table [i]) { + lv [i] = Tcl_NewStringObj (table [i], -1); + i ++; + } + + result = Tcl_NewListObj (n, lv); + ckfree ((char*) lv); + + return result; +} +#endif /* CRITCL_CLASS__HAVE_COMPUTE_METHOD_LIST */ + } + + ::critcl::class::spec::method methods proc {} void { + Tcl_SetObjResult (interp, instance->class->methods); + } + + ::critcl::class::spec::classmethod methods proc {} void { + Tcl_SetObjResult (interp, class->methods); + } + return +} + +# # ## ### ##### ######## ############# ##################### +## State + +namespace eval ::critcl::class { + variable selfdir [file dirname [file normalize [info script]]] +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::class { + namespace export define + catch { namespace ensemble create } ; # 8.5+ +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-class/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-class/pkgIndex.tcl new file mode 100644 index 00000000..5e353486 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-class/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::class 1.2.1 [list source [file join $dir class.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-cutil/allocs/critcl_alloc.h b/src/vfs/critcl.vfs/lib/critcl-cutil/allocs/critcl_alloc.h new file mode 100644 index 00000000..684eafe5 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-cutil/allocs/critcl_alloc.h @@ -0,0 +1,57 @@ +#ifndef __CRITCL_UTIL_ALLOC_H +#define __CRITCL_UTIL_ALLOC_H 1 + +/* + * Copyright (c) 2017-2020 Andreas Kupries + * = = == === ===== ======== ============= ===================== + */ + +#include /* memcpy - See STREP */ +#include + +/* + * Helper macros for easy allocation of structures and arrays. + */ + +#define ALLOC(type) (type *) ckalloc (sizeof (type)) +#define ALLOC_PLUS(type,n) (type *) ckalloc (sizeof (type) + (n)) +#define NALLOC(type,n) (type *) ckalloc (sizeof (type) * (n)) +#define REALLOC(x,type,n) (type *) ckrealloc ((char*) x, sizeof (type) * (n)) + +#define FREE(p) ckfree ((char*)(p)) + +/* + * Macros to properly set a string rep from a string or DString. The main + * point is adding the terminating \0 character. The Tcl core checks for that. + */ + +#define STREP(o,str,len) \ + (o)->length = (len); \ + (o)->bytes = ckalloc((len)+1); \ + memcpy ((o)->bytes, (str), (len)); \ + (o)->bytes[(len)] = '\0' + +#define STREP_DS(o,ds) { \ + int length = Tcl_DStringLength (ds); \ + STREP(o, Tcl_DStringValue (ds), length); \ + } + +#define STRDUP(v,s) { \ + char* str = ckalloc (1+strlen (s)); \ + strcpy (str, s); \ + v = str; \ + } + +/* + * = = == === ===== ======== ============= ===================== + */ + +#endif /* __CRITCL_UTIL_ALLOC_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-cutil/asserts/critcl_assert.h b/src/vfs/critcl.vfs/lib/critcl-cutil/asserts/critcl_assert.h new file mode 100644 index 00000000..32ff0755 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-cutil/asserts/critcl_assert.h @@ -0,0 +1,68 @@ +#ifndef __CRITCL_CUTIL_ASSERT_H +#define __CRITCL_CUTIL_ASSERT_H 1 + +/* + * Copyright (c) 2017-2020 Andreas Kupries + * = = == === ===== ======== ============= ===================== + */ + +#include + +/* + * Macros for assertions, controlled via CRITCL_ASSERT. + * Especially a helper to check array bounds, and counted + * abort. + */ + +#ifdef CRITCL_ASSERT + +#define CRITCL_CUTIL_XSTR(x) #x +#define CRITCL_CUTIL_STR(x) CRITCL_CUTIL_XSTR(x) +#define CRITCL_CUTIL_RANGEOK(i,n) ((0 <= (i)) && ((i) < (n))) + +#define ASSERT(x,msg) if (!(x)) { \ + Tcl_Panic (msg " (" #x "), in file %s @line %d", \ + __FILE__, __LINE__); \ + } + +#define ASSERT_VA(x,msg,format,...) if (!(x)) { \ + Tcl_Panic (msg " (" #x "), in file %s @line %d, " format, \ + __FILE__, __LINE__, __VA_ARGS__); \ + } + +#define ASSERT_BOUNDS(i,n) \ + ASSERT_VA (CRITCL_CUTIL_RANGEOK(i,n), \ + "array index out of bounds", \ + CRITCL_CUTIL_STR(i) \ + " = (%d) >= (%d) = " \ + CRITCL_CUTIL_STR(n), \ + i, n) + +#define STOPAFTER(x) { \ + static int count = (x); \ + count --; \ + if (!count) { Tcl_Panic ("stop"); } \ + } + +#else /* ! CRITCL_ASSERT */ + +#define ASSERT(x,msg) +#define ASSERT_VA(x,msg,format,...) +#define ASSERT_BOUNDS(i,n) +#define STOPAFTER(x) + +#endif + +/* + * = = == === ===== ======== ============= ===================== + */ + +#endif /* __CRITCL_CUTIL_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-cutil/cutil.tcl b/src/vfs/critcl.vfs/lib/critcl-cutil/cutil.tcl new file mode 100644 index 00000000..9a56160c --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-cutil/cutil.tcl @@ -0,0 +1,69 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# n/a + +# CriTcl Utility Commands To Provide Common C-level utility functions. +# +# Copyright (c) 2017-2023 Andreas Kupries + +package provide critcl::cutil 0.4 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.2 + +namespace eval ::critcl::cutil {} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Embed C Code + +# # ## ### ##### ######## ############# ##################### + +proc critcl::cutil::alloc {} { + variable selfdir + critcl::cheaders -I$selfdir/allocs + critcl::include critcl_alloc.h + return +} + +proc critcl::cutil::assertions {{enable 0}} { + variable selfdir + critcl::cheaders -I$selfdir/asserts + critcl::include critcl_assert.h + if {!$enable} return + critcl::cflags -DCRITCL_ASSERT + return +} + +proc critcl::cutil::tracer {{enable 0}} { + variable selfdir + alloc ;# Tracer uses the allocation utilities in its implementation + critcl::cheaders -I$selfdir/trace + critcl::include critcl_trace.h + critcl::csources $selfdir/trace/trace.c + if {!$enable} return + critcl::cflags -DCRITCL_TRACER + return +} + +# # ## ### ##### ######## ############# ##################### +## State + +namespace eval ::critcl::cutil { + variable selfdir [file dirname [file normalize [info script]]] +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::cutil { + namespace export alloc assert tracer + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-cutil/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-cutil/pkgIndex.tcl new file mode 100644 index 00000000..bd16d532 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-cutil/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::cutil 0.4 [list source [file join $dir cutil.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-cutil/trace/critcl_trace.h b/src/vfs/critcl.vfs/lib/critcl-cutil/trace/critcl_trace.h new file mode 100644 index 00000000..a0d1d203 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-cutil/trace/critcl_trace.h @@ -0,0 +1,156 @@ +#ifndef __CRITCL_UTIL_TRACE_H +#define __CRITCL_UTIL_TRACE_H 1 + +/* + * Copyright (c) 2017-2023 Andreas Kupries + * + * Narrative tracing support, controlled by CRITCL_TRACER + * = = == === ===== ======== ============= ===================== + * + * Further control of the active logical sub-streams is done via the + * declarators + * - TRACE_ON + * - TRACE_OFF + * - TRACE_TAG_ON + * - TRACE_TAG_OFF + * + * The macros make use of the standard macros __FILE__ and __LINE__ + * to identify traced locations (physically). + * + * ATTENTION: The trace facility assumes a C99 compiler to have + * access to the __func__ string which holds the name + * of the current function. + * + * NOTE: define CRITCL_TRACE_NOTHREADS if the tracer is run on a single-threaded + * process for sure. Else leave it at the new default of multi-threaded + * operation. + * + * In this mode it generates one `.trace` file per thread with active tracing. + * In single-threaded mode it writes to stdout as before. + */ + +#include + +/* + * Main (convenience) commands: + * + * - TRACE_FUNC :: Function entry, formatted parameters + * - TRACE_FUNC_VOID :: Function entry, no parameters + * - TRACE_RETURN :: Function exit, formatted result + * - TRACE_RETURN_VOID :: Function exit, no result + * - TRACE :: Additional trace line. + * + * The above commands are composed from the lower level commands below. + * + * Scoping + * - TRACE_PUSH_SCOPE :: Start a named scope, no output + * - TRACE_PUSH_FUNC :: Start a scope, named by the current function, no output + * - TRACE_POP :: End a scope, no output + + * Tracing + * - TRACE_HEADER :: Start of trace line (location, indentation, scope) + * - TRACE_ADD :: Extend trace line, formatted information + * - TRACE_CLOSER :: End of trace line + * + * All of the tracing command also come in TRACE_TAG_ forms which take an + * additional 1st argument, the tag of the stream. The scoping commands do not + * take tags. They manage indentation without generating output on their own. + */ + +#ifndef CRITCL_TRACER +/* Tracing disabled. All macros vanish */ +#define TRACE_PUSH_SCOPE(string) +#define TRACE_PUSH_FUNC +#define TRACE_POP +#define TRACE_ON +#define TRACE_OFF +#define TRACE_HEADER(indent) +#define TRACE_ADD(format, ...) +#define TRACE_CLOSER +#define TRACE_TAG_ON(tag) +#define TRACE_TAG_OFF(tag) +#define TRACE_TAG_HEADER(tag,indent) +#define TRACE_TAG_ADD(tag, format, ...) +#define TRACE_TAG_CLOSER(tag) +#define TRACE_FUNC(format, ...) +#define TRACE_FUNC_VOID +#define TRACE_RETURN(format,x) return (x); +#define TRACE_RETURN_VOID return; +#define TRACE(format, ...) +#define TRACE_TAG_FUNC(tag, format, ...) +#define TRACE_TAG_FUNC_VOID(tag) +#define TRACE_TAG_RETURN(tag, format, x) return (x); +#define TRACE_TAG_RETURN_VOID(tag) return; +#define TRACE_TAG(tag, format, ...) +#define TRACE_RUN(code) +#define TRACE_DO(code) +#define TRACE_TAG_DO(tag, code) +#define TRACE_TAG_VAR(tag) 0 +#endif + +#ifdef CRITCL_TRACER +/* Tracing active. Macros expand to content. + */ +#define TRACE_PUSH_SCOPE(string) critcl_trace_push (string) +#define TRACE_PUSH_FUNC TRACE_PUSH_SCOPE (__func__) +#define TRACE_POP critcl_trace_pop() + +#define TRACE_ON TRACE_TAG_ON (THIS_FILE) +#define TRACE_OFF TRACE_TAG_OFF (THIS_FILE) + +#define TRACE_HEADER(indent) TRACE_TAG_HEADER (THIS_FILE, indent) +#define TRACE_ADD(format, ...) TRACE_TAG_ADD (THIS_FILE, format, __VA_ARGS__) +#define TRACE_CLOSER TRACE_TAG_CLOSER (THIS_FILE) + +#define TRACE_TAG_ON(tag) static int TRACE_TAG_VAR (tag) = 1 +#define TRACE_TAG_OFF(tag) static int TRACE_TAG_VAR (tag) = 0 +#define TRACE_TAG_VAR(tag) __critcl_tag_ ## tag ## _status + +#define TRACE_TAG_HEADER(tag, indent) critcl_trace_header (TRACE_TAG_VAR (tag), (indent), __FILE__, __LINE__) +#define TRACE_TAG_ADD(tag, format, ...) critcl_trace_printf (TRACE_TAG_VAR (tag), format, __VA_ARGS__) +#define TRACE_TAG_CLOSER(tag) critcl_trace_closer (TRACE_TAG_VAR (tag)) + +/* Highlevel (convenience) tracing. + */ + +#define TRACE_FUNC(format, ...) TRACE_TAG_FUNC (THIS_FILE, format, __VA_ARGS__) +#define TRACE_FUNC_VOID TRACE_TAG_FUNC_VOID (THIS_FILE) +#define TRACE_RETURN(format,x) TRACE_TAG_RETURN (THIS_FILE, format, x) +#define TRACE_RETURN_VOID TRACE_TAG_RETURN_VOID (THIS_FILE) +#define TRACE(format, ...) TRACE_TAG (THIS_FILE, format, __VA_ARGS__) + +#define TRACE_TAG_FUNC(tag, format, ...) TRACE_PUSH_FUNC; TRACE_TAG_HEADER (tag,1); TRACE_TAG_ADD (tag, format, __VA_ARGS__); TRACE_TAG_CLOSER (tag) +#define TRACE_TAG_FUNC_VOID(tag) TRACE_PUSH_FUNC; TRACE_TAG_HEADER (tag,1); TRACE_TAG_ADD (tag, "(%s)", "void"); TRACE_TAG_CLOSER (tag) +#define TRACE_TAG_RETURN(tag, format, x) TRACE_TAG_HEADER (tag,1); TRACE_TAG_ADD (tag, "%s", "RETURN = ") ; TRACE_TAG_ADD (tag, format, x) ; TRACE_TAG_CLOSER (tag) ; TRACE_POP ; return (x) +#define TRACE_TAG_RETURN_VOID(tag) TRACE_TAG_HEADER (tag,1); TRACE_TAG_ADD (tag, "RETURN %s", "(void)") ; TRACE_TAG_CLOSER (tag) ; TRACE_POP ; return +#define TRACE_TAG(tag, format, ...) TRACE_TAG_HEADER (tag,1); TRACE_TAG_ADD (tag, format, __VA_ARGS__) ; TRACE_TAG_CLOSER (tag) + +#define TRACE_RUN(code) code +#define TRACE_DO(code) TRACE_TAG_DO (THIS_FILE, code) +#define TRACE_TAG_DO(tag, code) if (TRACE_TAG_VAR (tag)) { code ; } + +/* Support functions used in the macros. + */ + +extern void critcl_trace_push (const char* scope); +extern void critcl_trace_pop (void); +extern void critcl_trace_header (int on, int indent, const char *filename, int line); +extern void critcl_trace_printf (int on, const char *pat, ...); +extern void critcl_trace_closer (int on); + +/* Support functions used by the implementation of "critcl::cproc". + */ + +extern void critcl_trace_cmd_args (const char* scope, int oc, Tcl_Obj*const* ov); +extern int critcl_trace_cmd_result (int status, Tcl_Interp* ip); + +#endif +#endif /* __CRITCL_UTIL_TRACE_H */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-cutil/trace/trace.c b/src/vfs/critcl.vfs/lib/critcl-cutil/trace/trace.c new file mode 100644 index 00000000..f4e4ab82 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-cutil/trace/trace.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2017-2024 Andreas Kupries + * = = == === ===== ======== ============= ===================== + */ + +#include +#include +#include + +/* + * = = == === ===== ======== ============= ===================== + */ + +#ifdef CRITCL_TRACER + +/* Tracking the stack of scopes, + * single-linked list, + * top to bottom. + */ + +typedef struct scope_stack { + const char* scope; + struct scope_stack* down; +} scope_stack; + +/* + * = = == === ===== ======== ============= ===================== + * Tracing state (stack of scopes, associated indentation level) + * + * API regexp for trace output: + * (header printf* closer)* + * + * - closed == 1 :: post (closer) + * - closed == 0 :: post (header) + * + * [1] in (header) && !closed + * => starting a new line in the middle of an incomplete line + * => force closer + * [2] in (printf) && closed + * => continuing a line which was interrupted by another (see [1]) + * => force header + */ + +#define MSGMAX (1024*1024) + +#ifdef CRITCL_TRACE_NOTHREADS + +static scope_stack* top = 0; +static int level = 0; +static int closed = 1; +static char msg [MSGMAX]; + +#define SETUP +#define TOP top +#define LEVEL level +#define CLOSED closed +#define MSG msg +#define CHAN stdout + +#else + +typedef struct ThreadSpecificData { + scope_stack* top; + int level; + int closed; + char msg [MSGMAX]; + FILE* chan; +} ThreadSpecificData; + +/* copied from tclInt.h */ +#define TCL_TSD_INIT(keyPtr) \ + (ThreadSpecificData *)Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData)) /* OK tcl9 */ + +static Tcl_ThreadDataKey ctraceDataKey; + +#define TOP tsdPtr->top +#define LEVEL tsdPtr->level +#define CLOSED tsdPtr->closed +#define MSG tsdPtr->msg +#define CHAN chan() +#define SETUP ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&ctraceDataKey) + +// Very lazy channel initialization - First actual write +static FILE* chan (void) { + SETUP; + if (!tsdPtr->chan) { + sprintf (MSG, "%p.trace", Tcl_GetCurrentThread()); + tsdPtr->chan = fopen (MSG, "w"); + } + return tsdPtr->chan; +} + +#endif + +/* + * = = == === ===== ======== ============= ===================== + * Internals + */ + +static void +indent (void) +{ + int i; + SETUP; + for (i = 0; i < LEVEL; i++) { fwrite(" ", 1, 1, CHAN); } + fflush (CHAN); +} + +static void +scope (void) +{ + SETUP; + if (!TOP) return; + fwrite (TOP->scope, 1, strlen(TOP->scope), CHAN); + fflush (CHAN); +} + +static void +separator (void) +{ + SETUP; + fwrite(" | ", 1, 3, CHAN); + fflush (CHAN); +} + +/* + * = = == === ===== ======== ============= ===================== + * API + */ + +void +critcl_trace_push (const char* scope) +{ + SETUP; + scope_stack* new = ALLOC (scope_stack); + new->scope = scope; + new->down = TOP; + TOP = new; + LEVEL += 4; +} + +void +critcl_trace_pop (void) +{ + SETUP; + scope_stack* next = TOP->down; + LEVEL -= 4; + ckfree ((char*) TOP); + TOP = next; +} + +void +critcl_trace_closer (int on) +{ + if (!on) return; + SETUP; + fwrite ("\n", 1, 1, CHAN); + fflush (CHAN); + CLOSED = 1; +} + +void +critcl_trace_header (int on, int ind, const char* filename, int line) +{ + if (!on) return; + SETUP; + if (!CLOSED) critcl_trace_closer (1); + // location prefix +#if 0 /* varying path length breaks indenting by call level :( */ + if (filename) { + fprintf (CHAN, "%s:%6d", filename, line); + fflush (CHAN); + } +#endif + // indentation, scope, separator + if (ind) { indent (); } + scope (); + separator(); + CLOSED = 0; +} + +void +critcl_trace_printf (int on, const char *format, ...) +{ + /* + * 1MB output-buffer. We may trace large data structures. This is also a + * reason why the implementation can be compiled out entirely. + */ + int len; + va_list args; + if (!on) return; + SETUP; + if (CLOSED) critcl_trace_header (1, 1, 0, 0); + + va_start (args, format); + len = vsnprintf (MSG, MSGMAX, format, args); + va_end (args); + fwrite (MSG, 1, len, CHAN); + fflush (CHAN); +} + +void +critcl_trace_cmd_args (const char* scopename, int argc, Tcl_Obj*const* argv) +{ + int i; + critcl_trace_push (scopename); + for (i=0; i < argc; i++) { + // No location information + indent(); + scope(); + separator(); + critcl_trace_printf (1, "ARG [%3d] = %p (^%d:%s) '%s'\n", + i, argv[i], argv[i]->refCount, + argv[i]->typePtr ? argv[i]->typePtr->name : "", + Tcl_GetString((Tcl_Obj*) argv[i])); + } +} + +int +critcl_trace_cmd_result (int status, Tcl_Interp* ip) +{ + Tcl_Obj* robj = Tcl_GetObjResult (ip); + const char* rstr = Tcl_GetString (robj); + const char* rstate; + const char* rtype; + static const char* state_str[] = { + /* 0 */ "OK", + /* 1 */ "ERROR", + /* 2 */ "RETURN", + /* 3 */ "BREAK", + /* 4 */ "CONTINUE", + }; + char buf [TCL_INTEGER_SPACE]; + if (status <= TCL_CONTINUE) { + rstate = state_str [status]; + } else { + sprintf (buf, "%d", status); + rstate = (const char*) buf; + } + if (robj->typePtr) { + rtype = robj->typePtr->name; + } else { + rtype = ""; + } + + // No location information + indent(); + scope(); + separator(); + critcl_trace_printf (1, "RESULT = %s %p (^%d:%s) '%s'\n", + rstate, robj, robj->refCount, rtype, rstr); + critcl_trace_pop (); + return status; +} + +#endif /* CRITCL_TRACER */ +/* + * = = == === ===== ======== ============= ===================== + */ + +/* + * local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl-emap/emap.tcl b/src/vfs/critcl.vfs/lib/critcl-emap/emap.tcl new file mode 100644 index 00000000..4e5b0ebe --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-emap/emap.tcl @@ -0,0 +1,696 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# n/a + +# CriTcl Utility Package for en- and decoding an external enum. +# Based on i-assoc. +# +# Copyright (c) 2014-2023 Andreas Kupries + +package provide critcl::emap 1.3.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.1.11 ; # make, include -- dict portability +package require critcl::iassoc + +namespace eval ::critcl::emap {} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Embed C Code + +proc critcl::emap::def {name dict args} { + # dict: Tcl symbolic name -> (C int value (1)) + # + # (Ad 1) Can be numeric, or symbolic, as long as it is a C int + # expression in the end. + + # args = options. Currently supported: + # * -nocase : case-insensitive strings on encoding. + # * -mode : list of use cases, access case: tcl, c (default: tcl) + + Options $args + Index $dict id symbols last + # symbols :: list of words, lexicographically sorted + # id :: symbol -> index (sorted) + # last :: number of symbols + + Header $name + ConstStringTable $name $symbols $dict $nocase $last + set isdirect [DecideIfDirect $dict min max direct] + if {$isdirect} { + DecodeDirect $name $min $max id direct + } + Tcl Iassoc $name $symbols $dict $nocase $last + Tcl EncoderTcl $name $nocase + Tcl DecoderTcl $name $isdirect $last + List Decoder+List $name + Tcl ArgType $name + Tcl ResultType $name + C EncoderC $name $nocase $last + C DecoderC $name $isdirect $last + return +} + +# # ## ### ##### ######## ############# ##################### +## Internals + +proc critcl::emap::DecoderTcl {name isdirect last} { + if {$isdirect} { + DecoderTclDirect $name + } else { + DecoderTclSearch $name $last + } + return +} + +proc critcl::emap::DecoderTclSearch {name last} { + # Decoder based on linear search. Because we either + # - see some symbolic values (= do not know actual value) + # - the direct mapping table would be too large (> 50 entries). + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + lappend map @LAST@ $last + + critcl::ccode \n[critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@_decode (Tcl_Interp* interp, int state) + { + /* Decode via linear search */ + char buf [20]; + int i; + @NAME@_iassoc_data context = @NAME@_iassoc (interp); + + for (i = 0; i < @LAST@; i++) { + if (@NAME@_emap_state [i] != state) continue; + return context->tcl [i]; + } + + sprintf (buf, "%d", state); + Tcl_AppendResult (interp, "Invalid @NAME@ state code ", buf, NULL); + Tcl_SetErrorCode (interp, "@UNAME@", "STATE", NULL); + return NULL; + } + }] + return +} + +proc critcl::emap::DecodeDirect {name min max iv dv} { + upvar 1 $iv id $dv direct + # Decoder based on a direct mapping table. We can do this because + # we found that all the values are pure integers, i.e. we know + # them in detail, and that the table is not too big (< 50 entries). + + lassign [DirectTable $min $max id direct] table size + + lappend map @NAME@ $name + lappend map @DIRECT@ $table + lappend map @SIZE@ $size + lappend map @MIN@ $min + lappend map @MAX@ $max + lappend map @OFFSET@ [Offset $min] + + critcl::ccode \n[critcl::at::here!][string map $map { + static int @NAME@_direct (int state) + { + static const int direct [@SIZE@] = {@DIRECT@ + }; + /* Check limits first */ + if (state < @MIN@) { return -1; } + if (state > @MAX@) { return -1; } + /* Map to string index */ + return direct [state@OFFSET@]; + } + }] +} + +proc critcl::emap::DecoderTclDirect {name} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + + critcl::ccode \n[critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@_decode (Tcl_Interp* interp, int state) + { + /* Decode via direct mapping */ + char buf [20]; + int i; + @NAME@_iassoc_data context = @NAME@_iassoc (interp); + + i = @NAME@_direct (state); + if (i < 0) { goto error; } + + /* Return the chosen string */ + return context->tcl [i]; + + error: + sprintf (buf, "%d", state); + Tcl_AppendResult (interp, "Invalid @NAME@ state code ", buf, NULL); + Tcl_SetErrorCode (interp, "@UNAME@", "STATE", NULL); + return NULL; + } + }] + return +} + +proc critcl::emap::Decoder+List {name} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + + # Note on perf: O(mc), for m states in the definition, and c + # states to convert. As the number of declared states is however + # fixed, and small, we can say O(c) for some larger constant + # factor. + + critcl::ccode \n[critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@_decode_list (Tcl_Interp* interp, int c, int* state) + { + int k; + Tcl_Obj* result = Tcl_NewListObj (0, 0); + /* Failed to create, abort immediately */ + if (!result) { + return result; + } + for (k=0; k < c; k++) { + Tcl_Obj* lit = @NAME@_decode (interp, state[k]); + if (lit && (TCL_OK == Tcl_ListObjAppendElement (interp, result, lit))) { + continue; + } + /* Failed to translate or append; release and abort */ + Tcl_DecrRefCount (result); + return NULL; + } + return result; + } + }] + return +} + +proc critcl::emap::DirectTable {min max iv dv} { + upvar 1 $iv id $dv direct + + set table {} + set fmt %[string length $max]d + + for {set i $min} {$i <= $max} {incr i} { + if {[info exists direct($i)]} { + set sym [lindex $direct($i) 0] + set code $id($sym) + lappend table "$code,\t/* [format $fmt $i] <=> \"$sym\" */" + } else { + lappend table "-1," + } + } + + return [list "\n\t\t [join $table "\n\t\t "]" [llength $table]] +} + +proc critcl::emap::Offset {min} { + if {$min == 0} { + return "" + } elseif {$min < 0} { + return "+[expr {0-$min}]" + } else { + # Note: The 0+... ensures that we get a decimal number. + return "-[expr {0+$min}]" + } +} + +proc critcl::emap::DecideIfDirect {dict minv maxv dv} { + upvar 1 $minv min $maxv max $dv direct + + set min {} + set max {} + + dict for {sym value} $dict { + # Manage a direct mapping table from stati to strings, if we + # can see the numeric value of all stati. + if {[string is integer -strict $value]} { + if {($min eq {}) || ($value < $min)} { set min $value } + if {($max eq {}) || ($value > $max)} { set max $value } + lappend direct($value) $sym + } else { + return 0 + } + } + + if {$min eq {}} { return 0 } + if {$max eq {}} { return 0 } + if {($max-$min) >= 50} { return 0 } + return 1 +} + +proc critcl::emap::EncoderTcl {name nocase} { + if {$nocase} { + EncoderTclNocase $name + } else { + EncoderTclPlain $name + } + return +} + +proc critcl::emap::EncoderTclPlain {name} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + + critcl::ccode \n[critcl::at::here!][string map $map { + int + @NAME@_encode (Tcl_Interp* interp, + Tcl_Obj* state, + int* result) + { + int id, res; + res = Tcl_GetIndexFromObj (interp, state, @NAME@_emap_cstr, "@NAME@", 0, &id); + if (res != TCL_OK) { + Tcl_SetErrorCode (interp, "@UNAME@", "STATE", NULL); + return TCL_ERROR; + } + + *result = @NAME@_emap_state [id]; + return TCL_OK; + } + }] + return +} + +proc critcl::emap::EncoderTclNocase {name} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + + critcl::ccode \n[critcl::at::here!][string map $map { + int + @NAME@_encode (Tcl_Interp* interp, + Tcl_Obj* state, + int* result) + { + int id, res; + /* -nocase :: We duplicate the state string, making it unshared, + * allowing us to convert in place. As the string may change + * length (shrinking) we have to reset the length after + * conversion. + */ + state = Tcl_DuplicateObj (state); + Tcl_SetObjLength(state, Tcl_UtfToLower (Tcl_GetString (state))); /* OK tcl9 */ + res = Tcl_GetIndexFromObj (interp, state, @NAME@_emap_cstr, "@NAME@", 0, &id); + Tcl_DecrRefCount (state); + if (res != TCL_OK) { + Tcl_SetErrorCode (interp, "@UNAME@", "STATE", NULL); + return TCL_ERROR; + } + + *result = @NAME@_emap_state [id]; + return TCL_OK; + } + }] + return +} + +proc critcl::emap::EncoderC {name nocase last} { + if {$nocase} { + EncoderCNocase $name $last + } else { + EncoderCPlain $name $last + } + return +} + +proc critcl::emap::EncoderCPlain {name last} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + lappend map @LAST@ $last + + # case-sensitive search + critcl::ccode \n[critcl::at::here!][string map $map { + #include + + int + @NAME@_encode_cstr (const char* state) + { + int id; + /* explicit linear search */ + for (id = 0; id < @LAST@; id++) { + if (strcmp (state, @NAME@_emap_cstr [id]) != 0) continue; + return @NAME@_emap_state [id]; + } + return -1; + } + }] + return +} + +proc critcl::emap::EncoderCNocase {name last} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + lappend map @LAST@ $last + + # case-insensitive search + critcl::ccode \n[critcl::at::here!][string map $map { + #include + + int + @NAME@_encode_cstr (const char* state) + { + /* -nocase :: We duplicate the state string, allowing us to + * convert in place. As the string may change length (shrink) + * we have to re-terminate it after conversion. + */ + int id, slen = 1 + strlen (state); + char* lower = ckalloc (slen); + + memcpy (lower, state, slen); + lower [Tcl_UtfToLower (lower)] = '\0'; + + /* explicit linear search */ + for (id = 0; id < @LAST@; id++) { + if (strcmp (lower, @NAME@_emap_cstr [id]) != 0) continue; + ckfree ((char*) lower); + return @NAME@_emap_state [id]; + } + ckfree ((char*) lower); + return -1; + } + }] + return +} + +proc critcl::emap::DecoderC {name isdirect last} { + if {$isdirect} { + DecoderCDirect $name + } else { + DecoderCSearch $name $last + } + return +} + +proc critcl::emap::DecoderCSearch {name last} { + # Decoder based on linear search. Because we either + # - see some symbolic values (= do not know actual value) + # - the direct mapping table would be too large (> 50 entries). + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + lappend map @LAST@ $last + + critcl::ccode \n[critcl::at::here!][string map $map { + const char* + @NAME@_decode_cstr (int state) + { + /* Decode via linear search */ + int id; + for (id = 0; id < @LAST@; id++) { + if (@NAME@_emap_state [id] != state) continue; + return @NAME@_emap_cstr [id]; + } + return NULL; + } + }] + return +} + +proc critcl::emap::DecoderCDirect {name} { + lappend map @NAME@ $name + lappend map @UNAME@ [string toupper $name] + + critcl::ccode \n[critcl::at::here!][string map $map { + const char* + @NAME@_decode_cstr (int state) + { + /* Decode via direct mapping */ + int i = @NAME@_direct (state); + if (i < 0) { return NULL; } + /* Return the chosen string */ + return @NAME@_emap_cstr [i]; + } + }] + return +} + +proc critcl::emap::ResultType {name} { + lappend map @NAME@ $name + critcl::resulttype $name \n[critcl::at::here!][string map $map { + /* @NAME@_decode result is 0-refcount */ + { Tcl_Obj* ro = @NAME@_decode (interp, rv); + if (ro == NULL) { return TCL_ERROR; } + Tcl_SetObjResult (interp, ro); + return TCL_OK; } + }] int + return +} + +proc critcl::emap::ArgType {name} { + lappend map @NAME@ $name + critcl::argtype $name \n[critcl::at::here!][string map $map { + if (@NAME@_encode (interp, @@, &@A) != TCL_OK) return TCL_ERROR; + }] int int + return +} + +proc critcl::emap::Header {name} { + # I. Generate a header file for inclusion by other parts of the + # package, i.e. csources. Include the header here as well, for + # the following blocks of code. + # + # Declaration of the en- and decoder functions. + upvar 1 mode mode + append h [HeaderIntro $name] + append h [Tcl HeaderTcl $name] + append h [List Header+List $name] + append h [C HeaderC $name] + append h [HeaderEnd $name] + critcl::include [critcl::make ${name}.h $h] + return +} + +proc critcl::emap::HeaderIntro {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + #ifndef @NAME@_EMAP_HEADER + #define @NAME@_EMAP_HEADER + + #include + }] +} + +proc critcl::emap::HeaderEnd {name} { + lappend map @NAME@ $name + return [string map $map { + #endif /* @NAME@_EMAP_HEADER */ + }] +} + +proc critcl::emap::HeaderTcl {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + /* "tcl" + * Encode a Tcl string into the corresponding state code + * Decode a state into the corresponding Tcl string + */ + extern int @NAME@_encode (Tcl_Interp* interp, Tcl_Obj* state, int* result); + extern Tcl_Obj* @NAME@_decode (Tcl_Interp* interp, int state); + }] +} + +proc critcl::emap::Header+List {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + /* "+list" + * Decode a set of states into a list of the corresponding Tcl strings + */ + extern Tcl_Obj* @NAME@_decode_list (Tcl_Interp* interp, int c, int* state); + }] +} + +proc critcl::emap::HeaderC {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + /* "c" + * Encode a C string into the corresponding state code + * Decode a state into the corresponding C string + */ + extern int @NAME@_encode_cstr (const char* state); + extern const char* @NAME@_decode_cstr (int state); + }] +} + +proc critcl::emap::Iassoc {name symbols dict nocase last} { + upvar 1 mode mode + critcl::iassoc def ${name}_iassoc {} \ + [IassocStructure $last] \ + [IassocInit $name $symbols $dict $nocase $last] \ + [IassocFinal $symbols $dict] + return +} + +proc critcl::emap::IassocStructure {last} { + lappend map @LAST@ $last + return \n[critcl::at::here!][string map $map { + Tcl_Obj* tcl [@LAST@]; /* State name, Tcl_Obj*, sharable */ + }] +} + +proc critcl::emap::IassocInit {name symbols dict nocase last} { + set id -1 + foreach sym $symbols { + set value [dict get $dict $sym] + incr id + if {$nocase} { set sym [string tolower $sym] } + set map [list @ID@ $id @SYM@ $sym @VALUE@ $value @NAME@ $name] + + # iassoc initialization, direct from string, no C level + append init \n[critcl::at::here!][string map $map { + data->tcl [@ID@] = Tcl_NewStringObj (@NAME@_emap_cstr[@ID@], -1); + Tcl_IncrRefCount (data->tcl [@ID@]); + }] + } + return $init +} + +proc critcl::emap::IassocFinal {symbols dict} { + set id -1 + foreach sym $symbols { + incr id + set map [list @ID@ $id] + append final \n[critcl::at::here!][string map $map { + Tcl_DecrRefCount (data->tcl [@ID@]); + }] + } + return $final +} + +proc critcl::emap::ConstStringTable {name symbols dict nocase last} { + # C level table initialization (constant data) + foreach sym $symbols { + set value [dict get $dict $sym] + if {$nocase} { set sym [string tolower $sym] } + append ctable "\n\t \"${sym}\"," + append stable "\n\t ${value}," + } + append ctable "\n\t 0" + set stable [string trimright $stable ,] + + lappend map @NAME@ $name + lappend map @STRINGS@ $ctable + lappend map @STATES@ $stable + lappend map @LAST@ $last + + critcl::ccode [critcl::at::here!][string map $map { + /* State names, C string */ + static const char* @NAME@_emap_cstr [@LAST@+1] = {@STRINGS@ + }; + + /* State codes */ + static int @NAME@_emap_state [@LAST@] = {@STATES@ + }; + }] + return +} + +proc critcl::emap::C {args} { + upvar 1 mode mode + if {!$mode(c)} return + return [uplevel 1 $args] +} + +proc critcl::emap::!C {args} { + upvar 1 mode mode + if {$mode(c)} return + return [uplevel 1 $args] +} + +proc critcl::emap::Tcl {args} { + upvar 1 mode mode + if {!$mode(tcl)} return + return [uplevel 1 $args] +} + +proc critcl::emap::!Tcl {args} { + upvar 1 mode mode + if {$mode(tcl)} return + return [uplevel 1 $args] +} + +proc critcl::emap::List {args} { + upvar 1 mode mode + if {!$mode(+list)} return + return [uplevel 1 $args] +} + +proc critcl::emap::!List {args} { + upvar 1 mode mode + if {$mode(+list)} return + return [uplevel 1 $args] +} + +proc critcl::emap::Index {dict iv sv lv} { + upvar 1 $iv id $sv symbols $lv last + # For the C level search we want lexicographically sorted elements + set symbols [lsort -dict [dict keys $dict]] + set i 0 + foreach s $symbols { + set id($s) $i + incr i + } + set last $i + # id :: symbol -> index (sorted) + return +} + +proc critcl::emap::Options {options} { + upvar 1 nocase nocase mode mode + set nocase 0 + set use tcl + + while {[llength $options]} { + set options [lassign $options o] + switch -glob -- $o { + -nocase - + -nocas - + -noca - + -noc - + -no - + -n { set nocase 1 } + -mode - + -mod - + -mo - + -m { set options [lassign $options use] } + -* - + default { + return -code error -errorcode {CRITCL EMAP INVALID-OPTION} \ + "Expected option -nocase, or -use, got \"$o\"" + } + } + } + Use $use + return +} + +proc critcl::emap::Use {use} { + # Use cases: tcl, c, both + upvar 1 mode mode + set uses 0 + foreach u {c tcl +list} { set mode($u) 0 } + foreach u $use { set mode($u) 1 ; incr uses } + if {$mode(+list)} { set mode(tcl) 1 } + if {$uses} return + return -code error "Need at least one use case (c, tcl, or +list)" +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::emap { + namespace export def + catch { namespace ensemble create } +} + +namespace eval ::critcl { + namespace export emap + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-emap/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-emap/pkgIndex.tcl new file mode 100644 index 00000000..f608bf57 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-emap/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::emap 1.3.1 [list source [file join $dir emap.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-enum/enum.tcl b/src/vfs/critcl.vfs/lib/critcl-enum/enum.tcl new file mode 100644 index 00000000..7541e9be --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-enum/enum.tcl @@ -0,0 +1,151 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# n/a + +# CriTcl Utility Commands. Generation of functions handling conversion +# from and to a C enum. Not a full Tcl_ObjType. Based on +# Tcl_GetIndexFromObj() instead. + +package provide critcl::enum 1.2.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.1.11 ; # make, include -- dict portability +package require critcl::literals 1.1 ; # String pool for conversion to Tcl. + +namespace eval ::critcl::enum {} + +# # ## ### ##### ######## ############# ##################### +## API: Generate the declaration and implementation files for the enum. + +proc ::critcl::enum::def {name dict {use tcl}} { + # Arguments are + # - the C name of the enumeration, and + # - dict of strings to convert. Key is the symbolic C name, value + # is the string. Numeric C value is in the order of the strings in + # the dict, treating it as list for that case. + # + # dict: C symbolic name -> Tcl string (Tcl symbolic name). + + if {![dict size $dict]} { + return -code error -errorcode {CRITCL ENUM DEF INVALID} \ + "Expected an enum definition, got empty string" + } + + set plist 0 + foreach m $use { + switch $m { + tcl {} + +list { set plist 1 } + default { + return -code error -errorcode {CRITCL ENUM DEF MODE INVALID} \ + "Unknown mode $m, expected one of \"+list\", or \"tcl\"" + } + } + } + + critcl::literals::def ${name}_pool $dict $use + + # _pool_names = C enum of symbolic names, and implied numeric values. + # _pool.h = Header + # _pool ( interp, code ) => Tcl_Obj* :: up-conversion C to Tcl. + + # Exporting: + # Header .h + # Function _ToObj (interp, code) -> obj + # Function _ToObjList (interp, count, code*) -> obj (**) + # Function _GetFromObj (interp, obj, flags, &code) -> Tcl code + # Enum type _names + # + # (**) Mode +list only. + + dict for {sym str} $dict { + lappend table "\t\t\"$str\"," + } + + lappend map @NAME@ $name + lappend map @TABLE@ \n[join $table \n] + lappend map @TSIZE@ [llength $table] + lappend map @TSIZE1@ [expr {1 + [llength $table]}] + + if {$plist} { + lappend map @PLIST@ \ + "\n #define ${name}_ToObjList(i,c,l) (${name}_pool_list(i,c,l))" + } else { + lappend map @PLIST@ "" + } + + critcl::include [critcl::make ${name}.h \n[critcl::at::here!][string map $map { + #ifndef @NAME@_HEADER + #define @NAME@_HEADER + #include <@NAME@_pool.h> + #include + + typedef @NAME@_pool_names @NAME@; + #define @NAME@_LAST @NAME@_pool_name_LAST + + extern int + @NAME@_GetFromObj (Tcl_Interp* interp, + Tcl_Obj* obj, + int flags, + int* literal); + + #define @NAME@_ToObj(i,l) (@NAME@_pool(i,l))@PLIST@ + #endif + }]] + + # Create second function, down-conversion Tcl to C. + + critcl::ccode [critcl::at::here!][string map $map { + extern int + @NAME@_GetFromObj (Tcl_Interp* interp, + Tcl_Obj* obj, + int flags, + int* literal ) + { + static const char* strings[@TSIZE1@] = {@TABLE@ + NULL + }; + + return Tcl_GetIndexFromObj (interp, obj, strings, + "@NAME@", + flags, literal); + } + }] + + + # V. Define convenient argument- and result-type definitions + # wrapping the de- and encoder functions for use by cprocs. + + critcl::argtype $name \n[critcl::at::here!][string map $map { + if (@NAME@_GetFromObj (interp, @@, TCL_EXACT, &@A) != TCL_OK) return TCL_ERROR; + }] int int + + critcl::argtype ${name}-prefix \n[critcl::at::here!][string map $map { + if (@NAME@_GetFromObj (interp, @@, 0, &@A) != TCL_OK) return TCL_ERROR; + }] int int + + # Use the underlying literal pool directly. + critcl::resulttype $name = ${name}_pool + return +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::enum { + namespace export def + catch { namespace ensemble create } +} + +namespace eval ::critcl { + namespace export enum + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-enum/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-enum/pkgIndex.tcl new file mode 100644 index 00000000..f7a9e188 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-enum/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::enum 1.2.1 [list source [file join $dir enum.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-iassoc/iassoc.tcl b/src/vfs/critcl.vfs/lib/critcl-iassoc/iassoc.tcl new file mode 100644 index 00000000..691d5cae --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-iassoc/iassoc.tcl @@ -0,0 +1,182 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# @mdgen OWNER: iassoc.h + +# CriTcl Utility Commands. Specification of a C function and structure +# associated with an interpreter made easy. + +package provide critcl::iassoc 1.2.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.1.13 ; # Need 'meta?' to get the package name. + # Need 'Deline' helper. +package require critcl::util ; # Use the package's Get/Put commands. + +namespace eval ::critcl::iassoc {} + +# # ## ### ##### ######## ############# ##################### +## API: Generate the declaration and implementation files for the iassoc. + +proc ::critcl::iassoc::def {name arguments struct constructor destructor} { + critcl::at::caller + critcl::at::incrt $arguments ; set sloc [critcl::at::get*] + critcl::at::incrt $struct ; set cloc [critcl::at::get*] + critcl::at::incrt $constructor ; set dloc [critcl::at::get] + + set struct $sloc$struct + set constructor $cloc$constructor + set destructor $dloc$destructor + + # Arguments: + # - name of the C function which will provide access to the + # structure. This name, with a fixed prefix is also used to + # identify the association within the interpreter, and for + # the structure's type. + # + # - C code declaring the structure's contents. + # - C code executed to initialize the structure. + # - C code executed to destroy the structure. + + # Note that this is, essentially, a singleton object, without + # methods. + + # Pull the package we are working on out of the system. + + set package [critcl::meta? name] + set qpackage [expr {[string match ::* $package] + ? "$package" + : "::$package"}] + lassign [uplevel 1 [list ::critcl::name2c $qpackage]] pns pcns package cpackage + + #puts "%%% pNS |$pns|" + #puts "%%% Pkg |$package|" + #puts "%%% pCNS |$pcns|" + #puts "%%% cPkg |$cpackage|" + #puts "%%% Name |$name|" + #puts "@@@ <<$data>>" + + set stem ${pcns}${cpackage}_iassoc_${name} + set type ${name}_data + set label critcl::iassoc/p=$package/a=$name + + set anames {} + if {[llength $arguments]} { + foreach {t v} $arguments { + lappend alist "$t $v" + lappend anames $v + } + set arguments ", [join $alist {, }]" + set anames ", [join $anames {, }]" + } + + lappend map "\t" {} + lappend map @package@ $package + lappend map @name@ $name + lappend map @stem@ $stem + lappend map @label@ $label + lappend map @type@ $type + lappend map @struct@ $struct + lappend map @argdecls@ $arguments + lappend map @argnames@ $anames + lappend map @constructor@ $constructor + lappend map @destructor@ $destructor + + #puts T=[string length $template] + + critcl::include [critcl::make ${name}.h \n[critcl::at::here!][string map $map { + #ifndef @name@_HEADER + #define @name@_HEADER + + #include + + typedef struct @type@__ { + @struct@ + } @type@__; + typedef struct @type@__* @type@; + + extern @type@ + @name@ (Tcl_Interp* interp@argdecls@); + + #endif + }]] + + # Note: Making the .c code a `csources` instead of including it + # directly is a backward incompatible API change (The C code does + # not see any preceding includes. Which may define things used + # in/by the user's constructor. Breaks the users of iassoc, like + # bitmap, emap, etc. -- change defered -- + critcl::include [critcl::make ${name}.c \n[critcl::at::here!][string map $map { + /* + * For package "@package@". + * Implementation of Tcl Interpreter Association "@name@". + * + * Support functions for structure creation and destruction. + */ + + static void + @stem@_Release (@type@ data, Tcl_Interp* interp) + { + @destructor@ + ckfree((char*) data); + } + + static @type@ + @stem@_Init (Tcl_Interp* interp@argdecls@) + { + @type@ data = (@type@) ckalloc (sizeof (@type@__)); + + @constructor@ + return data; + + error: + ckfree ((char*) data); + return NULL; + } + + /* + * Structure accessor, automatically creating it if the + * interpreter does not have it already, setting it up for + * destruction on interpreter shutdown. + */ + + @type@ + @name@ (Tcl_Interp* interp@argdecls@) + { + #define KEY "@label@" + + Tcl_InterpDeleteProc* proc = (Tcl_InterpDeleteProc*) @stem@_Release; + @type@ data; + + data = Tcl_GetAssocData (interp, KEY, &proc); + if (data) { + return data; + } + + data = @stem@_Init (interp@argnames@); + + if (data) { + Tcl_SetAssocData (interp, KEY, proc, (ClientData) data); + } + + return data; + #undef KEY + } + }]] + return +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::iassoc { + namespace export def + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-iassoc/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-iassoc/pkgIndex.tcl new file mode 100644 index 00000000..61ee1c52 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-iassoc/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::iassoc 1.2.1 [list source [file join $dir iassoc.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-literals/literals.tcl b/src/vfs/critcl.vfs/lib/critcl-literals/literals.tcl new file mode 100644 index 00000000..feaf5ac6 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-literals/literals.tcl @@ -0,0 +1,330 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# n/a + +# CriTcl Utility Package for Shared Tcl_Obj* literals of a package. +# Based on critcl::iassoc. +# +# Copyright (c) 20??-2023 Andreas Kupries + +package provide critcl::literals 1.4.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.1.11 ; # make, include -- dict portability +package require critcl::iassoc + +namespace eval ::critcl::literals {} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Embed C Code + +proc critcl::literals::def {name dict {use tcl}} { + # dict :: map (C symbolic name -> string) + Use $use + Header $name $dict + + C ConstStringTable $name $dict + C AccessorC $name + + Tcl Iassoc $name $dict + Tcl AccessorTcl $name + Tcl ResultType $name + + +List AccessorTcl+List $name + return +} + +# # ## ### ##### ######## ############# ##################### +## Internals + +proc critcl::literals::Use {use} { + # Use cases: tcl, c, both, +list-mode + upvar 1 mode mode + set uses 0 + foreach u {c tcl +list} { set mode($u) 0 } + foreach u $use { set mode($u) 1 ; incr uses } + # +list-mode is an extension of tcl mode, thus implies it + if {$mode(+list)} { set mode(tcl) 1 } + if {$uses} return + return -code error "Need at least one use case (c, +list, or tcl)" +} + +proc critcl::literals::ConstStringTable {name dict} { + # C level table initialization (constant data) + dict for {sym string} $dict { + append ctable "\n\t\"${string}\"," + } + append ctable "\n\t0" + + lappend map @NAME@ $name + lappend map @STRINGS@ $ctable + critcl::ccode [critcl::at::here!][string map $map { + static const char* @NAME@_literal[] = { + @STRINGS@ + }; + }] + return +} + +proc critcl::literals::Iassoc {name dict} { + upvar 1 mode mode + lappend map @NAME@ $name + critcl::iassoc def ${name}_iassoc {} \n[critcl::at::here!][string map $map { + /* Array of the string literals, indexed by the symbolic names */ + Tcl_Obj* literal [@NAME@_name_LAST]; + }] [IassocInit $name $dict] [IassocFinal $dict] + return +} + +proc critcl::literals::IassocFinal {dict} { + # Finalization code for iassoc structures + dict for {sym string} $dict { + append final "\n[critcl::at::here!]\n\tTcl_DecrRefCount (data->literal \[$sym\]);" + } + return $final +} + +proc critcl::literals::IassocInit {name dict} { + # Initialization code for iassoc structures. + # Details dependent on if C is supported together with Tcl, or not. + upvar 1 mode mode + return [C IassocInitWithC $name $dict][!C IassocInitTcl $dict] +} + +proc critcl::literals::IassocInitWithC {name dict} { + dict for {sym string} $dict { + set map [list @SYM@ $sym @NAME@ $name] + append init \n[critcl::at::here!][string map $map { + data->literal [@SYM@] = Tcl_NewStringObj (@NAME@_literal[@SYM@], -1); + Tcl_IncrRefCount (data->literal [@SYM@]); + }] + } + return $init +} + +proc critcl::literals::IassocInitTcl {dict} { + dict for {sym string} $dict { + set map [list @SYM@ $sym @STR@ $string] + append init \n[critcl::at::here!][string map $map { + data->literal [@SYM@] = Tcl_NewStringObj ("@STR@", -1); + Tcl_IncrRefCount (data->literal [@SYM@]); + }] + } + return $init +} + +proc critcl::literals::Header {name dict} { + # I. Generate a header file for inclusion by other parts of the + # package, i.e. csources. Include the header here as well, for + # the following blocks of code. + # + # Declarations of an enum of the symbolic names, plus the + # accessor function. + upvar 1 mode mode + append h [HeaderIntro $name $dict] + append h [Tcl HeaderTcl $name] + append h [+List HeaderTcl+List $name] + append h [C HeaderC $name] + append h [HeaderEnd $name] + critcl::include [critcl::make ${name}.h $h] + return +} + +proc critcl::literals::HeaderIntro {name dict} { + lappend map @NAME@ $name + lappend map @CODES@ [join [dict keys $dict] {, }] + return \n[critcl::at::here!][string map $map { + #ifndef @NAME@_LITERALS_HEADER + #define @NAME@_LITERALS_HEADER + + #include + + /* Symbolic names for the literals */ + typedef enum @NAME@_names { + @CODES@ + , @NAME@_name_LAST + } @NAME@_names; + }] +} + +proc critcl::literals::HeaderEnd {name} { + lappend map @NAME@ $name + return [string map $map { + #endif /* @NAME@_LITERALS_HEADER */ + }] +} + +proc critcl::literals::HeaderTcl {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + /* Tcl Accessor function for the literals */ + extern Tcl_Obj* + @NAME@ (Tcl_Interp* interp, @NAME@_names literal); + }] +} + +proc critcl::literals::HeaderTcl+List {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + /* Tcl "+list" Accessor function for the literals */ + extern Tcl_Obj* + @NAME@_list (Tcl_Interp* interp, int c, @NAME@_names* literal); + }] +} + +proc critcl::literals::HeaderC {name} { + lappend map @NAME@ $name + return \n[critcl::at::here!][string map $map { + /* C Accessor function for the literals */ + extern const char* @NAME@_cstr (@NAME@_names literal); + }] +} + +proc critcl::literals::ResultType {name} { + lappend map @NAME@ $name + critcl::resulttype $name \n[critcl::at::here!][string map $map { + /* @NAME@ result is effectively 0-refcount */ + Tcl_SetObjResult (interp, @NAME@ (interp, rv)); + return TCL_OK; + }] int +} + +proc critcl::literals::AccessorTcl {name} { + lappend map @NAME@ $name + critcl::ccode [critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@ (Tcl_Interp* interp, @NAME@_names literal) + { + if ((literal < 0) || (literal >= @NAME@_name_LAST)) { + Tcl_Panic ("Bad @NAME@ literal index %d outside [0...%d]", + literal, @NAME@_name_LAST-1); + } + return @NAME@_iassoc (interp)->literal [literal]; + } + }] + return +} + +proc critcl::literals::AccessorTcl+List {name} { + lappend map @NAME@ $name + critcl::ccode [critcl::at::here!][string map $map { + Tcl_Obj* + @NAME@_list (Tcl_Interp* interp, int c, @NAME@_names* literal) + { + int k; + for (k=0; k < c; k++) { + if ((literal[k] < 0) || (literal[k] >= @NAME@_name_LAST)) { + Tcl_Panic ("Bad @NAME@ literal index %d outside [0...%d]", + literal[k], @NAME@_name_LAST-1); + } + } + + Tcl_Obj* result = Tcl_NewListObj (0, 0); + if (!result) return result; + + for (k=0; k < c; k++) { + if (TCL_OK == Tcl_ListObjAppendElement (interp, result, @NAME@_iassoc (interp)->literal [literal [k]])) + continue; + /* Failed to append, release and abort */ + Tcl_DecrRefCount (result); + return 0; + } + + return result; + } + }] + return +} + +proc critcl::literals::AccessorC {name} { + upvar 1 mode mode + return [Tcl AccessorCWithTcl $name][!Tcl AccessorCRaw $name] +} + +proc critcl::literals::AccessorCWithTcl {name} { + # C accessor can use Tcl API + lappend map @NAME@ $name + critcl::ccode [critcl::at::here!][string map $map { + const char* + @NAME@_cstr (@NAME@_names literal) + { + if ((literal < 0) || (literal >= @NAME@_name_LAST)) { + Tcl_Panic ("Bad @NAME@ literal"); + } + return @NAME@_literal [literal]; + } + }] + return +} + +proc critcl::literals::AccessorCRaw {name} { + # C accessor has only basics + lappend map @NAME@ $name + critcl::ccode [critcl::at::here!][string map $map { + #include + const char* + @NAME@_cstr (@NAME@_names literal) + { + assert ((0 <= literal) && (literal < @NAME@_name_LAST)); + return @NAME@_literal [literal]; + } + }] + return +} + +proc critcl::literals::C {args} { + upvar 1 mode mode + if {!$mode(c)} return + return [uplevel 1 $args] +} + +proc critcl::literals::!C {args} { + upvar 1 mode mode + if {$mode(c)} return + return [uplevel 1 $args] +} + +proc critcl::literals::Tcl {args} { + upvar 1 mode mode + if {!$mode(tcl)} return + return [uplevel 1 $args] +} + +proc critcl::literals::!Tcl {args} { + upvar 1 mode mode + if {$mode(tcl)} return + return [uplevel 1 $args] +} + +proc critcl::literals::+List {args} { + upvar 1 mode mode + if {!$mode(+list)} return + return [uplevel 1 $args] +} + +proc critcl::literals::!+List {args} { + upvar 1 mode mode + if {$mode(+list)} return + return [uplevel 1 $args] +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::literals { + namespace export def + catch { namespace ensemble create } +} + +namespace eval ::critcl { + namespace export literals + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl-literals/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-literals/pkgIndex.tcl new file mode 100644 index 00000000..146857fe --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-literals/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::literals 1.4.1 [list source [file join $dir literals.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-md5c/md5c.tcl b/src/vfs/critcl.vfs/lib/critcl-md5c/md5c.tcl new file mode 100644 index 00000000..79500ccd --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-md5c/md5c.tcl @@ -0,0 +1,145 @@ +# md5c.tcl - +# +# Wrapper for RSA's Message Digest in C +# +# Written by Jean-Claude Wippler + +package require critcl 3.2 +package provide critcl_md5c 0.12 + +critcl::cheaders md5c_c/md5.h; # The RSA header file +critcl::csources md5c_c/md5.c; # The RSA MD5 implementation. + +critcl::ccode { + #include + #include "md5.h" + #include + + static + Tcl_ObjType md5_type; /* fast internal access representation */ + + static void + md5_free_rep(Tcl_Obj *obj) + { + MD5_CTX *mp = (MD5_CTX *) obj->internalRep.otherValuePtr; + Tcl_Free((char*)mp); + } + + static void + md5_dup_rep(Tcl_Obj *obj, Tcl_Obj *dup) + { + MD5_CTX *mp = (MD5_CTX *) obj->internalRep.otherValuePtr; + dup->internalRep.otherValuePtr = Tcl_Alloc(sizeof *mp); + memcpy(dup->internalRep.otherValuePtr, mp, sizeof *mp); + dup->typePtr = &md5_type; + } + + static void + md5_string_rep(Tcl_Obj *obj) + { + unsigned char buf[16]; + Tcl_Obj *temp; + char *str; + MD5_CTX dup = *(MD5_CTX *) obj->internalRep.otherValuePtr; + + MD5Final(buf, &dup); + + /* convert via a byte array to properly handle null bytes */ + temp = Tcl_NewByteArrayObj(buf, sizeof (buf)); /* OK tcl9 */ + Tcl_IncrRefCount(temp); + + str = Tcl_GetStringFromObj(temp, &obj->length); /* OK tcl9 */ + obj->bytes = Tcl_Alloc(obj->length + 1); + memcpy(obj->bytes, str, obj->length + 1); + + Tcl_DecrRefCount(temp); + } + + static int + md5_from_any(Tcl_Interp* ip, Tcl_Obj* obj) + { + assert(0); + return TCL_ERROR; + } + + static + Tcl_ObjType md5_type = { + "md5c", md5_free_rep, md5_dup_rep, md5_string_rep, md5_from_any + }; +} + +critcl::ccommand md5c {dummy ip objc objv} { + MD5_CTX *mp; + unsigned char *data; + Tcl_Size size; + Tcl_Obj *obj; + + if (objc < 2 || objc > 3) { + Tcl_WrongNumArgs(ip, 1, objv, "data ?context?"); /* OK tcl9 */ + return TCL_ERROR; + } + + if (objc == 3) { + if (objv[2]->typePtr != &md5_type && md5_from_any(ip, objv[2]) != TCL_OK) { + return TCL_ERROR; + } + obj = objv[2]; + if (Tcl_IsShared(obj)) { + obj = Tcl_DuplicateObj(obj); + } + } else { + mp = (MD5_CTX *)Tcl_Alloc(sizeof *mp); + MD5Init(mp); + obj = Tcl_NewObj(); + Tcl_InvalidateStringRep(obj); + obj->internalRep.otherValuePtr = mp; + obj->typePtr = &md5_type; + } + + mp = (MD5_CTX *) obj->internalRep.otherValuePtr; + + data = Tcl_GetBytesFromObj(ip, objv[1], &size); /* OK tcl9 */ + if (data == NULL) return TCL_ERROR; + + MD5Update(mp, data, size); + Tcl_SetObjResult(ip, obj); + + return TCL_OK; +} + +if {[info exists pkgtest] && $pkgtest} { + + proc md5c_try {} { + foreach {msg expected} { + "" + "d41d8cd98f00b204e9800998ecf8427e" + "a" + "0cc175b9c0f1b6a831c399e269772661" + "abc" + "900150983cd24fb0d6963f7d28e17f72" + "message digest" + "f96b697d7cb7938d525a2f31aaf161d0" + "abcdefghijklmnopqrstuvwxyz" + "c3fcd3d76192e4007dfb496cca67e13b" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "d174ab98d277d9f5a5611c2c9f419d9f" + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + "57edf4a22be3c955ac49da2e2107b67a" + } { + puts "testing: md5c \"$msg\"" + binary scan [md5c $msg] H* computed + puts "computed: $computed" + if {0 != [string compare $computed $expected]} { + puts "expected: $expected" + puts "FAILED" + } + } + + foreach len {10 50 100 500 1000 5000 10000} { + set blanks [format %$len.0s ""] + puts "input length $len: [time {md5c $blanks} 1000]" + } + } + + md5c_try +} diff --git a/src/vfs/critcl.vfs/lib/critcl-md5c/md5c_c/md5.c b/src/vfs/critcl.vfs/lib/critcl-md5c/md5c_c/md5.c new file mode 100644 index 00000000..0a8cafe4 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-md5c/md5c_c/md5.c @@ -0,0 +1,293 @@ +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** + *********************************************************************** + */ + +/* + * Edited 7 May 93 by CP to change the interface to match that + * of the MD5 routines in RSAREF. Due to this alteration, this + * code is "derived from the RSA Data Security, Inc. MD5 Message- + * Digest Algorithm". (See below.) + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#include "md5.h" + +/* + *********************************************************************** + ** Message-digest routines: ** + ** To form the message digest for a message M ** + ** (1) Initialize a context buffer mdContext using MD5Init ** + ** (2) Call MD5Update on mdContext and M ** + ** (3) Call MD5Final on mdContext ** + ** The message digest is now in the bugffer passed to MD5Final ** + *********************************************************************** + */ + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* The routine MD5Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301L; + mdContext->buf[1] = (UINT4)0xefcdab89L; + mdContext->buf[2] = (UINT4)0x98badcfeL; + mdContext->buf[3] = (UINT4)0x10325476L; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void MD5Update (mdContext, inBuf, inLen) +register MD5_CTX *mdContext; unsigned char *inBuf; + unsigned int inLen; +{ + register int i, ii; + int mdi; + UINT4 in[16]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ +void MD5Final (digest, mdContext) +unsigned char digest[16]; MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + digest[ii] = (unsigned char) (mdContext->buf[i] & 0xFF); + digest[ii+1] = (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + digest[ii+2] = (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + digest[ii+3] = (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } +} + +/* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious + Constants are arranged backwards in little-endian order and decrypted with + the DES they produce OCCULT MESSAGES! + */ +void Transform(buf, in) +register UINT4 *buf; +register UINT4 *in; +{ + register UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, 0xD76AA478L); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, 0xE8C7B756L); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, 0x242070DBL); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, 0xC1BDCEEEL); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, 0xF57C0FAFL); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, 0x4787C62AL); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, 0xA8304613L); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, 0xFD469501L); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, 0x698098D8L); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, 0x8B44F7AFL); /* 10 */ + FF ( c, d, a, b, in[10], S13, 0xFFFF5BB1L); /* 11 */ + FF ( b, c, d, a, in[11], S14, 0x895CD7BEL); /* 12 */ + FF ( a, b, c, d, in[12], S11, 0x6B901122L); /* 13 */ + FF ( d, a, b, c, in[13], S12, 0xFD987193L); /* 14 */ + FF ( c, d, a, b, in[14], S13, 0xA679438EL); /* 15 */ + FF ( b, c, d, a, in[15], S14, 0x49B40821L); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, 0xF61E2562L); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, 0xC040B340L); /* 18 */ + GG ( c, d, a, b, in[11], S23, 0x265E5A51L); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, 0xE9B6C7AAL); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, 0xD62F105DL); /* 21 */ + GG ( d, a, b, c, in[10], S22, 0x02441453L); /* 22 */ + GG ( c, d, a, b, in[15], S23, 0xD8A1E681L); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, 0xE7D3FBC8L); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, 0x21E1CDE6L); /* 25 */ + GG ( d, a, b, c, in[14], S22, 0xC33707D6L); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, 0xF4D50D87L); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, 0x455A14EDL); /* 28 */ + GG ( a, b, c, d, in[13], S21, 0xA9E3E905L); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, 0xFCEFA3F8L); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, 0x676F02D9L); /* 31 */ + GG ( b, c, d, a, in[12], S24, 0x8D2A4C8AL); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, 0xFFFA3942L); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, 0x8771F681L); /* 34 */ + HH ( c, d, a, b, in[11], S33, 0x6D9D6122L); /* 35 */ + HH ( b, c, d, a, in[14], S34, 0xFDE5380CL); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, 0xA4BEEA44L); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, 0x4BDECFA9L); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, 0xF6BB4B60L); /* 39 */ + HH ( b, c, d, a, in[10], S34, 0xBEBFBC70L); /* 40 */ + HH ( a, b, c, d, in[13], S31, 0x289B7EC6L); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, 0xEAA127FAL); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, 0xD4EF3085L); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, 0x04881D05L); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, 0xD9D4D039L); /* 45 */ + HH ( d, a, b, c, in[12], S32, 0xE6DB99E5L); /* 46 */ + HH ( c, d, a, b, in[15], S33, 0x1FA27CF8L); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, 0xC4AC5665L); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, 0xF4292244L); /* 49 */ + II ( d, a, b, c, in[ 7], S42, 0x432AFF97L); /* 50 */ + II ( c, d, a, b, in[14], S43, 0xAB9423A7L); /* 51 */ + II ( b, c, d, a, in[ 5], S44, 0xFC93A039L); /* 52 */ + II ( a, b, c, d, in[12], S41, 0x655B59C3L); /* 53 */ + II ( d, a, b, c, in[ 3], S42, 0x8F0CCC92L); /* 54 */ + II ( c, d, a, b, in[10], S43, 0xFFEFF47DL); /* 55 */ + II ( b, c, d, a, in[ 1], S44, 0x85845DD1L); /* 56 */ + II ( a, b, c, d, in[ 8], S41, 0x6FA87E4FL); /* 57 */ + II ( d, a, b, c, in[15], S42, 0xFE2CE6E0L); /* 58 */ + II ( c, d, a, b, in[ 6], S43, 0xA3014314L); /* 59 */ + II ( b, c, d, a, in[13], S44, 0x4E0811A1L); /* 60 */ + II ( a, b, c, d, in[ 4], S41, 0xF7537E82L); /* 61 */ + II ( d, a, b, c, in[11], S42, 0xBD3AF235L); /* 62 */ + II ( c, d, a, b, in[ 2], S43, 0x2AD7D2BBL); /* 63 */ + II ( b, c, d, a, in[ 9], S44, 0xEB86D391L); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + diff --git a/src/vfs/critcl.vfs/lib/critcl-md5c/md5c_c/md5.h b/src/vfs/critcl.vfs/lib/critcl-md5c/md5c_c/md5.h new file mode 100644 index 00000000..5627f627 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-md5c/md5c_c/md5.h @@ -0,0 +1,74 @@ +#ifndef MD5_H +#define MD5_H + +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + *********************************************************************** + */ + +/* + * Edited 7 May 93 by CP to change the interface to match that + * of the MD5 routines in RSAREF. Due to this alteration, this + * code is "derived from the RSA Data Security, Inc. MD5 Message- + * Digest Algorithm". (See below.) Also added argument names + * to the prototypes. + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +/* typedef a 32-bit unsigned integer type */ + +#include +#if UINT_MAX == 4294967295U + typedef unsigned int UINT4; +#elif ULONG_MAX == 4294967295UL + typedef unsigned long UINT4; +#else +#error "Unable to define UINT4, no 32bit unsigned integer type found" +#endif + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + UINT4 buf[4]; /* scratch buffer */ + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + unsigned char in[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init (MD5_CTX *mdContext); +void MD5Update (MD5_CTX *mdContext, unsigned char *buf, unsigned int len); +void MD5Final (unsigned char digest[16], MD5_CTX *mdContext); +void Transform (UINT4 *buf, UINT4 *in); + +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl-platform/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-platform/pkgIndex.tcl new file mode 100644 index 00000000..f2bd08b5 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-platform/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::platform 1.1.1 [list source [file join $dir platform.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-platform/platform.tcl b/src/vfs/critcl.vfs/lib/critcl-platform/platform.tcl new file mode 100644 index 00000000..fbfc5353 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-platform/platform.tcl @@ -0,0 +1,404 @@ +# -*- 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. + +package require Tcl 8.6 9 + +# ### ### ### ######### ######### ######### +## 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 -glob -- $plat { + cygwin* { + set plat cygwin + } + windows { + if {$tcl_platform(platform) == "unix"} { + set plat cygwin + } else { + 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 { + freebsd { + set abi [lindex [split $tcl_platform(osVersion) .] 0] + append plat $abi + return "${plat}-${cpu}" + } + 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-powerpc { + lappend res macosx-universal + } + macosx-x86_64 { + lappend res macosx-i386-x86_64 + } + macosx-ix86 { + lappend res macosx-universal macosx-i386-x86_64 + } + macosx*-* { + # 10.5+ + if {[regexp {macosx([^-]*)-(.*)} $id -> v cpu]} { + + switch -exact -- $cpu { + ix86 { + lappend alt i386-x86_64 + lappend alt universal + } + x86_64 { lappend 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} + foreach a $alt { + lappend res macosx${major}.${j}-$a + } + } + + # Add unversioned patterns for 10.3/10.4 builds. + lappend res macosx-${cpu} + foreach a $alt { + lappend res macosx-$a + } + } else { + # No version, just do unversioned patterns. + foreach a $alt { + lappend res macosx-$a + } + } + } else { + # no v, no cpu ... nothing + } + } + } + lappend res tcl ; # Pure tcl packages are always compatible. + return $res +} + + +# ### ### ### ######### ######### ######### +## Ready + +package provide critcl::platform 1.1.1 + +# ### ### ### ######### ######### ######### +## 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 +} diff --git a/src/vfs/critcl.vfs/lib/critcl-util/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl-util/pkgIndex.tcl new file mode 100644 index 00000000..d5262dee --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-util/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl::util 1.2.1 [list source [file join $dir util.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critcl-util/util.tcl b/src/vfs/critcl.vfs/lib/critcl-util/util.tcl new file mode 100644 index 00000000..22f758d6 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl-util/util.tcl @@ -0,0 +1,149 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# n/a + +# CriTcl Utility Commands. + +package provide critcl::util 1.2.1 + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Min supported version. +package require critcl 3.2 + +namespace eval ::critcl::util {} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Embed C Code + +proc ::critcl::util::locate {label paths {cmd {}}} { + # Locate a file across set of paths. + # Relative paths are to "::critcl::Here". + # Paths are run through subst for dynamic construction. + # A command prefix can be specified, to further check/process each found path. + # Result is the found path, as coming from the paths argument. + # Should go into cheader or similar command. + # Failure to find is reported via critcl::error + + foreach path $paths { + if {[file pathtype $path] eq "relative"} { + set fullpath [file normalize [file join [critcl::Here] $path]] + } else { + set fullpath $path + } + if {![file exists $fullpath]} continue + if {[llength $cmd] && ![uplevel 1 [linsert $cmd end $fullpath]]} continue + critcl::msg "${label}: $path" + return $path + } + critcl::error "${label}: not found, searched [linsert [join $paths {, }] end-1 and]" + return +} + +proc ::critcl::util::checkfun {name {label {}}} { + variable cftemplate + if {$label eq {}} { set label "Checking for function '$name'" } + return [critcl::checklink $label [string map [list @@@ $name] $cftemplate]] +} + +proc ::critcl::util::def {configfile define {value 1}} { + set result [file join [critcl::cache] [file tail $configfile]] + + Put $result "[Get $result]\n\#define $define $value\n" + return +} + +proc ::critcl::util::undef {configfile define} { + set result [file join [critcl::cache] [file tail $configfile]] + + Put $result "[Get $result]\n\#undef $define\n" + return +} + +# # ## ### ##### ######## ############# ##################### + +proc ::critcl::util::Get {path} { + if {[catch { + set c [open $path r] + set d [read $c] + close $c + }]} { + set d {} + } + return $d +} + +proc ::critcl::util::Put {path data} { + # Write changes back, via temp file. Commit via atomic rename. + set c [open $path.[pid] w] + puts -nonewline $c $data + close $c + file rename -force $path.[pid] $path + return +} + +# # ## ### ##### ######## ############# ##################### +## State + +namespace eval ::critcl::util { + variable cftemplate { + /* The header may declare @@@. To avoid a clash + * redefine it to something aside. As an example, gettimeofday() + * is declared in the provided by HP-UX 11i. Regardless, + * we pull in a system header defining the __stub macros, and a + * few prototypes only possibly in conflict with @@@, we hope. + * As exists even on free-standing compilers its use + * is preferred when __STDC__ is active. + */ + + #define @@@ innocuous_@@@ + #ifdef __STDC__ + # include + #else + # include + #endif + #undef @@@ + + /* Next up a declaration to override whatever internal prototype + * was declared by GCC, to prevent an error. As the return type + * 'int' might match such a GCC builtin, and thus causing the application + * of the argument prototype despite this we use 'char' instead. + */ + + #ifdef __cplusplus + extern "C" + #endif + char @@@ (); + + /* Lastly the GNU libc defines a few special names for its functions, + * these will always fail with ENONSYS. Further, some functions + * actually start with __, with the normal name (we are looking for) + * an alias of it. Regardless, for these we bail. + */ + + #if defined __stub_@@@ || defined __stub___@@@ + choke me + #endif + + int main () + { + return @@@ (); + ; + return 0; + } + } +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl::util { + namespace export checkfun def undef locate + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return diff --git a/src/vfs/critcl.vfs/lib/critcl/Config b/src/vfs/critcl.vfs/lib/critcl/Config new file mode 100644 index 00000000..185b968e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/Config @@ -0,0 +1,537 @@ +# -*- tcl -*- Critcl configuration file + +# some defaults - you can override these in the platform specific section +# but shouldn't need to for typical *nix toolchains using gcc +# +# platform sets the platform (defaults to platform::generic) +# target indicates that this is a cross-compile target, the value is the actual platform code. +# compile compile a C source file to an object file +# version print the compiler version number +# ldout See below +# link Command to link one or more object files and create a shared library +# embed_manifest Command to embed a manifest into a DLL. (Win-specific) +# link_debug See below +# link_preload Linker flags to use when dependent libraries are pre-loaded. +# link_release See below +# preproc_define preprocess C source file (for critcl::cdefines) +# preproc_enum ditto +# tclstubs cflag to set USE_TCL_STUBS +# tkstubs cflag to set USE_TK_STUBS +# debug_memory cflag to enable memory debugging +# debug_symbols cflag to add symbols to resulting library +# object file extension for object files +# output flags to set output file +# strip cflag to tell linker to strip symbols +# optimize cflag to specify optimization level +# include cflag to add an include directory +# noassert cflag to turn off assertions in Tcl code +# threadflags cflags to enable threaded build +# sharedlibext the platform's file extension for shared libraries +# +# (Support for Fortran) +# fcompile compile a Fortran source file to an object file +# fversion print the Fortran compiler version number +# flink link one or more object files and create a shared library, +# if at least one object file comes from Fortran +# foutput Fortran flag(s) to set output file +# finclude Fortran flag to add an include directory +# fextra_cflags Extra C flags for indicating type of Fortran compiler +# +# Any other config options are assumed to refer to Tcl variables and +# these are set when building so they can be used in the Critcl script. +# Typically this is used when defining cross-compile environments to set +# various tcl_platform() values. +# +# You can also set Tcl variables to use in "when" options (see the MacOSX +# section for an example - "set universal ..."). These commands and the +# "when" commands are run in a separate interpreter. +# +# You can also base a build configuration on an existing one by using +# the "copy" option and then specifically setting the config bits that +# you want to change. See win32-x86_64-cl for an example. + +compile gcc -c -fPIC +version gcc -v +link gcc -shared +include -I +libinclude -L +preproc_define gcc -E -dM +preproc_enum gcc -E +tclstubs -DUSE_TCL_STUBS +tkstubs -DUSE_TK_STUBS +debug_memory -DTCL_MEM_DEBUG +debug_symbols -g +object .o +output -o [list $outfile] +embed_manifest +ldoutput +link_debug +link_release +link_preload --unresolved-symbols=ignore-in-shared-libs +link_rpath -Wl,-rpath,@ +strip -Wl,-s +optimize -O2 +noassert -DNDEBUG +threadflags -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 \ + -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_READDIR_R=1 \ + -DTCL_THREADS=1 + +# platform specific stuff follows + +# OSX - check if universal binaries supported by the installed toolchain + +if {[string match macosx-* $platform]} { + if {[info exists ::env(SDKROOT)] && $::env(SDKROOT) ne ""} { + set SDKROOT $::env(SDKROOT) + } else { + # look for an SDK supporting universal binaries + set pos [string length MacOSX] + set sdklist {} + set base /Developer + catch {set base [exec xcode-select -print-path]} + foreach dir [glob -nocomplain -tails \ + -directory $base/SDKs MacOSX*] { + set ver [string trimright \ + [file rootname [string range $dir $pos end]] u] + if {"$ver" != "" && [package vcompare $ver 10.4] >= 0} { + # 10.4 is earliest supporting universal that we support + set path($ver) $dir + lappend sdklist $ver + } + } + if {[llength $sdklist]} { + set ver [lindex [lsort -command "package vcompare" $sdklist] 0] + set SDKROOT $base/SDKs/$path($ver) + } else { + set SDKROOT "" + } + } + if {$SDKROOT ne ""} { + # get the SDKsettings for the min OSX value supported + set info "" + if [catch { + set info [exec defaults read $SDKROOT/SDKSettings buildSettings] + }] { + catch { + set info [exec defaults read $SDKROOT/SDKSettings DefaultProperties \ + -dict MACOSX_DEPLOYMENT_TARGET] + } + } + if {$info eq ""} { + puts stderr "SDKROOT isn't configured correctly on this host" + puts stderr "current setting $SDKROOT needs updating" + exit 1 + } + set info [string trim $info] + regsub -all {[\n"\;=\{\}]+} $info "" info ;#" help emacs hilighting + regsub -all {\s+} $info " " info + set osxmin [lindex $info 1] + } else { + # use the current platform + foreach {v1 v2 v3} [split $::tcl_platform(osVersion) .] break + incr v1 -4 + set osxmin 10.$v1.$v2 + # do we actually need to check if universal is supported, given the + # gcc check below will do it for us? + # set info [exec lipo -info /usr/lib/libSystem.dylib] + # set plats [split [string trim [lindex [split $info :] 2]]] + } + if {[info exists ::env(osxmin)] && $::env(osxmin) ne ""} { + set osxmin $::env(osxmin) + } + set universal 0 + catch { + set ppc [expr {[exec gcc -v -arch ppc > /dev/null 2>@stdout] eq ""}] + set ppc64 [expr {[exec gcc -v -arch ppc64 > /dev/null 2>@stdout] eq ""}] + set i386 [expr {[exec gcc -v -arch i386 > /dev/null 2>@stdout] eq ""}] + set x86_64 [expr {[exec gcc -v -arch x86_64 > /dev/null 2>@stdout] eq ""}] + } +} + +# Note: The result of 'platform::generic' is used to restrict which of +# the following blocks will be considered. + +# Note 2: The platform declarations are required to set up a proper +# mapping in pkgIndex.tcl of a -pkg. + +# default on OSX ppc is universal containing ppc and x86 32 bit +macosx-powerpc when $ppc +macosx-powerpc compile gcc -c -arch ppc \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-powerpc link gcc -bundle -arch ppc \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-powerpc link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 +macosx-powerpc strip + +# default on OSX intel is universal containing x86 32 and 64 bit +macosx-ix86 when $i386 && $x86_64 +macosx-ix86 compile gcc -c -arch i386 -arch x86_64 \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-ix86 link gcc -bundle -arch i386 -arch x86_64 \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-ix86 link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 +macosx-ix86 strip +macosx-ix86 platform macosx-ix86 $osxmin \ + macosx-ix86 \ + macosx-x86_64 + +# target for most common architectures +macosx-most when $ppc && $i386 && $x86_64 +macosx-most compile gcc -c -arch i386 -arch x86_64 -arch ppc \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-most link gcc -bundle -arch i386 -arch x86_64 -arch ppc \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-most link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 +macosx-most strip +macosx-most platform macosx-most $osxmin \ + macosx-powerpc \ + macosx-ix86 \ + macosx-x86_64 + +# target for old universal, ppc and x86 32. +macosx-universal when $ppc && $i386 +macosx-universal compile gcc -c -arch i386 -arch ppc \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-universal link gcc -bundle -arch i386 -arch ppc \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-universal link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 +macosx-universal strip +macosx-universal platform macosx-universal $osxmin \ + macosx-powerpc \ + macosx-ix86 + +# target for all architectures +macosx-all when $ppc && $ppc64 && $i386 && $x86_64 +macosx-all compile gcc -c -arch i386 -arch x86_64 -arch ppc -arch ppc64 \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-all link gcc -bundle -arch i386 -arch x86_64 -arch ppc -arch ppc64 \ + -isysroot $SDKROOT \ + -mmacosx-version-min=$osxmin +macosx-all link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 +macosx-all strip +macosx-all platform macosx-all $osxmin \ + macosx-powerpc \ + macosx-powerpc64 \ + macosx-ix86 \ + macosx-x86_64 + +# OSX ppc 32 bit +macosx-ppc32 when $ppc +macosx-ppc32 compile gcc -c -arch ppc +macosx-ppc32 link gcc -bundle -arch ppc +macosx-ppc32 link_preload -undefined dynamic_lookup +macosx-ppc32 strip +macosx-ppc32 platform macosx-powerpc + +# OSX ppc 64 bit +macosx-ppc64 when $ppc64 +macosx-ppc64 compile gcc -c -arch ppc64 +macosx-ppc64 link gcc -bundle -arch ppc64 +macosx-ppc64 link_preload -undefined dynamic_lookup +macosx-ppc64 strip +macosx-ppc64 platform macosx-powerpc64 + +# OSX x86 32 bit +macosx-x86_32 when $i386 +macosx-x86_32 compile gcc -c -arch i386 +macosx-x86_32 link gcc -bundle -arch i386 +macosx-x86_32 link_preload -undefined dynamic_lookup +macosx-x86_32 strip +macosx-x86_32 platform macosx-ix86 + +# OSX x86 64 bit +macosx-x86_64 when $x86_64 +macosx-x86_64 compile gcc -c -arch x86_64 +macosx-x86_64 link gcc -bundle -arch x86_64 +macosx-x86_64 link_preload -undefined dynamic_lookup +macosx-x86_64 strip +macosx-x86_64 platform macosx-x86_64 + +# Linux - 32 bit or 64 bit build - select using "-target" if you don't +# want the platform default (32 on 32, 64 on 64). This requires +# some work to detect the cpu class in use and then set a platform +# with the proper variant name. + +if {[string match linux-* $platform]} { + # platform = os-cpu(-compiler) + set cpu [lindex [split $platform -] 1] + + switch -- $cpu { + x86_64 - ix86 { + set cpu32 ix86 + set cpu64 x86_64 + } + * { + #error "Unknown architecture" + set cpu32 unknown32fixme_$cpu + set cpu64 unknown64fixme_$cpu + } + } +} + +linux-32-* compile gcc -c -m32 +linux-32-* link gcc -shared -m32 +linux-32-* platform linux-$cpu32 + +linux-64-* compile gcc -c -m64 +linux-64-* link gcc -shared -m64 +linux-64-* platform linux-$cpu64 + +# Windows - Check if bufferoverflowU.lib is required, or not. We +# assume that "requiredness" coincides with "presence". IOW, if the +# library is present in the LIB search paths, then it is required. +# This should be ok, for linking to it when it is present but not +# required, should do no harm. + +set msvc 0 +if {[string match win32-* $platform]} { + set cl [file nativename [lindex [auto_execok cl] 0]] + if {$cl ne ""} { + set msvc 1 + + set msvcbufferoverflowlib "" + foreach p [split $::env(LIB) \;] { + if {[llength [glob -nocomplain -directory $p bufferoverflowu.lib]]} { + set msvcbufferoverflowlib bufferoverflowU.lib + break + } + } + + set tmpfile $::env(TMP)/[pid].txt + catch { exec $cl 2> $tmpfile > NUL: } msg + #puts "M $msg" + set chan [open $tmpfile r] + set output [read $chan] + #puts "O $output" + close $chan + file delete $tmpfile + + regexp {Version ([0-9.]*)} $output -> msvcversion + #puts V=$msvcversion + if {[package vcompare $msvcversion 15.00.30729.01] >= 0} { + # VC9 or higher. -debug:full is not supported anymore. + # VC9 - warning, VC10 - error + set msvclinkdebug -debug + # Enable local stack checks for buffer overflow + set msvcstackchecks -GS + # -GZ deprecated in favor of -RTC1 + set msvcdebugchecks -RTC1 + set msvclinkglobaloptimize -ltcg + } else { + set msvclinkdebug -debug:full + set msvcdebugchecks -GZ + set msvcstackchecks "" + set msvclinkglobaloptimize "" + } + + if {[package vcompare $msvcversion 14] >= 0} { + # -Op not supported or needed. Use -fp instead to match Tcl + set msvcfpopt -fp:strict + set msvclinkworkingset "" + } else { + # -Op -> floating point consistency + set msvcfpopt -Op + # Working set optimization + set msvclinkworkingset -ws:aggressive + } + } +} + +# Windows - using 32-bit MS VC++ +# +# Note: the language option for cl is -TC for c and -TP for c++ or +# it can treat single files -Tc +# +win32-ix86-cl when $msvc +win32-ix86-cl compile cl -nologo -c +win32-ix86-cl link link -nologo +win32-ix86-cl embed_manifest mt -manifest [list $outfile].manifest -outputresource:[list $outfile]\;2 +win32-ix86-cl preproc_define cl -nologo -E +win32-ix86-cl preproc_enum cl -nologo -E +win32-ix86-cl libinclude /LIBPATH: +win32-ix86-cl object .obj +win32-ix86-cl debug_symbols -W3 -Od -Zi $msvcstackchecks $msvcdebugchecks -MDd -D_DEBUG $msvcfpopt +win32-ix86-cl optimize -W3 -O2 -MD $msvcstackchecks $msvcfpopt +win32-ix86-cl output [list -Fo$outfile] +win32-ix86-cl ldoutput -dll [list -out:$outfile] +win32-ix86-cl link_debug $msvclinkdebug -debugtype:cv -verbose:lib -nodefaultlib:libc +win32-ix86-cl link_release -release -opt:ref -opt:icf,3 $msvclinkworkingset -verbose:lib $msvclinkglobaloptimize +win32-ix86-cl link_preload +win32-ix86-cl link_rpath +win32-ix86-cl strip +win32-ix86-cl version cl +win32-ix86-cl platform win32-ix86 + +# Windows - using 64-bit MS VC++ +# +# Note: the language option for cl is -TC for c and -TP for c++ or +# it can treat single files -Tc +# + +win32-x86_64-cl when $msvc +win32-x86_64-cl copy win32-ix86-cl +win32-x86_64-cl link_debug $msvclinkdebug -debugtype:cv -verbose:lib $msvcbufferoverflowlib +win32-x86_64-cl link_release -release -opt:ref -opt:icf,3 $msvclinkworkingset -verbose:lib $msvclinkglobaloptimize $msvcbufferoverflowlib +win32-x86_64-cl platform win32-x86_64 + +# Cross-compile for Windows using Xmingwin +mingw32 target win32-ix86 +mingw32 compile gcc -c -nostdlib +mingw32 link gcc -shared +mingw32 link_preload +mingw32 sharedlibext .dll +mingw32 tcl_platform(byteOrder) littleEndian +mingw32 tcl_platform(machine) intel +mingw32 tcl_platform(os) Windows NT +mingw32 tcl_platform(osVersion) 5.0 +mingw32 tcl_platform(platform) windows +mingw32 tcl_platform(wordSize) 4 + +# Cross-compile for ARM (n770/Zaurus/etc) using Scratchbox et al +linux-arm target +linux-arm sharedlibext .so +linux-arm tcl_platform(byteOrder) littleEndian +linux-arm tcl_platform(machine) arm +linux-arm tcl_platform(os) Linux +linux-arm tcl_platform(osVersion) 2.6 +linux-arm tcl_platform(platform) unix +linux-arm tcl_platform(wordSize) 4 + +# hpux itanium, native cc, 32 and 64bit builds. +# +z <=> -fPIC on hpux. +# +DD64 invokes the 64bit mode. + +hpux-ia64_32-cc compile cc -c +z +hpux-ia64_32-cc link ld -b +hpux-ia64_32-cc preproc_define cc -E +hpux-ia64_32-cc preproc_enum cc -E +hpux-ia64_32-cc link_preload +hpux-ia64_32-cc strip + +hpux-ia64-cc compile cc -c +z +DD64 +hpux-ia64-cc link ld -b +hpux-ia64-cc preproc_define cc -E +hpux-ia64-cc preproc_enum cc -E +hpux-ia64-cc link_preload +hpux-ia64-cc strip + +# hpux, itanium, gcc +# This works only if the -lgcc for 64bit is somewhere reachable. +# hpux-ia64 gcc -c -fPIC -mlp64 + +hpux-parisc-cc compile cc -c +z +DAportable +hpux-parisc-cc link ld -b +hpux-parisc-cc preproc_define cc -E +hpux-parisc-cc preproc_enum cc -E +hpux-parisc-cc link_preload +hpux-parisc-cc strip + +hpux-parisc64-cc compile cc -c +z +DA2.0W +hpux-parisc64-cc link ld -b +hpux-parisc64-cc preproc_define cc -E +hpux-parisc64-cc preproc_enum cc -E +hpux-parisc64-cc link_preload +hpux-parisc64-cc strip + +# hpux-parisc, 64bit, gcc +# +# For this architecture gcc does not have compiler switches for change +# between 32/64 results. Rather, gcc has to be built specifically to +# produce either 32 or 64 bit binaries. And if both results are +# wanted, it has to be built and installed twice (in different +# directories). +# +# HP provides precompiled binaries of these two variants at +# http://www.hp.com/go/gcc. Install the desired compiler(s). In case +# of having both ensure that the desired one is first in the PATH. + +# aix, rs6000/powerpc, native cc, 32bit build +# The link line is pretty much copied from Tcl. + +# NOTE: ldAix was copied from Tcl into a directory in the PATH. + +# It might make sense to stuff this file into critcl and then copy it +# out when needed, either into a fixed place, or tempdir. In the +# latter case the link line needs some way of getting the value +# substituted into it. I have no idea of the critcl config allows +# that, and if yes, nor how. + +# cc_r = something with thread-enabled. better use it than cc and have +# things fail. + +aix-powerpc-cc compile cc_r -c -O +aix-powerpc-cc link ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -lm -lc +aix-powerpc-cc preproc_define cc -E +aix-powerpc-cc preproc_enum cc -E +aix-powerpc-cc link_preload +aix-powerpc-cc strip + +aix-powerpc64-cc compile cc_r -c -O -q64 +aix-powerpc64-cc link ldAix /bin/ld -b64 -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -lm -lc +aix-powerpc64-cc preproc_define cc -E +aix-powerpc64-cc preproc_enum cc -E +aix-powerpc64-cc link_preload +aix-powerpc64-cc strip + +aix-powerpc-xlc compile xlc_r -c -O +aix-powerpc-xlc link ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -lm -lc +aix-powerpc-xlc preproc_define xlc -E +aix-powerpc-xlc preproc_enum xlc -E +aix-powerpc-xlc link_preload +aix-powerpc-xlc strip + +aix-powerpc64-xlc compile xlc_r -c -O -q64 +aix-powerpc64-xlc link ldAix /bin/ld -b64 -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -lm -lc +aix-powerpc64-xlc preproc_define xlc -E +aix-powerpc64-xlc preproc_enum xlc -E +aix-powerpc64-xlc link_preload +aix-powerpc64-xlc strip + +# Solaris, Sparc and Intel platforms, 32 and 64 bit + +solaris-x86_64-cc compile cc -m64 -c -KPIC +solaris-x86_64-cc link /usr/ccs/bin/ld -L/lib/64 -G -lc -lnsl +solaris-x86_64-cc preproc_define cc -E +solaris-x86_64-cc preproc_enum cc -E +solaris-x86_64-cc version cc -V +solaris-x86_64-cc link_preload +solaris-x86_64-cc strip + +solaris-x86_64-gcc compile gcc -m64 -c -fPIC +solaris-x86_64-gcc link gcc -m64 -shared + +solaris-ix86-cc compile cc -m32 -c -KPIC +solaris-ix86-cc link /usr/ccs/bin/ld -G -lc -lnsl +solaris-ix86-cc preproc_define cc -E +solaris-ix86-cc preproc_enum cc -E +solaris-ix86-cc version cc -V +solaris-ix86-cc link_preload +solaris-ix86-cc strip + +solaris-sparc-cc compile cc -KPIC -c +solaris-sparc-cc link /usr/ccs/bin/ld -G -lc -lnsl +solaris-sparc-cc preproc_define cc -E +solaris-sparc-cc preproc_enum cc -E +solaris-sparc-cc version cc -V +solaris-sparc-cc link_preload +solaris-sparc-cc strip + +solaris-sparc64-cc compile cc -KPIC -xarch=v9 -c +solaris-sparc64-cc link /usr/ccs/bin/ld -G -lc -lnsl +solaris-sparc64-cc preproc_define cc -E +solaris-sparc64-cc preproc_enum cc -E +solaris-sparc64-cc version cc -V +solaris-sparc64-cc link_preload +solaris-sparc64-cc strip + +solaris-sparc64-gcc compile gcc -m64 -c -fPIC -mcpu=v9 +solaris-sparc64-gcc link gcc -m64 -shared -mcpu=v9 diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl.tcl b/src/vfs/critcl.vfs/lib/critcl/critcl.tcl new file mode 100644 index 00000000..212847c8 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl.tcl @@ -0,0 +1,6832 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +# Pragmas for MetaData Scanner. +# @mdgen OWNER: Config +# @mdgen OWNER: critcl_c +# +# Copyright (c) 2001-20?? Jean-Claude Wippler +# Copyright (c) 2002-20?? Steve Landers +# Copyright (c) 20??-2023 Andreas Kupries + +# # ## ### ##### ######## ############# ##################### +# CriTcl Core. + +package provide critcl 3.2.1 + +namespace eval ::critcl {} + +# # ## ### ##### ######## ############# ##################### +## Requirements. + +package require Tcl 8.6 9 ; # Minimal supported Tcl runtime. +if {[catch { + package require platform 1.0.2 ; # Determine current platform. +}]} { + # Fall back to our internal copy (currently equivalent to platform + # 1.0.14(+)) if the environment does not have the official + # package. + package require critcl::platform +} elseif { + [string match freebsd* [platform::generic]] && + ([platform::generic] eq [platform::identify]) +} { + # Again fall back to the internal package if we are on FreeBSD and + # the official package does not properly identify the OS ABI + # version. + package require critcl::platform +} + +# # ## ### ##### ######## ############# ##################### +## https://github.com/andreas-kupries/critcl/issues/112 +# +## Removed the code ensuring that we have maximal 'info frame' data, +## if supported. This code was moved into the app-critcl package +## instead. +# +## The issue with having it here is that this changes a global setting +## of the core, i.e. this will not only affect critcl itself when +## building binaries, but also the larger environment, i.e. the +## application using critcl. Given that this feature being active +## slows the Tcl core down by about 10%, sometimes more this is not a +## good decision to make on behalf of the user. +# +## In the critcl application itself I am willing to pay the price for +## the more precise location information in case of compilation +## failures, and the isolation to that application. For the +## dynamically `compile & run` in arbitrary environments OTOH not. + +# # ## ### ##### ######## ############# ##################### +# This is the md5 package bundled with critcl. +# No need to look for fallbacks. + +proc ::critcl::md5_hex {s} { + if {$v::uuidcounter} { + return [format %032d [incr v::uuidcounter]] + } + package require critcl_md5c + # As `s` is an arbitrary string of unknown origin we cannot assume + # that it contains byte data. And we definitely cannot assume that + # it only contains ASCII characters. For MD5 to operate correctly + # we have to convert the string into a proper series of bytes. + binary scan [md5c [encoding convertto utf-8 $s]] H* md; return $md +} + +# # ## ### ##### ######## ############# ##################### + +proc ::critcl::lappendlist {lvar list} { + if {![llength $list]} return + upvar $lvar dest + lappend dest {*}$list + return +} + +# # ## ### ##### ######## ############# ##################### +## + +proc ::critcl::buildrequirement {script} { + # In regular code this does nothing. It is a marker for + # the static scanner to change under what key to record + # the 'package require' found in the script. + uplevel 1 $script +} + +proc ::critcl::TeapotPlatform {} { + # Platform identifier HACK. Most of the data in critcl is based on + # 'platform::generic'. The TEApot MD however uses + # 'platform::identify' with its detail information (solaris kernel + # version, linux glibc version). But, if a cross-compile is + # running we are SOL, because we have no place to pull the + # necessary detail from, 'identify' is a purely local operation :( + + set platform [actualtarget] + if {[platform::generic] eq $platform} { + set platform [platform::identify] + } + + return $platform +} + +proc ::critcl::TeapotRequire {dspec} { + # Syntax of dspec: (a) pname + # ...: (b) pname req-version... + # ...: (c) pname -exact req-version + # + # We can assume that the syntax is generally ok, because otherwise + # the 'package require' itself will fail in a moment, blocking the + # further execution of the .critcl file. So we only have to + # distinguish the cases. + + if {([llength $dspec] == 3) && + ([lindex $dspec 1] eq "-exact")} { + # (c) + lassign $dspec pn _ pv + set spec [list $pn ${pv}-$pv] + } else { + # (a, b) + set spec $dspec + } + + return $spec +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Embed C Code + +proc ::critcl::HeaderLines {text} { + if {![regexp {^[\t\n ]+} $text header]} { + return [list 0 $text] + } + set lines [regexp -all {\n} $header] + # => The C code begins $lines lines after location of the c** + # command. This goes as offset into the generated #line pragma, + # because now (see next line) we throw away this leading + # whitespace. + set text [string trim $text] + return [list $lines $text] +} + +proc ::critcl::Lines {text} { + set n [regexp -all {\n} $text] + return $n +} + +proc ::critcl::ccode {text} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + CCodeCore $file $text + return +} + +proc ::critcl::CCodeCore {file text} { + set digest [UUID.extend $file .ccode $text] + + set block {} + lassign [HeaderLines $text] leadoffset text + Transition9Check [at::Loc $leadoffset -3 $file] $text + if {$v::options(lines)} { + append block [at::CPragma $leadoffset -3 $file] + } + + append block $text \n + dict update v::code($file) config c { + dict lappend c fragments $digest + dict set c block $digest $block + dict lappend c defs $digest + } + return +} + +proc ::critcl::ccommand {name anames args} { + SkipIgnored [set file [This]] + HandleDeclAfterBuild + + # Basic key for the clientdata and delproc arrays. + set cname $name[UUID.serial $file] + + if {[llength $args]} { + set body [lindex $args 0] + set args [lrange $args 1 end] + } else { + set body {} + } + + set clientdata NULL ;# Default: ClientData expression + set delproc NULL ;# Default: Function pointer expression + set acname 0 + set tname "" + while {[string match "-*" $args]} { + switch -- [set opt [lindex $args 0]] { + -clientdata { set clientdata [lindex $args 1] } + -delproc { set delproc [lindex $args 1] } + -cname { set acname [lindex $args 1] } + -tracename { set tname [lindex $args 1] } + default { + error "Unknown option $opt, expected one of -clientdata, -cname, -delproc" + } + } + set args [lrange $args 2 end] + } + + # Put body back into args for integration into the MD5 uuid + # generated for mode compile&run. Bug and fix reported by Peter + # Spjuth. + lappend args $body + + if {$acname} { + BeginCommand static $name $anames $args + set ns {} + set cns {} + set key $cname + set wname $name + if {$tname ne {}} { + set traceref \"$tname\" + } else { + set traceref \"$name\" + } + } else { + lassign [BeginCommand public $name $anames $args] ns cns name cname + set key [string map {:: _} $ns$cname] + set wname tcl_$cns$cname + set traceref ns_$cns$cname + } + + # XXX clientdata/delproc, either note clashes, or keep information per-file. + + set v::clientdata($key) $clientdata + set v::delproc($key) $delproc + + #set body [join $args] + if {$body != ""} { + lappend anames "" + foreach {cd ip oc ov} $anames break + if {$cd eq ""} { set cd clientdata } + if {$ip eq ""} { set ip interp } + if {$oc eq ""} { set oc objc } + if {$ov eq ""} { set ov objv } + + set ca "(ClientData $cd, Tcl_Interp *$ip, Tcl_Size $oc, Tcl_Obj *CONST $ov\[])" + + if {$v::options(trace)} { + # For ccommand tracing we will emit a shim after the implementation. + # Give the implementation a different name. + Emitln "static int\n${wname}_actual$ca" + } else { + Emitln "static int\n$wname$ca" + } + + Emit \{\n + lassign [HeaderLines $body] leadoffset body + Transition9Check [at::Loc $leadoffset -2 $file] $body + if {$v::options(lines)} { + Emit [at::CPragma $leadoffset -2 $file] + } + Emit $body + Emitln \n\} + + # Now emit the call to the ccommand tracing shim. It simply + # calls the regular implementation and places the tracing + # around that. + if {$v::options(trace)} { + Emitln "\nstatic int\n$wname$ca" + Emitln \{ + Emitln " int _rv;" + Emitln " critcl_trace_cmd_args ($traceref, $oc, $ov);" + Emitln " _rv = ${wname}_actual ($cd, $ip, $oc, $ov);" + Emitln " return critcl_trace_cmd_result (_rv, $ip);" + Emitln \} + } + } else { + # if no body is specified, then $anames is alias for the real cmd proc + Emitln "#define $wname $anames" + Emitln "int $anames\(\);" + } + EndCommand + return +} + +proc ::critcl::cdata {name data} { + SkipIgnored [This] + HandleDeclAfterBuild + binary scan $data c* bytes ;# split as bytes, not (unicode) chars + + set inittext "" + set line "" + foreach x $bytes { + if {[string length $line] > 70} { + append inittext " " $line \n + set line "" + } + append line $x , + } + append inittext " " $line + + set count [llength $bytes] + + set body [subst [Cat [Template cdata.c]]] + # ^=> count, inittext + + # NOTE: The uplevel is needed because otherwise 'ccommand' will + # not properly determine the caller's namespace. + uplevel 1 [list critcl::ccommand $name {dummy ip objc objv} [at::caller!]$body] + return $name +} + +proc ::critcl::cdefines {defines {namespace "::"}} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + set digest [UUID.extend $file .cdefines [list $defines $namespace]] + + dict update v::code($file) config c { + foreach def $defines { + dict set c const $def $namespace + } + } + return +} + +proc ::critcl::MakeDerivedType {type ev} { + upvar 1 $ev errmsg + foreach synth { + MakeScalarLimited + MakeList + } { + set ltype [$synth $type errmsg] + if {$ltype eq {}} continue + return $ltype + } + return +} + +# Dynamically create an arg-type for "(length-limited) list (of T)". +proc ::critcl::MakeList {type ev} { + # Check for basic syntax. + # Accept the list indicator syntax as either prefix or suffix of the base type. + + if {![regexp {^\[(\d*|\*)\](.*)$} $type -> limit base]} { + if {![regexp {^(.*)\[(\d*|\*)\]$} $type -> base limit]} { + return + } + } + + # This looks like a list type, start recording errors + + if {($base ne {}) && ![has-argtype $base]} { + # XXX TODO: Recurse into the base for possible further synthesis. + set err "list: Unknown base type '$base'" + return + } + if {($limit ne {}) && ($limit == 0)} { + set err "list: Bad size 0, i.e. would be empty" + return + } + + # (LIST) Note: The '[]' and '[*]', i.e. unlimited lists of any type cannot appear here, because + # they exist as standard builtins. This means that at least one of base or limit is __not__ empty. + + set ntype list + + if {$base eq {}} { + append ntype _obj + } else { + append ntype _$base + } + + # Save the type-specific list type, without length restrictions factored in. + # This is what we need for the data structures and conversion, nothing more. + # IOW we do not wish to create multiple different types and functions for the + # same list type, just different length restrictions. + set nctype $ntype + + if {$limit in {{} *}} { + set limit {} + append ntype _any + } else { + append ntype _$limit + } + + # Check if this list type was seen before + if {[has-argtype $ntype]} { return $ntype } + + # Generate the validator for this kind of list. + + if {$base eq {}} { + # Without a base type simply start from `list`. + + set ctype [ArgumentCType list] + set code [ArgumentConversion list] + set new $code + } else { + # With a base type the start is not quite `list`. Because the C type is different, and we + # need a proper place for the list of Tcl_Obj* to get the element from. + + set new { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, @@, /* OK tcl9 */ + &(@A.c), &el) != TCL_OK) return TCL_ERROR; + @A.o = @@; + } + } + + if {$limit ne {}} { + # Check that the list conforms to the expected size + append new \ + "\n\t/* Size check, assert (length (list) == $limit) */" \ + "\n\tif (@A.c != $limit) \{" \ + "\n\t Tcl_AppendResult (interp, \"Expected a list of $limit\", NULL);" \ + "\n\t return TCL_ERROR;" \ + "\n\t\}" + } + + if {$base eq {}} { + # Without a base type we have a length-limited plain list, and there nothing more to do. + + argtype $ntype $new $ctype $ctype + argtypesupport $ntype [ArgumentSupport list] + + return $ntype + } + + # With a base type it is now time to synthesize something more complex to validate the list + # elements against the base type. `el` is the array of Tcl_Obj* holding the unconverted raw + # values. See `MakeVariadicTypeFor` too. It uses the same general schema, applied to the list of + # remaining cproc 'args'. + + lappend one @@ src + lappend one &@A dst + lappend one @A *dst + lappend one @A. dst-> + + lappend map @1conv@ [Deline [string map $one [ArgumentConversion $base]]] + lappend map @type@ [ArgumentCType $base] + lappend map @ntype@ $ntype + lappend map @nctype@ $nctype + + append new [string map $map { + @A.v = (@type@*) ((!@A.c) ? 0 : ckalloc (@A.c * sizeof (@type@))); + for (k = 0; k < @A.c; k++) { + if (_critcl_@nctype@_item (interp, el[k], &(@A.v[k])) != TCL_OK) { + ckfree ((char*) @A.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } + }] + + argtype $ntype $new critcl_$nctype critcl_$nctype + + argtypesupport $ntype [string map $map { + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_@nctype@ { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + @type@* v; /* Allocated array of the elements */ + } critcl_@nctype@; + + static int + _critcl_@nctype@_item (Tcl_Interp* interp, Tcl_Obj* src, @type@* dst) { + @1conv@ + return TCL_OK; + } + }] $nctype + + argtyperelease $ntype [string map $map { + if (@A.c) { ckfree ((char*) @A.v); } + }] + + return $ntype +} + +proc ::critcl::MakeScalarLimited {type ev} { + upvar 1 $ev errmsg + if {[catch {llength $type}]} return + + if {[lindex $type 0] ni { + int long wideint double float + }} return + + # At this point we assume that it can be a restricted scalar type and we record errors. + + set limits [lassign $type base] + set n [llength $type] + if {($n < 3) || (($n % 2) == 0)} { set err "$type: Incomplete restriction" ; return } + + foreach {op _} $limits { + if {$op in {> < >= <=}} continue + set err "$type: Bad relation '$op'" + return + } + + if {$base in {int long wideint}} { + foreach {_ v} $limits { + if {[string is integer -strict $v]} continue + set err "$base: Expected integer, have '$v'" + return + } + } else { + # double or float + foreach {_ v} $limits { + if {[string is double -strict $v]} continue + set err "$base: Expected float, have '$v'" + return + } + } + + # This looks mostly good. Condense the set of restrictions into a simple min/max range + lassign {} mingt minge maxlt maxle + + # Phase 1. Fuse identical kind of restrictions into a single of their type + foreach {op v} $limits { + switch -exact -- $op { + > { if {($mingt eq {}) || ($v > $mingt)} { set mingt $v } } + >= { if {($minge eq {}) || ($v > $minge)} { set minge $v } } + < { if {($maxlt eq {}) || ($v < $maxlt)} { set maxlt $v } } + <= { if {($maxle eq {}) || ($v < $maxle)} { set maxle $v } } + } + } + + # Phase 2. Fuse similar (lt/le, gt/ge) into a single + + if {($mingt ne {}) && ($minge ne {})} { + # We have both x > a && + # x >= b + # ... Determine the stricter form. + + # a > b => "> a" + # a < b => ">= b" + # a == b => "> a" + + if {$mingt >= $minge} { + set min $mingt + set minop > + } else { + set min $minge + set minop >= + } + } elseif {$mingt ne {}} { + # x > a only + set min $mingt + set minop > + } elseif {$minge ne {}} { + # x >= a only + set min $minge + set minop >= + } else { + # No limit + lassign {} min minop + } + + if {($maxlt ne {}) && ($maxle ne {})} { + # We have both x < a && + # x <= b + # ... Determine the stricter form. + + # a > b => "<= b" + # a < b => "< a" + # a == b => "< a" + + if {$maxlt <= $maxle} { + set max $maxlt + set maxop < + } else { + set max $maxle + set maxop <= + } + } elseif {$maxlt ne {}} { + # x > a only + set max $maxlt + set maxop < + } elseif {$maxle ne {}} { + # x >= a only + set max $maxle + set maxop <= + } else { + # No limit + lassign {} max maxop + } + + if {($min ne {}) && ($max ne {})} { + # With both limits they may specify an empty range, or a range allowing only single value. + # That is not sensible. + + # a < x < b -- a >= b is empty + # a <= x < b -- a >= b is empty + # a < x <= b -- a >= b is empty + # a <= x <= b -- a > b is empty, a == b is singular, + + # Reduced checks: + # - a > b is empty + # - a == b is singular if both <=, else empty + + if {($min > $max)} { + set err "$base: Limits do not allow any value as valid" + return + } + if {$min == $max} { + if {$minop$maxop eq ">=<=")} { + set err "$base: Limits only allow a single value as valid: $min" + } else { + set err "$base: Limits do not allow any value as valid" + } + return + } + } + + # Compute canonical type from the fused ranges. + + set ntype $base + if {$min ne {}} { lappend ntype $minop $min } + if {$max ne {}} { lappend ntype $maxop $max } + + # Check if we saw this canonical type before. + + if {[has-argtype $ntype]} { return $ntype } + + # Generate the new type + + set ctype [ArgumentCType $base] + set code [ArgumentConversion $base] + + set head "expected $ntype, but got \\\"" + set tail "\\\"" + set msg "\"$head\", Tcl_GetString (@@), \"$tail\"" + set new $code + + if {$min ne {}} { + append new \ + "\n\t/* Range check, assert (x $minop $min) */" \ + "\n\tif (!(@A $minop $min)) \{" \ + "\n\t Tcl_AppendResult (interp, $msg, NULL);" \ + "\n\t return TCL_ERROR;" \ + "\n\t\}" + } + if {$max ne {}} { + append new \ + "\n\t/* Range check, assert (x $maxop $max) */" \ + "\n\tif (!(@A $maxop $max)) \{" \ + "\n\t Tcl_AppendResult (interp, $msg, NULL);" \ + "\n\t return TCL_ERROR;" \ + "\n\t\}" + } + + argtype $ntype $new $ctype $ctype + + return $ntype +} + +proc ::critcl::MakeVariadicTypeFor {type} { + # Note: The type "Tcl_Obj*" required special treatment and is + # directly defined as a builtin, see 'Initialize'. The has-argtype + # check below will prevent us from trying to create something + # generic, and wrong. + + set ltype variadic_$type + if {![has-argtype $ltype]} { + # Generate a type representing a list/array of + # elements, plus conversion code. Similar to the 'list' type, + # except for custom C types, and conversion assumes variadic, + # not single argument. + + lappend one @@ src + lappend one &@A dst + lappend one @A *dst + lappend one @A. dst-> + lappend map @1conv@ [Deline [string map $one [ArgumentConversion $type]]] + + lappend map @type@ [ArgumentCType $type] + lappend map @ltype@ $ltype + + argtype $ltype [string map $map { + int src, dst, leftovers = @C; + @A.c = leftovers; + @A.v = (@type@*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (@type@))); + @A.o = (Tcl_Obj**) &ov[@I]; + for (src = @I, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_@type@_item (interp, ov[src], &(@A.v[dst])) != TCL_OK) { + ckfree ((char*) @A.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } + }] critcl_$ltype critcl_$ltype + + argtypesupport $ltype [string map $map { + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_@ltype@ { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + @type@* v; /* Allocated array of the elements */ + } critcl_@ltype@; + + static int + _critcl_variadic_@type@_item (Tcl_Interp* interp, Tcl_Obj* src, @type@* dst) { + @1conv@ + return TCL_OK; + } + }] + + argtyperelease $ltype [string map $map { + if (@A.c) { ckfree ((char*) @A.v); } + }] + } + return $ltype +} + +proc ::critcl::ArgsInprocess {adefs skip} { + # Convert the regular arg spec from the API into a dictionary + # containing all the derived data we need in the various places of + # the cproc implementation. + + set db {} + + set names {} ; # list of raw argument names + set cnames {} ; # list of C var names for the arguments. + set optional {} ; # list of flags signaling optional args. + set variadic {} ; # list of flags signaling variadic args. + set islast {} ; # list of flags signaling the last arg. + set varargs no ; # flag signaling 'args' collector. + set defaults {} ; # list of default values. + set csig {} ; # C signature of worker function. + set tsig {} ; # Tcl signature for frontend/shim command. + set vardecls {} ; # C variables for arg conversion in the shim. + set support {} ; # Conversion support code for arguments. + set has {} ; # Types for which we have emitted the support + # code already. (dict: type -> '.' (presence)) + set hasopt no ; # Overall flag - Have optionals ... + set min 0 ; # Count required args - minimal needed. + set max 0 ; # Count all args - maximal allowed. + set aconv {} ; # list of the basic argument conversions. + set achdr {} ; # list of arg conversion annotations. + set arel {} ; # List of arg release code fragments, for those which have them. + + # Normalization, and typo fixing: + # - Remove singular commas from the list. + # - Strip argument names of trailing commas. + # - Strip type names of leading commas. + # Reason: Handle mistakenly entered C syntax for a function/command. + # + # Newly accepted syntax: + # = int x , int y ... + # = int x, int y ... + # = int x ,int y ... + + # TODO: lmap. + set adefnew {} + set mode type + foreach word $adefs { + if {$word eq ","} continue + switch -exact -- $mode { + type { lappend adefnew [string trimleft $word ,] ; set mode args } + args { lappend adefnew [string trimright $word ,] ; set mode type } + } + } + set adefs $adefnew ; unset adefnew mode + + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. But appears in both signature and + # actual list of arguments. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + lappend csig [lrange $adefs 0 1] + lappend cnames interp;#Fixed name for cproc[lindex $adefs 1] + set adefs [lrange $adefs 2 end] + } + + set last [expr {[llength $adefs]/2-1}] + set current 0 + + foreach {t a} $adefs { + # t = type + # a = name | {name default} + + # Check for a special case of list syntax, where the list indicator is written as suffix of + # the argument name, instead of attached to the base type. When found normalize to the + # expected form. I.e. transform a spec of the form `type a[...]` into `[...]type a`. + # + # Note that the argument name may be packaged with a default value. Ensure that we deail + # with only the name itself. + + set hasdefault [expr {[llength $a] == 2}] + lassign $a name defaultvalue + + if {[regexp {^(.+)(\[(\d*|\*)\])$} $name -> abase limit _]} { + set name $abase + set t $limit$t + } + + # Check type validity + + if {![has-argtype $t]} { + # XXXA Attempt to compute a derived type on the fly. + set err "Argument type '$t' is not known" + set ltype [MakeDerivedType $t err] + if {$ltype eq {}} { + return -code error $err + } + + set t $ltype + } + + # Base type support + if {![dict exists $has $t]} { + dict set has $t . + lappend support "[ArgumentSupport $t]" + } + + lappend islast [expr {$current == $last}] + + # Cases to consider: + # 1. 'args' as the last argument, without a default. + # 2. Any argument with a default value. + # 3. Any argument. + + if {($current == $last) && ($name eq "args") && !$hasdefault} { + set hdr " /* ($t $name, ...) - - -- --- ----- -------- */" + lappend optional 0 + lappend variadic 1 + lappend defaults n/a + lappend tsig ?${name}...? + set varargs yes + set max Inf ; # No limit on the number of args. + + # Dynamically create an arg-type for "variadic list of T". + set t [MakeVariadicTypeFor $t] + # List support. + if {![dict exists $has $t]} { + dict set has $t . + lappend support "[ArgumentSupport $t]" + } + + } elseif {$hasdefault} { + incr max + set hasopt yes + set hdr " /* ($t $name, optional, default $defaultvalue) - - -- --- ----- -------- */" + lappend tsig ?${name}? + lappend optional 1 + lappend variadic 0 + lappend defaults $defaultvalue + lappend cnames _has_$name + # Argument to signal if the optional argument was set + # (true) or is the default (false). + lappend csig "int has_$name" + lappend vardecls "int _has_$name = 0;" + + } else { + set hdr " /* ($t $name) - - -- --- ----- -------- */" + lappend tsig $name + incr max + incr min + lappend optional 0 + lappend variadic 0 + lappend defaults n/a + } + + lappend achdr $hdr + lappend csig "[ArgumentCTypeB $t] $name" + lappend vardecls "[ArgumentCType $t] _$name;" + + lappend names $name + lappend cnames _$name + lappend aconv [TraceReturns "\"$t\" argument" [ArgumentConversion $t]] + + set rel [ArgumentRelease $t] + if {$rel ne {}} { + set rel [string map [list @A _$name] $rel] + set hdr [string map {( {(Release: }} $hdr] + lappend arel "$hdr$rel" + } + + incr current + } + + set thresholds {} + if {$hasopt} { + # Compute thresholds for optional arguments. The threshold T + # of an optional argument A is the number of required + # arguments _after_ A. If during arg processing more than T + # arguments are left then A can take the current word, + # otherwise A is left to its default. We compute them from the + # end. + set t 0 + foreach o [lreverse $optional] { + if {$o} { + lappend thresholds $t + } else { + lappend thresholds - + incr t + } + } + set thresholds [lreverse $thresholds] + } + + set tsig [join $tsig { }] + if {$tsig eq {}} { + set tsig NULL + } else { + set tsig \"$tsig\" + } + + # Generate code for wrong#args checking, based on the collected + # min/max information. Cases to consider: + # + # a. max == Inf && min == 0 <=> All argc allowed. + # b. max == Inf && min > 0 <=> Fail argc < min. + # c. max < Inf && min == max <=> Fail argc != min. + # d. max < Inf && min < max <=> Fail argc < min || max < argc + + if {$max == Inf} { + # a, b + if {!$min} { + # a: nothing to check. + set wacondition {} + } else { + # b: argc < min + set wacondition {oc < MIN_ARGS} + } + } else { + # c, d + if {$min == $max} { + # c: argc != min + set wacondition {oc != MIN_ARGS} + } else { + # d: argc < min || max < argc + set wacondition {(oc < MIN_ARGS) || (MAX_ARGS < oc)} + } + } + + # Generate conversion code for arguments. Use the threshold + # information to handle optional arguments at all positions. + # The code is executed after the wrong#args check. + # That means we have at least 'min' arguments, enough to fill + # all the required parameters. + + set map {} + set conv {} + set opt no + set idx $skip + set prefix " idx_ = $idx;" ; # Start at skip offset! + append prefix "\n argc_ = oc - $idx;" + foreach \ + name $names \ + t $thresholds \ + o $optional \ + v $variadic \ + l $islast \ + h $achdr \ + c $aconv \ + d $defaults { + + # Things to consider: + # 1. Required variables at the beginning. + # We can access these using fixed indices. + # 2. Any other variable require access using a dynamic index + # (idx_). During (1) we maintain the code initializing + # this. + + set useindex [expr {!$l}] ;# last arg => no need for idx/argc updates + + if {$v} { + # Variadic argument. Can only be last. + # opt => dynamic access at idx_..., collect argc_ + # !opt => static access at $idx ..., collect oc-$idx + + unset map + lappend map @A _$name + if {$opt} { + lappend map @I idx_ @C argc_ + } else { + lappend map @I $idx @C (oc-$idx) + } + + set c [string map $map $c] + + lappend conv $h + lappend conv $c + lappend conv {} + lappend conv {} + break + } + + if {$o} { + # Optional argument. Anywhere. Check threshold. + + unset map + lappend map @@ "ov\[idx_\]" + lappend map @A _$name + + set c [string map $map $c] + + if {$prefix ne {}} { lappend conv $prefix\n } + lappend conv $h + lappend conv " if (argc_ > $t) \{" + lappend conv $c + if {$useindex} { + lappend conv " idx_++;" + lappend conv " argc_--;" + } + lappend conv " _has_$name = 1;" + lappend conv " \} else \{" + lappend conv " _$name = $d;" + lappend conv " \}" + lappend conv {} + lappend conv {} + + set prefix {} + set opt yes + continue + } + + if {$opt} { + # Required argument, after one or more optional arguments + # were processed. Access to current word is dynamic. + + unset map + lappend map @@ "ov\[idx_\]" + lappend map @A _$name + + set c [string map $map $c] + + lappend conv $h + lappend conv $c + lappend conv {} + if {$useindex} { + lappend conv " idx_++;" + lappend conv " argc_--;" + } + lappend conv {} + lappend conv {} + continue + } + + # Required argument. No optionals processed yet. Access to + # current word is via static index. + + unset map + lappend map @@ "ov\[$idx\]" + lappend map @A _$name + + set c [string map $map $c] + + lappend conv $h + lappend conv $c + lappend conv {} + lappend conv {} + + incr idx + set prefix " idx_ = $idx;" + append prefix "\n argc_ = oc - $idx;" + } + set conv [Deline [join $conv \n]] + + # Save results ... + + dict set db skip $skip + dict set db aconv $conv + dict set db arelease $arel + dict set db thresholds $thresholds + dict set db wacondition $wacondition + dict set db min $min + dict set db max $max + dict set db tsignature $tsig + dict set db names $names + dict set db cnames $cnames + dict set db optional $optional + dict set db variadic $variadic + dict set db islast $islast + dict set db defaults $defaults + dict set db varargs $varargs + dict set db csignature $csig + dict set db vardecls $vardecls + dict set db support $support + dict set db hasoptional $hasopt + + #puts ___________________________________________________________|$adefs + #array set __ $db ; parray __ + #puts _______________________________________________________________\n + return $db +} + +proc ::critcl::argoptional {adefs} { + set optional {} + + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + set adefs [lrange $adefs 2 end] + } + + foreach {t a} $adefs { + if {[llength $a] == 2} { + lappend optional 1 + } else { + lappend optional 0 + } + } + + return $optional +} + +proc ::critcl::argdefaults {adefs} { + set defaults {} + + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + set adefs [lrange $adefs 2 end] + } + + foreach {t a} $adefs { + if {[llength $a] == 2} { + lappend defaults [lindex $a 1] + } + } + + return $defaults +} + +proc ::critcl::argnames {adefs} { + set names {} + + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + set adefs [lrange $adefs 2 end] + } + + foreach {t a} $adefs { + if {[llength $a] == 2} { + set a [lindex $a 0] + } + lappend names $a + } + + return $names +} + +proc ::critcl::argcnames {adefs {interp ip}} { + set cnames {} + + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + lappend cnames interp + set adefs [lrange $adefs 2 end] + } + + foreach {t a} $adefs { + if {[llength $a] == 2} { + set a [lindex $a 0] + lappend cnames _has_$a + } + lappend cnames _$a + } + + return $cnames +} + +proc ::critcl::argcsignature {adefs} { + # Construct the signature of the low-level C function. + + set cargs {} + + # If the 1st argument is "Tcl_Interp*", we pass it without + # counting it as a command argument. + + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + lappend cargs [lrange $adefs 0 1] + set adefs [lrange $adefs 2 end] + } + + foreach {t a} $adefs { + if {[llength $a] == 2} { + set a [lindex $a 0] + # Argument to signal if the optional argument was set + # (true) or is the default (false). + lappend cargs "int has_$a" + } + lappend cargs "[ArgumentCTypeB $t] $a" + } + + return $cargs +} + +proc ::critcl::argvardecls {adefs} { + # Argument variables, destinations for the Tcl -> C conversion. + + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + set adefs [lrange $adefs 2 end] + } + + set result {} + foreach {t a} $adefs { + if {[llength $a] == 2} { + set a [lindex $a 0] + lappend result "[ArgumentCType $t] _$a;\n int _has_$a = 0;" + } else { + lappend result "[ArgumentCType $t] _$a;" + } + } + + return $result +} + +proc ::critcl::argsupport {adefs} { + # Argument global support, outside/before function. + + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + set adefs [lrange $adefs 2 end] + } + + set has {} + + set result {} + foreach {t a} $adefs { + if {[lsearch -exact $has $t] >= 0} continue + lappend has $t + lappend result "[ArgumentSupport $t]" + } + + return $result +} + +proc ::critcl::argconversion {adefs {n 1}} { + # A 1st argument matching "Tcl_Interp*" does not count as a user + # visible command argument. + if {[lindex $adefs 0] eq "Tcl_Interp*"} { + set adefs [lrange $adefs 2 end] + } + + set min $n ; # count all non-optional arguments. min required. + foreach {t a} $adefs { + if {[llength $a] == 2} continue + incr min + } + + set result {} + set opt 0 + set prefix " idx_ = $n;\n" + + foreach {t a} $adefs { + if {[llength $a] == 2} { + # Optional argument. Can be first, or later. + # For the first the prefix gives us the code to initialize idx_. + + lassign $a a default + + set map [list @@ "ov\[idx_\]" @A _$a] + set code [string map $map [ArgumentConversion $t]] + + set code "${prefix} if (oc > $min) \{\n$code\n idx_++;\n _has_$a = 1;\n \} else \{\n _$a = $default;\n \}" + incr min + + lappend result " /* ($t $a, optional, default $default) - - -- --- ----- -------- */" + lappend result $code + lappend result {} + set opt 1 + set prefix "" + } elseif {$opt} { + # Fixed argument, after the optionals. + # Main issue: Use idx_ to access the array. + # We know that no optionals can follow, only the same. + + set map [list @@ "ov\[idx_\]" @A _$a] + lappend result " /* ($t $a) - - -- --- ----- -------- */" + lappend result [string map $map [ArgumentConversion $t]] + lappend result " idx_++;" + lappend result {} + + } else { + # Fixed argument, before any optionals. + set map [list @@ "ov\[$n\]" @A _$a] + lappend result " /* ($t $a) - - -- --- ----- -------- */" + lappend result [string map $map [ArgumentConversion $t]] + lappend result {} + incr n + set prefix " idx_ = $n;\n" + } + } + + return [Deline $result] +} + +proc ::critcl::has-argtype {name} { + variable v::aconv + return [info exists aconv($name)] +} + +proc ::critcl::argtype-def {name} { + lappend def [ArgumentCType $name] + lappend def [ArgumentCTypeB $name] + lappend def [ArgumentConversion $name] + lappend def [ArgumentRelease $name] + lappend def [ArgumentSupport $name] + return $def +} + +proc ::critcl::argtype {name conversion {ctype {}} {ctypeb {}}} { + variable v::actype + variable v::actypeb + variable v::aconv + variable v::acrel + variable v::acsup + + # ctype Type of variable holding the argument. + # ctypeb Type of formal C function argument. + + # Handle aliases by copying the original definition. + if {$conversion eq "="} { + # XXXA auto-create derived type from known base types. + + if {![info exists aconv($ctype)]} { + return -code error "Unable to alias unknown type '$ctype'." + } + + # Do not forget to copy support and release code, if present. + if {[info exists acsup($ctype)]} { + #puts COPY/S:$ctype + set acsup($name) $acsup($ctype) + } + if {[info exists acrel($ctype)]} { + #puts COPY/R:$ctype + set acrel($name) $acrel($ctype) + } + + set conversion $aconv($ctype) + set ctypeb $actypeb($ctype) + set ctype $actype($ctype) + } else { + lassign [HeaderLines $conversion] leadoffset conversion + Transition9Check [at::Loc $leadoffset 0 [This]] $conversion + set conversion "\t\{\n[at::caller! $leadoffset]\t[string trim $conversion] \}" + } + if {$ctype eq {}} { + set ctype $name + } + if {$ctypeb eq {}} { + set ctypeb $name + } + + if {[info exists aconv($name)] && + (($aconv($name) ne $conversion) || + ($actype($name) ne $ctype) || + ($actypeb($name) ne $ctypeb)) + } { + return -code error "Illegal duplicate definition of '$name'." + } + + set aconv($name) $conversion + set actype($name) $ctype + set actypeb($name) $ctypeb + return +} + +proc ::critcl::argtypesupport {name code {guard {}}} { + variable v::aconv + variable v::acsup + if {![info exists aconv($name)]} { + return -code error "No definition for '$name'." + } + if {$guard eq {}} { + set guard $name ; # Handle non-identifier chars! + } + lappend lines "#ifndef CRITCL_$guard" + lappend lines "#define CRITCL_$guard" + lappend lines $code + lappend lines "#endif /* CRITCL_$guard _________ */" + set support [join $lines \n]\n + + if {[info exists acsup($name)] && + ($acsup($name) ne $support) + } { + return -code error "Illegal duplicate support of '$name'." + } + + set acsup($name) $support + return +} + +proc ::critcl::argtyperelease {name code} { + variable v::aconv + variable v::acrel + if {![info exists aconv($name)]} { + return -code error "No definition for '$name'." + } + if {[info exists acrel($name)] && + ($acrel($name) ne $code) + } { + return -code error "Illegal duplicate release of '$name'." + } + + set acrel($name) $code + return +} + +proc ::critcl::has-resulttype {name} { + variable v::rconv + return [info exists rconv($name)] +} + +proc ::critcl::resulttype {name conversion {ctype {}}} { + variable v::rctype + variable v::rconv + + # Handle aliases by copying the original definition. + if {$conversion eq "="} { + if {![info exists rconv($ctype)]} { + return -code error "Unable to alias unknown type '$ctype'." + } + set conversion $rconv($ctype) + set ctype $rctype($ctype) + } else { + lassign [HeaderLines $conversion] leadoffset conversion + Transition9Check [at::Loc $leadoffset 0 [This]] $conversion + set conversion [at::caller! $leadoffset]\t[string trimright $conversion] + } + if {$ctype eq {}} { + set ctype $name + } + + if {[info exists rconv($name)] && + (($rconv($name) ne $conversion) || + ($rctype($name) ne $ctype)) + } { + return -code error "Illegal duplicate definition of '$name'." + } + + set rconv($name) $conversion + set rctype($name) $ctype + return +} + +proc ::critcl::cconst {name rtype rvalue} { + # The semantics are equivalent to + # + # cproc $name {} $rtype { return $rvalue ; } + # + # The main feature of this new command is the knowledge of a + # constant return value, which allows the optimization of the + # generated code. Only the shim is emitted, with the return value + # in place. No need for a lower-level C function containing a + # function body. + + SkipIgnored [set file [This]] + HandleDeclAfterBuild + + # A void result does not make sense for constants. + if {$rtype eq "void"} { + error "Constants cannot be of type \"void\"" + } + + lassign [BeginCommand public $name $rtype $rvalue] ns cns name cname + set traceref ns_$cns$cname + set wname tcl_$cns$cname + set cname c_$cns$cname + + # Construct the shim handling the conversion between Tcl and C + # realms. + + set adb [ArgsInprocess {} 1] + + EmitShimHeader $wname + EmitShimVariables $adb $rtype + EmitArgTracing $traceref + EmitWrongArgsCheck $adb + EmitConst $rtype $rvalue + EmitShimFooter $adb $rtype + EndCommand + return +} + +proc ::critcl::CheckForTracing {} { + if {!$v::options(trace)} return + if {[info exists ::critcl::v::__trace__]} return + + package require critcl::cutil + ::critcl::cutil::tracer on + set ::critcl::v::__trace__ marker ;# See above + return +} + +proc ::critcl::cproc {name adefs rtype {body "#"} args} { + SkipIgnored [set file [This]] + HandleDeclAfterBuild + CheckForTracing + + set acname 0 + set passcd 0 + set aoffset 0 + set tname "" + while {[string match "-*" $args]} { + switch -- [set opt [lindex $args 0]] { + -cname { set acname [lindex $args 1] } + -pass-cdata { set passcd [lindex $args 1] } + -arg-offset { set aoffset [lindex $args 1] } + -tracename { set tname [lindex $args 1] } + default { + error "Unknown option $opt, expected one of -cname, or -pass-cdata" + } + } + set args [lrange $args 2 end] + } + + incr aoffset ; # always include the command name. + set adb [ArgsInprocess $adefs $aoffset] + + if {$acname} { + BeginCommand static $name $adefs $rtype $body + set ns {} + set cns {} + set wname $name + set cname c_$name + if {$tname ne {}} { + set traceref \"$tname\" + } else { + set traceref \"$name\" + } + } else { + lassign [BeginCommand public $name $adefs $rtype $body] ns cns name cname + set traceref ns_$cns$cname + set wname tcl_$cns$cname + set cname c_$cns$cname + } + + set names [dict get $adb names] + set cargs [dict get $adb csignature] + set cnames [dict get $adb cnames] + + if {$passcd} { + set cargs [linsert $cargs 0 {ClientData clientdata}] + set cnames [linsert $cnames 0 cd] + } + + # Support code for argument conversions (i.e. structures, helper + # functions, etc. ...) + EmitSupport $adb + + # Emit either the low-level function, or, if it wasn't defined + # here, a reference to the shim we can use. + + if {$body ne "#"} { + Emit "static [ResultCType $rtype] " + Emitln "${cname}([join $cargs {, }])" + Emit \{\n + + at::caller + at::incrt $name + at::incrt $adefs + at::incrt $rtype + Transition9Check [at::raw] $body + + lassign [HeaderLines $body] leadoffset body + if {$v::options(lines)} { + Emit [at::CPragma $leadoffset -2 $file] + } + Emit $body + Emitln \n\} + } else { + Emitln "#define $cname $name" + } + + # Construct the shim handling the conversion between Tcl and C + # realms. + + EmitShimHeader $wname + EmitShimVariables $adb $rtype + EmitArgTracing $traceref + EmitWrongArgsCheck $adb + Emit [dict get $adb aconv] + EmitCall $cname $cnames $rtype + EmitShimFooter $adb $rtype + EndCommand + return +} + +proc ::critcl::cinit {text edecls} { + set file [SkipIgnored [set file [This]]] + HandleDeclAfterBuild + CInitCore $file $text $edecls + return +} + +proc ::critcl::CInitCore {file text edecls} { + set digesta [UUID.extend $file .cinit.f $text] + set digestb [UUID.extend $file .cinit.e $edecls] + + set initc {} + set skip [Lines $text] + lassign [HeaderLines $text] leadoffset text + Transition9Check [at::Loc $leadoffset -2 $file] $text + if {$v::options(lines)} { + append initc [at::CPragma $leadoffset -2 $file] + } + append initc $text \n + + set edec {} + lassign [HeaderLines $edecls] leadoffset edecls + Transition9Check [at::Loc $leadoffset -2 $file] $edecls + if {$v::options(lines)} { + incr leadoffset $skip + append edec [at::CPragma $leadoffset -2 $file] + } + append edec $edecls \n + + dict update v::code($file) config c { + dict append c initc $initc \n + dict append c edecls $edec \n + } + return +} + +# # ## ### ##### ######## ############# ##################### +## Public API to code origin handling. + +namespace eval ::critcl::at { + namespace export caller caller! here here! get get* raw raw* incr incrt = + catch { namespace ensemble create } +} + +# caller - stash caller location, possibly modified (level change, line offset) +# caller! - format & return caller location, clears stash +# here - stash current location +# here! - return format & return current location, clears stash +# incr* - modify stashed location (only line number, not file). +# get - format, return, and clear stash +# get* - format & return stash + +proc ::critcl::at::caller {{off 0} {level 0}} { + ::incr level -3 + Where $off $level [::critcl::This] + return +} + +proc ::critcl::at::caller! {{off 0} {level 0}} { + ::incr level -3 + Where $off $level [::critcl::This] + return [get] +} + +proc ::critcl::at::here {} { + Where 0 -2 [::critcl::This] + return +} + +proc ::critcl::at::here! {} { + Where 0 -2 [::critcl::This] + return [get] +} + +proc ::critcl::at::get {} { + variable where + if {!$::critcl::v::options(lines)} { + return {} + } + if {![info exists where]} { + return -code error "No location defined" + } + set result [Format $where] + unset where + return $result +} + +proc ::critcl::at::raw {} { + variable where + if {![info exists where]} { + return -code error "No location defined" + } + set result $where + set where {} + return $result +} + +proc ::critcl::at::get* {} { + variable where + if {!$::critcl::v::options(lines)} { + return {} + } + if {![info exists where]} { + return -code error "No location defined" + } + return [Format $where] +} + +proc ::critcl::at::raw* {} { + variable where + if {![info exists where]} { + return -code error "No location defined" + } + return $where +} + +proc ::critcl::at::= {file line} { + variable where + set where [list $file $line] + return +} + +proc ::critcl::at::incr {args} { + variable where + lassign $where file line + foreach offset $args { + ::incr line $offset + } + set where [list $file $line] + return +} + +proc ::critcl::at::incrt {args} { + variable where + if {$where eq {}} { + # Ignore problem when we have no precise locations. + if {![interp debug {} -frame]} return + return -code error "No location to change" + } + lassign $where file line + foreach text $args { + ::incr line [::critcl::Lines $text] + } + set where [list $file $line] + return +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Input and Output control + +proc ::critcl::collect {script {slot {}}} { + collect_begin $slot + uplevel 1 $script + return [collect_end] +} + +proc ::critcl::collect_begin {{slot {}}} { + # Divert the collection of code fragments to slot + # (output control). Stack on any previous diversion. + variable v::this + # See critcl::This for where this information is injected into the + # code generation system. + + if {$slot eq {}} { + set slot MEMORY[expr { [info exists this] + ? [llength $this] + : 0 }] + } + # Prefix prevents collision of slot names and file paths. + lappend this critcl://$slot + return +} + +proc ::critcl::collect_end {} { + # Stop last diversion, and return the collected information as + # single string of C code. + variable v::this + # See critcl::This for where this information is injected into the + # code generation system. + + # Ensure that a diversion is actually open. + if {![info exists this] || ![llength $this]} { + return -code error "collect_end mismatch, no diversions active" + } + + set slot [Dpop] + set block {} + + foreach digest [dict get $v::code($slot) config fragments] { + append block "[Separator]\n\n" + append block [dict get $v::code($slot) config block $digest]\n + } + + # Drop all the collected data. Note how anything other than the C + # code fragments is lost, and how cbuild results are removed + # also. These do not belong anyway. + unset v::code($slot) + + return $block +} + + +proc ::critcl::Dpop {} { + variable v::this + + # Get current slot, and pop from the diversion stack. + # Remove stack when it becomes empty. + set slot [lindex $this end] + set v::this [lrange $this 0 end-1] + if {![llength $this]} { + unset this + } + return $slot +} + +proc ::critcl::include {path args} { + # Include headers or other C files into the current code. + set args [linsert $args 0 $path] + msg " (include <[join $args ">)\n (include <"]>)" + ccode "#include <[join $args ">\n#include <"]>" +} + +proc ::critcl::make {path contents} { + # Generate a header or other C file for pickup by other parts of + # the current package. Stored in the cache dir, making it local. + file mkdir [cache] + set cname [file join [cache] $path] + + set c [open $cname.[pid] w] + puts -nonewline $c $contents\n\n + close $c + file rename -force $cname.[pid] $cname + + return $path +} + +proc ::critcl::source {path} { + # Source a critcl file in the context of the current file, + # i.e. [This]. Enables the factorization of a large critcl + # file into smaller, easier to read pieces. + SkipIgnored [set file [This]] + HandleDeclAfterBuild + + msg " (importing $path)" + + set undivert 0 + variable v::this + if {![info exists this] || ![llength $this]} { + # critcl::source is recording the critcl commands in the + # context of the toplevel file which started the chain the + # critcl::source. So why are we twiddling with the diversion + # state? + # + # The condition above tells us that we are in the first + # non-diverted critcl::source called by the context. [This] + # returns that context. Due to our use of regular 'source' (*) + # during its execution [This] would return the sourced file as + # context. Wrong. Our fix for this is to perform, essentially, + # an anti-diversion. Saving [This] as diversion, forces it to + # return the proper value during the whole sourcing. + # + # And if the critcl::source is run in an already diverted + # context then the changes to [info script] by 'source' do not + # matter, making an anti-diversion unnecessary. + # + # Diversions inside of 'source' will work as usual, given + # their nesting nature. + # + # (Ad *) And we use 'source' as only this ensures proper + # collection of [info frame] location information. + + lappend this [This] + set undivert 1 + } + + foreach f [Expand $file $path] { + set v::source $f + # The source file information is used by critcl::at::Where + #uplevel 1 [Cat $f] + uplevel #0 [list ::source $f] + unset -nocomplain v::source + } + + if {$undivert} Dpop + return +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Control & Interface + +proc ::critcl::owns {args} {} + +proc ::critcl::cheaders {args} { + SkipIgnored [This] + HandleDeclAfterBuild + return [SetParam cheaders [ResolveRelative -I $args]] +} + +proc ::critcl::csources {args} { + SkipIgnored [This] + HandleDeclAfterBuild + return [SetParam csources $args 1 1 1] +} + +proc ::critcl::clibraries {args} { + SkipIgnored [This] + HandleDeclAfterBuild + return [SetParam clibraries [ResolveRelative { + -L --library-directory + } $args]] +} + +proc ::critcl::cobjects {args} { + SkipIgnored [This] + HandleDeclAfterBuild + return [SetParam cobjects $args] +} + +proc ::critcl::tsources {args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + # Here, 'license', 'meta?' and 'meta' are the only places where we + # are not extending the UUID. Because the companion Tcl sources + # (count, order, and content) have no bearing on the binary at + # all. + InitializeFile $file + + set dfiles {} + dict update v::code($file) config c { + foreach f $args { + foreach e [Expand $file $f] { + dict lappend c tsources $e + lappend dfiles $e + } + } + } + # Attention: The actual scanning is done outside of the `dict + # update`, because it makes changes to the dictionary which would + # be revert on exiting the update. + foreach e $dfiles { + ScanDependencies $file $e + } + return +} + +proc ::critcl::cflags {args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + if {![llength $args]} return + CFlagsCore $file $args + return +} + +proc ::critcl::CFlagsCore {file flags} { + UUID.extend $file .cflags $flags + dict update v::code($file) config c { + foreach flag $flags { + dict lappend c cflags $flag + } + } + return +} + +proc ::critcl::ldflags {args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + if {![llength $args]} return + + UUID.extend $file .ldflags $args + dict update v::code($file) config c { + foreach flag $args { + # Drop any -Wl prefix which will be added back a moment + # later, otherwise it would be doubled, breaking the command. + regsub -all {^-Wl,} $flag {} flag + dict lappend c ldflags -Wl,$flag + } + } + return +} + +proc ::critcl::framework {args} { + SkipIgnored [This] + HandleDeclAfterBuild + + # Check if we are building for OSX and ignore the command if we + # are not. Our usage of "actualtarget" means that we allow for a + # cross-compilation environment to OS X as well. + if {![string match "macosx*" [actualtarget]]} return + + foreach arg $args { + # if an arg contains a slash it must be a framework path + if {[string first / $arg] == -1} { + ldflags -framework $arg + } else { + cflags -F$arg + ldflags -F$arg + } + } + return +} + +proc ::critcl::tcl {version} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + + msg " (tcl $version)" + + # When a minimum Tcl version is requested it can be assumed that the C code will work for that + # version. Doing compatibility checks of any kind is not needed. + config tcl9 0 + + UUID.extend $file .mintcl $version + dict set v::code($file) config mintcl $version + + # This is also a dependency to record in the meta data. A 'package + # require' is not needed. This can be inside of the generated and + # loaded C code. + + ImetaAdd $file require [list [list Tcl $version]] + return +} + +proc ::critcl::tk {} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + + msg " (+tk)" + + UUID.extend $file .tk 1 + dict set v::code($file) config tk 1 + + # This is also a dependency to record in the meta data. A 'package + # require' is not needed. This can be inside of the generated and + # loaded C code. + + ImetaAdd $file require Tk + return +} + +# Register a shared library for pre-loading - this will eventually be +# redundant when TIP #239 is widely available +proc ::critcl::preload {args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + if {![llength $args]} return + + UUID.extend $file .preload $args + dict update v::code($file) config c { + foreach lib $args { + dict lappend c preload $lib + } + } + return +} + +proc ::critcl::license {who args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + + set who [string trim $who] + if {$who ne ""} { + set license "This software is copyrighted by $who.\n" + } else { + set license "" + } + + set elicense [LicenseText $args] + + append license $elicense + + # This, 'tsources', 'meta?', and 'meta' are the only places where + # we are not extending the UUID. Because the license text has no + # bearing on the binary at all. + InitializeFile $file + + ImetaSet $file license [Text2Words $elicense] + ImetaSet $file author [Text2Authors $who] + return +} + +proc ::critcl::LicenseText {words} { + if {[llength $words]} { + # Use the supplied license details as our suffix. + return [join $words] + } else { + # No details were supplied, fall back to the critcl license as + # template for the generated package. This is found in a + # sibling of this file. + + # We strip the first 2 lines from the file, this gets rid of + # the author information for critcl itself, allowing us to + # replace it by the user-supplied author. + + variable mydir + set f [file join $mydir license.terms] + return [join [lrange [split [Cat $f] \n] 2 end] \n] + } +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: meta data (teapot) + +proc ::critcl::description {text} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + InitializeFile $file + + ImetaSet $file description [Text2Words $text] + return +} + +proc ::critcl::summary {text} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + InitializeFile $file + + ImetaSet $file summary [Text2Words $text] + return +} + +proc ::critcl::subject {args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + InitializeFile $file + + ImetaAdd $file subject $args + return +} + +proc ::critcl::meta {key args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + + # This, 'meta?', 'license', and 'tsources' are the only places + # where we are not extending the UUID. Because the meta data has + # no bearing on the binary at all. + InitializeFile $file + + dict update v::code($file) config c { + dict update c meta m { + foreach v $args { dict lappend m $key $v } + } + } + return +} + +proc ::critcl::meta? {key} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + + # This, 'meta', 'license', and 'tsources' are the only places + # where we are not extending the UUID. Because the meta data has + # no bearing on the binary at all. + InitializeFile $file + + if {[dict exists $v::code($file) config package $key]} { + return [dict get $v::code($file) config package $key] + } + if {[dict exists $v::code($file) config meta $key]} { + return [dict get $v::code($file) config meta $key] + } + return -code error "Unknown meta data key \"$key\"" +} + +proc ::critcl::ImetaSet {file key words} { + dict set v::code($file) config package $key $words + #puts |||$key|%|[dict get $v::code($file) config package $key]| + return +} + +proc ::critcl::ImetaAdd {file key words} { + dict update v::code($file) config c { + dict update c package p { + foreach word $words { + dict lappend p $key $word + } + } + } + #puts XXX|$file||$key|+|[dict get $v::code($file) config package $key]| + return +} + +proc ::critcl::Text2Words {text} { + regsub -all {[ \t\n]+} $text { } text + return [split [string trim $text]] +} + +proc ::critcl::Text2Authors {text} { + regsub -all {[ \t\n]+} $text { } text + set authors {} + foreach a [split [string trim $text] ,] { + lappend authors [string trim $a] + } + return $authors +} + +proc ::critcl::GetMeta {file} { + if {![dict exists $v::code($file) config meta]} { + set result {} + } else { + set result [dict get $v::code($file) config meta] + } + + # Merge the package information (= system meta data) with the + # user's meta data. The system information overrides anything the + # user may have declared for the reserved keys (name, version, + # platform, as::author, as::build::date, license, description, + # summary, require). Note that for the internal bracketing code + # the system information may not exist, hence the catch. Might be + # better to indicate the bracket somehow and make it properly + # conditional. + + #puts %$file + + catch { + set result [dict merge $result [dict get $v::code($file) config package]] + } + + # A few keys need a cleanup, i.e. removal of duplicates, and the like + catch { + dict set result require [lsort -dict -unique [dict get $result require]] + } + catch { + dict set result build::require [lsort -dict -unique [dict get $result build::require]] + } + catch { + dict set result platform [lindex [dict get $result platform] 0] + } + catch { + dict set result generated::by [lrange [dict get $result generated::by] 0 1] + } + catch { + dict set result generated::date [lindex [dict get $result generated::by] 0] + } + + #array set ___M $result ; parray ___M ; unset ___M + return $result +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: user configuration options. + +proc ::critcl::userconfig {cmd args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + InitializeFile $file + + if {![llength [info commands ::critcl::UC$cmd]]} { + return -code error "Unknown method \"$cmd\"" + } + + # Dispatch + return [eval [linsert $args 0 ::critcl::UC$cmd $file]] +} + +proc ::critcl::UCdefine {file oname odesc otype {odefault {}}} { + # When declared without a default determine one of our own. Bool + # flag default to true, whereas enum flags, which is the rest, + # default to their first value. + + # The actual definition ignores the config description. This + # argument is only used by the static code scanner supporting + # TEA. See ::critcl::scan::userconfig. + + if {[llength [info level 0]] < 6} { + set odefault [UcDefault $otype] + } + + # Validate the default against the type too, before saving + # everything. + UcValidate $oname $otype $odefault + + UUID.extend $file .uc-def [list $oname $otype $odefault] + + dict set v::code($file) config userflag $oname type $otype + dict set v::code($file) config userflag $oname default $odefault + return +} + +proc ::critcl::UCset {file oname value} { + # NOTE: We can set any user flag we choose, even if not declared + # yet. Validation of the value happens on query, at which time the + # flag must be declared. + + dict set v::code($file) config userflag $oname value $value + return +} + +proc ::critcl::UCquery {file oname} { + # Prefer cached data. This is known as declared, defaults merged, + # validated. + if {[dict exists $v::code($file) config userflag $oname =]} { + return [dict get $v::code($file) config userflag $oname =] + } + + # Reject use of undeclared user flags. + if {![dict exists $v::code($file) config userflag $oname type]} { + error "Unknown user flag \"$oname\"" + } + + # Check if a value was supplied by the calling app. If not, fall + # back to the declared default. + + if {[dict exists $v::code($file) config userflag $oname value]} { + set value [dict get $v::code($file) config userflag $oname value] + } else { + set value [dict get $v::code($file) config userflag $oname default] + } + + # Validate value against the flag's type. + set otype [dict get $v::code($file) config userflag $oname type] + UcValidate $oname $otype $value + + # Fill cache + dict set v::code($file) config userflag $oname = $value + return $value +} + +proc ::critcl::UcValidate {oname otype value} { + switch -exact -- $otype { + bool { + if {![string is bool -strict $value]} { + error "Expected boolean for user flag \"$oname\", got \"$value\"" + } + } + default { + if {[lsearch -exact $otype $value] < 0} { + error "Expected one of [linsert [join $otype {, }] end-1 or] for user flag \"$oname\", got \"$value\"" + } + } + } +} + +proc ::critcl::UcDefault {otype} { + switch -exact -- $otype { + bool { + return 1 + } + default { + return [lindex $otype 0] + } + } +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: API (stubs) management + +proc ::critcl::api {cmd args} { + set file [SkipIgnored [This]] + HandleDeclAfterBuild + + if {![llength [info commands ::critcl::API$cmd]]} { + return -code error "Unknown method \"$cmd\"" + } + + # Dispatch + return [eval [linsert $args 0 ::critcl::API$cmd $file]] +} + +proc ::critcl::APIscspec {file scspec} { + UUID.extend $file .api-scspec $scspec + dict set v::code($file) config api_scspec $scspec + return +} + +proc ::critcl::APIimport {file name version} { + + # First we request the imported package, giving it a chance to + # generate the headers searched for in a moment (maybe it was + # critcl based as well, and generates things dynamically). + + # Note that this can fail, for example in a cross-compilation + # environment. Such a failure however does not imply that the + # required API headers are not present, so we can continue. + + catch { + package require $name $version + } + + ImetaAdd $file require [list [list $name $version]] + + # Now we check that the relevant headers of the imported package + # can be found in the specified search paths. + + set cname [string map {:: _} $name] + + set at [API_locate $cname searched] + if {$at eq {}} { + error "Headers for API $name not found in \n-\t[join $searched \n-\t]" + } else { + msg " (stubs import $name $version @ $at/$cname)" + } + + set def [list $name $version] + UUID.extend $file .api-import $def + dict update v::code($file) config c { + dict lappend c api_use $def + } + + # At last look for the optional .decls file. Ignore if there is + # none. Decode and return contained stubs table otherwise. + + set decls $at/$cname/$cname.decls + if {[file exists $decls]} { + package require stubs::reader + set T [stubs::container::new] + stubs::reader::file T $decls + return $T + } + return +} + +proc ::critcl::APIexport {file name} { + msg " (stubs export $name)" + + UUID.extend $file .api-self $name + return [dict set v::code($file) config api_self $name] +} + +proc ::critcl::APIheader {file args} { + UUID.extend $file .api-headers $args + return [SetParam api_hdrs $args] +} + +proc ::critcl::APIextheader {file args} { + UUID.extend $file .api-eheaders $args + return [SetParam api_ehdrs $args 0] +} + +proc ::critcl::APIfunction {file rtype name arguments} { + package require stubs::reader + + # Generate a declaration as it would have come straight out of the + # stubs reader. To this end we generate a C code fragment as it + # would be have been written inside of a .decls file. + + # TODO: We should record this as well, and later generate a .decls + # file as part of the export. Or regenerate it from the internal + # representation. + + if {[llength $arguments]} { + foreach {t a} $arguments { + lappend ax "$t $a" + } + } else { + set ax void + } + set decl [stubs::reader::ParseDecl "$rtype $name ([join $ax ,])"] + + UUID.extend $file .api-fun $decl + dict update v::code($file) config c { + dict lappend c api_fun $decl + } + return +} + +proc ::critcl::API_locate {name sv} { + upvar 1 $sv searched + foreach dir [SystemIncludePaths [This]] { + lappend searched $dir + if {[API_at $dir $name]} { return $dir } + } + return {} +} + +proc ::critcl::API_at {dir name} { + foreach suffix { + Decls.h StubLib.h + } { + if {![file exists [file join $dir $name $name$suffix]]} { return 0 } + } + return 1 +} + +proc ::critcl::API_setup {file} { + package require stubs::gen + + lassign [API_setup_import $file] iprefix idefines + dict set v::code($file) result apidefines $idefines + + append prefix $iprefix + append prefix [API_setup_export $file] + + # Save prefix to result dictionary for pickup by Compile. + if {$prefix eq ""} return + + dict set v::code($file) result apiprefix $prefix\n + return +} + +proc ::critcl::API_setup_import {file} { + if {![dict exists $v::code($file) config api_use]} { + return "" + } + + #msg -nonewline " (stubs import)" + + set prefix "" + set defines {} + + foreach def [dict get $v::code($file) config api_use] { + lassign $def iname iversion + + set cname [string map {:: _} $iname] + set upname [string toupper $cname] + set capname [stubs::gen::cap $cname] + + set import [critcl::at::here!][subst -nocommands { + /* Import API: $iname */ + #define USE_${upname}_STUBS 1 + #include <$cname/${cname}Decls.h> + }] + append prefix \n$import + CCodeCore $file $import + + # TODO :: DOCUMENT environment of the cinit code. + CInitCore $file [subst -nocommands { + if (!${capname}_InitStubs (ip, "$iversion", 0)) { + return TCL_ERROR; + } + }] [subst -nocommands { + #include <$cname/${cname}StubLib.h> + }] + + lappend defines -DUSE_${upname}_STUBS=1 + } + + return [list $prefix $defines] +} + +proc ::critcl::API_setup_export {file} { + if {![dict exists $v::code($file) config api_hdrs] && + ![dict exists $v::code($file) config api_ehdrs] && + ![dict exists $v::code($file) config api_fun]} return + + if {[dict exists $v::code($file) config api_self]} { + # API name was declared explicitly + set ename [dict get $v::code($file) config api_self] + } else { + # API name is implicitly defined, is package name. + set ename [dict get $v::code($file) config package name] + } + + set prefix "" + + #msg -nonewline " (stubs export)" + + set cname [string map {:: _} $ename] + set upname [string toupper $cname] + set capname [stubs::gen::cap $cname] + + set import [at::here!][subst -nocommands { + /* Import our own exported API: $ename, mapping disabled */ + #undef USE_${upname}_STUBS + #include <$cname/${cname}Decls.h> + }] + append prefix \n$import + CCodeCore $file $import + + # Generate the necessary header files. + + append sdecls "\#ifndef ${cname}_DECLS_H\n" + append sdecls "\#define ${cname}_DECLS_H\n" + append sdecls "\n" + append sdecls "\#include \n" + + if {[dict exists $v::code($file) config api_ehdrs]} { + append sdecls "\n" + file mkdir [cache]/$cname + foreach hdr [dict get $v::code($file) config api_ehdrs] { + append sdecls "\#include \"[file tail $hdr]\"\n" + } + } + + if {[dict exists $v::code($file) config api_hdrs]} { + append sdecls "\n" + file mkdir [cache]/$cname + foreach hdr [dict get $v::code($file) config api_hdrs] { + Copy $hdr [cache]/$cname + append sdecls "\#include \"[file tail $hdr]\"\n" + } + } + + # Insert code to handle the storage class settings on Windows. + + append sdecls [string map \ + [list @cname@ $cname @up@ $upname] \ + $v::storageclass] + + package require stubs::container + package require stubs::reader + package require stubs::gen + package require stubs::gen::header + package require stubs::gen::init + package require stubs::gen::lib + package require stubs::writer + + # Implied .decls file. Not actually written, only implied in the + # stubs container invocations, as if read from such a file. + + set T [stubs::container::new] + stubs::container::library T $ename + stubs::container::interface T $cname + + if {[dict exists $v::code($file) config api_scspec]} { + stubs::container::scspec T \ + [dict get $v::code($file) config api_scspec] + } + + if {[dict exists $v::code($file) config api_fun]} { + set index 0 + foreach decl [dict get $v::code($file) config api_fun] { + #puts D==|$decl| + stubs::container::declare T $cname $index generic $decl + incr index + } + append sdecls "\n" + append sdecls [stubs::gen::header::gen $T $cname] + } + + append sdecls "\#endif /* ${cname}_DECLS_H */\n" + + set comment "/* Stubs API Export: $ename */" + + set thedecls [stubs::writer::gen $T] + set slib [stubs::gen::lib::gen $T] + set sinitstatic " $comment\n " + append sinitstatic [stubs::gen::init::gen $T] + + set pn [dict get $v::code($file) config package name] + set pv [dict get $v::code($file) config package version] + + set sinitrun $comment\n + append sinitrun "Tcl_PkgProvideEx (ip, \"$pn\", \"$pv\", (ClientData) &${cname}Stubs);" + + # Save the header files to the result cache for pickup (importers + # in mode "compile & run", or by the higher-level code doing a + # "generate package") + + WriteCache $cname/${cname}Decls.h $sdecls + WriteCache $cname/${cname}StubLib.h $slib + WriteCache $cname/${cname}.decls $thedecls + + dict update v::code($file) result r { + dict lappend r apiheader [file join [cache] $cname] + } + + CInitCore $file $sinitrun $sinitstatic + CFlagsCore $file [list -DBUILD_$cname] + + return $prefix +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Introspection + +proc ::critcl::check {args} { + set file [SkipIgnored [This] 0] + HandleDeclAfterBuild + + switch -exact -- [llength $args] { + 1 { + set label Checking + set code [lindex $args 0] + } + 2 { + lassign $args label code + } + default { + return -code error "wrong#args: Expected ?label? code" + } + } + + set src [WriteCache check_[pid].c $code] + set obj [file rootname $src][getconfigvalue object] + + # See also the internal helper 'Compile'. Thre code here is in + # essence a simplified form of that. + + set cmdline [getconfigvalue compile] + lappendlist cmdline [GetParam $file cflags] + lappendlist cmdline [SystemIncludes $file] + lappendlist cmdline [CompileResult $obj] + lappend cmdline $src + + LogOpen $file + Log* "${label}... " + StatusReset + set ok [ExecWithLogging $cmdline OK FAILED] + StatusReset + + LogClose + clean_cache check_[pid].* + return $ok +} + +proc ::critcl::checklink {args} { + set file [SkipIgnored [This] 0] + HandleDeclAfterBuild + + switch -exact -- [llength $args] { + 1 { + set label Checking + set code [lindex $args 0] + } + 2 { + lassign $args label code + } + default { + return -code error "wrong#args: Expected ?label? code" + } + } + + set src [WriteCache check_[pid].c $code] + set obj [file rootname $src][getconfigvalue object] + + # See also the internal helper 'Compile'. Thre code here is in + # essence a simplified form of that. + + set cmdline [getconfigvalue compile] + lappendlist cmdline [GetParam $file cflags] + lappendlist cmdline [SystemIncludes $file] + lappendlist cmdline [CompileResult $obj] + lappend cmdline $src + + LogOpen $file + Log* "${label} (build)... " + StatusReset + set ok [ExecWithLogging $cmdline OK FAILED] + StatusReset + + if {!$ok} { + LogClose + clean_cache check_[pid].* + return 0 + } + + set out [file join [cache] a_[pid].out] + set cmdline [getconfigvalue link] + + if {$option::debug_symbols} { + lappendlist cmdline [getconfigvalue link_debug] + } else { + lappendlist cmdline [getconfigvalue strip] + lappendlist cmdline [getconfigvalue link_release] + } + + lappendlist cmdline [LinkResult $out] + lappendlist cmdline $obj + lappendlist cmdline [SystemLibraries] + lappendlist cmdline [FixLibraries [GetParam $file clibraries]] + lappendlist cmdline [GetParam $file ldflags] + + Log* "${label} (link)... " + StatusReset + set ok [ExecWithLogging $cmdline OK ERR] + + LogClose + clean_cache check_[pid].* a_[pid].* + return $ok +} + +proc ::critcl::compiled {} { + SkipIgnored [This] 1 + HandleDeclAfterBuild + return 0 +} + +proc ::critcl::compiling {} { + SkipIgnored [This] 0 + HandleDeclAfterBuild + # Check that we can indeed run a compiler + # Should only need to do this if we have to compile the code? + if {[auto_execok [lindex [getconfigvalue compile] 0]] eq ""} { + set v::compiling 0 + } else { + set v::compiling 1 + } + return $v::compiling +} + +proc ::critcl::done {} { + set file [SkipIgnored [This] 1] + return [expr {[info exists v::code($file)] && + [dict exists $v::code($file) result closed]}] +} + +proc ::critcl::failed {} { + SkipIgnored [This] 0 + if {$v::buildforpackage} { return 0 } + return [cbuild [This] 0] +} + +proc ::critcl::load {} { + SkipIgnored [This] 1 + if {$v::buildforpackage} { return 1 } + return [expr {![cbuild [This]]}] +} + +# # ## ### ##### ######## ############# ##################### +## Default error behaviour + +proc ::critcl::error {msg} { + return -code error $msg +} + +# # ## ### ##### ######## ############# ##################### +## Default message behaviour + +proc ::critcl::msg {args} { + # ignore message (compile & run) +} + +# # ## ### ##### ######## ############# ##################### +## Default print behaviour + +proc ::critcl::print {args} { + # API same as for builtin ::puts. Use as is. + return [eval [linsert $args 0 ::puts]] +} + +# # ## ### ##### ######## ############# ##################### +## Runtime support to handle the possibility of a prebuilt package using +## the .tcl file with embedded C as its own companon defining regular +## Tcl code for the package as well. If the critcl package is loaded +## already this will cause it to ignore the C definitions, with best +## guesses for failed, done, load, check, compiled, and compiling. + +proc ::critcl::Ignore {f} { + set v::ignore([file normalize $f]) . + return +} + +proc ::critcl::SkipIgnored {f {result {}}} { + if {[info exists v::ignore($f)]} { return -code return $result } + return $f +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Build Management + +proc ::critcl::config {option args} { + if {![info exists v::options($option)] || [llength $args] > 1} { + error "option must be one of: [lsort [array names v::options]]" + } + if {![llength $args]} { + return $v::options($option) + } + set v::options($option) [lindex $args 0] +} + +proc ::critcl::debug {args} { + # Replace 'all' everywhere, and squash duplicates, whether from + # this, or user-specified. + set args [string map {all {memory symbols}} $args] + set args [lsort -unique $args] + + foreach arg $args { + switch -- $arg { + memory { foreach x [getconfigvalue debug_memory] { cflags $x } } + symbols { foreach x [getconfigvalue debug_symbols] { cflags $x } + set option::debug_symbols 1 + } + default { + error "unknown critcl::debug option - $arg" + } + } + } + return +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Result Cache + +proc ::critcl::cache {{dir ""}} { + if {[llength [info level 0]] == 2} { + set v::cache [file normalize $dir] + } + return $v::cache +} + +proc ::critcl::clean_cache {args} { + if {![llength $args]} { lappend args * } + foreach pattern $args { + foreach file [glob -nocomplain -directory $v::cache $pattern] { + file delete -force $file + } + } + return +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Build Configuration +# read toolchain information from config file + +proc ::critcl::readconfig {config} { + variable run + variable configfile $config + + set cfg [open $config] + set knowntargets [list] + set cont "" + set whenplat "" + + interp eval $run set platform $v::buildplatform + + set i 0 + while {[gets $cfg line] >= 0} { + incr i + if {[set line [string trim $line]] ne ""} { + # config lines can be continued using trailing backslash + if {[string index $line end] eq "\\"} { + append cont " [string range $line 0 end-1]" + continue + } + if {$cont ne ""} { + append cont $line + set line [string trim $cont] + set cont "" + } + + # At this point we have a complete line/command in 'line'. + # We expect the following forms of input: + # + # (1.) if {...} {.............} - Tcl command, run in the + # backend interpreter. + # Note that this can EXIT + # the application using + # the critcl package. + # (2.) set VAR VALUE.......... - Ditto. + # (3.) # ..................... - Comment. Skipped + # (4.) PLATFORM VAR VALUE...... - Platform-specific + # configuration variable + # and value. + + # (4a) PLATFORM when ......... - Makes the PLATFORM + # conditional on the + # expression after the + # 'when' keyword. This + # uses variables set by + # (1) and/or (2). The + # expression is run in the + # backend interpreter. If + # and only if PLATFORM is + # a prefix of the current + # build platform, or the + # reverse, then the code + # with an TRUE when is + # chosen as the + # configuration. + + # (4b) PLATFORM target ?actual? - Marks the platform as a + # cross-compile target, + # and actual is the + # platform identifier of + # the result. If not + # specified it defaults to + # PLATFORM. + # (4c) PLATFORM copy PARENT... - Copies the currently defined + # configuration variables and + # values to the settings for + # this platform. + # (5.) VAR VALUE............... - Default configuration + # variable, and value. + + set plat [lindex [split $line] 0] + + # (1), or (2) + if {$plat eq "set" || $plat eq "if"} { + while {![info complete $line] && ![eof $cfg]} { + if {[gets $cfg more] == -1} { + set msg "incomplete command in Critcl Config file " + append msg "starting at line $i" + error $msg + } + append line "\n$more" + + } + interp eval $run $line + continue + } + + # (3) + if {$plat eq "#"} continue + + # (4), or (5). + if {[lsearch -exact $v::configvars $plat] != -1} { + # (5) default config option + set cmd "" + if {![regexp {(\S+)\s+(.*)} $line -> type cmd]} { + # cmd is empty + set type $plat + set cmd "" + } + set plat "" + } else { + # (4) platform config option + if {![regexp {(\S+)\s+(\S+)\s+(.*)} $line -> p type cmd]} { + # cmd is empty + set type [lindex $line 1] + set cmd "" + } + + # (4a) if and only if either build platform or config + # code are a prefix of each other can the 'when' + # condition be evaluated and override the + # standard selection for the configuration. + + if {$type eq "when" && + ( [string match ${v::buildplatform}* $plat] || + [string match ${plat}* $v::buildplatform] )} { + set res "" + catch { + set res [interp eval $run expr $cmd] + } + switch $res { + "" - + 0 { set whenfalse($plat) 1 } + 1 { set whenplat $plat } + } + } + lappend knowntargets $plat + } + + switch -exact -- $type { + target { + # (4b) cross compile target. + # cmd = actual target platform identifier. + if {$cmd eq ""} { + set cmd $plat + } + set v::xtargets($plat) $cmd + } + copy { + # (4c) copy an existing config + # XXX - should we error out if no definitions exist + # for parent platform config + # $cmd contains the parent platform + foreach {key val} [array get v::toolchain "$cmd,*"] { + set key [lindex [split $key ,] 1] + set v::toolchain($plat,$key) $val + } + } + default { + set v::toolchain($plat,$type) $cmd + } + } + } + } + set knowntargets [lsort -unique $knowntargets] + close $cfg + + # Config file processing has completed. + # Now select the platform to configure the + # compiler backend with. + + set v::knowntargets $knowntargets + + # The config file may have selected a configuration based on the + # TRUE when conditions. Which were matched to v::buildplatform, + # making the chosen config a variant of it. If that did not happen + # a platform is chosen from the set of defined targets. + if {$whenplat ne ""} { + set match [list $whenplat] + } else { + set match [critcl::chooseconfig $v::buildplatform] + } + + # Configure the backend. + + setconfig "" ;# defaults + if {[llength $match]} { + setconfig [lindex $match 0] + } else { + setconfig $v::buildplatform + } + return +} + +proc ::critcl::chooseconfig {targetconfig {err 0}} { + # first try to match exactly + set match [lsearch -exact -all -inline $v::knowntargets $targetconfig] + + # on failure, try to match as glob pattern + if {![llength $match]} { + set match [lsearch -glob -all -inline $v::knowntargets $targetconfig] + } + + # on failure, error out if requested + if {![llength $match] && $err} { + error "unknown target $targetconfig - use one of $v::knowntargets" + } + return $match +} + +proc ::critcl::showconfig {{fd ""}} { + variable run + variable configfile + + # XXX replace gen - v::buildplatform + # XXX Do not use v::targetplatform here. Use v::config. + # XXX Similarly in setconfig. + + set gen $v::buildplatform + if {$v::targetplatform eq ""} { + set plat "default" + } else { + set plat $v::targetplatform + } + set out [list] + if {$plat eq $gen} { + lappend out "Config: $plat" + } else { + lappend out "Config: $plat (built on $gen)" + } + lappend out "Origin: $configfile" + lappend out " [format %-15s cache] [cache]" + foreach var [lsort $v::configvars] { + set val [getconfigvalue $var] + set line " [format %-15s $var]" + foreach word [split [string trim $val]] { + if {[set word [string trim $word]] eq ""} continue + if {[string length "$line $word"] > 70} { + lappend out "$line \\" + set line " [format %-15s { }] $word" + } else { + set line "$line $word" + } + } + lappend out $line + } + # Tcl variables - Combined LengthLongestWord (all), and filtering + set vars [list] + set max 0 + foreach idx [array names v::toolchain $v::targetplatform,*] { + set var [lindex [split $idx ,] 1] + if {[set len [string length $var]] > $max} { + set max $len + } + if {$var ne "when" && ![info exists c::$var]} { + lappend vars $idx $var + } + } + if {[llength $vars]} { + lappend out "Tcl variables:" + foreach {idx var} $vars { + set val $v::toolchain($idx) + if {[llength $val] == 1} { + # for when someone inevitably puts quotes around + # values - e.g. "Windows NT" + set val [lindex $val 0] + } + lappend out " [PadRight $max $var] $val" + } + } + set out [join $out \n] + if {$fd ne ""} { + puts $fd $out + } else { + return $out + } +} + +proc ::critcl::showallconfig {{ofd ""}} { + variable configfile + set txt [Cat $configfile] + if {$ofd ne ""} { + puts $ofd $txt + } else { + return $txt + } +} + +proc ::critcl::setconfig {targetconfig} { + global env + set v::targetconfig $targetconfig + + # Strip the compiler information from the configuration to get the + # platform identifier embedded into it. This is a semi-recurrence + # of the original hardwired block handling win32/gcc/cl. We can + # partly emulate this with 'platform' directives in the Config + # file, however this breaks down when trying to handle the default + # settings. I.e. something like FOO-gcc which has no configuration + # block in the file uses the defaults, and thus has no proper + # place for a custom platform directive. So we have to do it here, + # in code. For symmetry the other compilers (-cc, -cl) are handled + # as well. + + set v::targetplatform $targetconfig + foreach p {gcc cc_r xlc xlc_r cc cl clang([[:digit:]])*} { + if {[regsub -- "-$p\$" $v::targetplatform {} v::targetplatform]} break + } + + set c::platform "" + set c::sharedlibext "" + + foreach var $v::configvars { + if {[info exists v::toolchain($targetconfig,$var)]} { + + set c::$var $v::toolchain($targetconfig,$var) + + if {$var eq "platform"} { + set px [getconfigvalue platform] + set v::targetplatform [lindex $px 0] + set v::version [lindex $px 1] + } + } + } + if {[info exists env(CFLAGS)]} { + variable c::compile + append c::compile " $env(CFLAGS)" + } + if {[info exists env(LDFLAGS)]} { + variable c::link + append c::link " $env(LDFLAGS)" + append c::link_preload " $env(LDFLAGS)" + } + if {[string match $v::targetplatform $v::buildplatform]} { + # expand platform to match host if it contains wildcards + set v::targetplatform $v::buildplatform + } + if {$c::platform eq ""} { + # default config platform (mainly for the "show" command) + set c::platform $v::targetplatform + } + if {$c::sharedlibext eq ""} { + set c::sharedlibext [info sharedlibextension] + } + + # The following definition of the cache directory is only relevant + # for mode "compile & run". The critcl application handling the + # package mode places the cache in a process-specific location + # without care about platforms. For here this means that we can + # ignore both cross-compilation, and the user choosing a target + # for us, as neither happens nor works for "compile & run". We can + # assume that build and target platforms will be the same, be the + # current platform, and we can make a simple choice for the + # directory. + + cache [file join $env(HOME) .critcl [platform::identify]] + + # Initialize Tcl variables based on the chosen tooling + foreach idx [array names v::toolchain $v::targetplatform,*] { + set var [lindex [split $idx ,] 1] + if {![info exists c::$var]} { + set val $v::toolchain($idx) + if {[llength $val] == 1} { + # for when someone inevitably puts quotes around + # values - e.g. "Windows NT" + set val [lindex $val 0] + } + set $var $val + } + } + return +} + +proc ::critcl::getconfigvalue {var} { + variable run + if {[catch {set val [interp eval $run [list subst [set c::$var]]]}]} { + set val [set c::$var] + } + return $val +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- API: Application + +# The regular commands used by the application, defined in other +# sections of the package are: +# +# C critcl::cache +# C critcl::ccode +# C critcl::chooseconfig +# C critcl::cinit +# C critcl::clean_cache +# C critcl::clibraries +# C critcl::cobjects +# C critcl::config I, L, lines, force, keepsrc, combine, trace, tcl9, outdir +# C critcl::debug +# C critcl::error | App overrides our implementation. +# C critcl::getconfigvalue +# C critcl::lappendlist +# C critcl::ldflags +# C critcl::preload +# C critcl::readconfig +# C critcl::setconfig +# C critcl::showallconfig +# C critcl::showconfig + +proc ::critcl::crosscheck {} { + variable run + global tcl_platform + + if {$tcl_platform(platform) eq "windows"} { + set null NUL: + } else { + set null /dev/null + } + + if {![catch { + set cmd [linsert $c::version 0 exec] + lappend cmd 2> $null;#@stdout + set config [interp eval $run $cmd] + } msg]} { + set host "" + set target "" + foreach line $config { + foreach arg [split $line] { + if {[string match "--*" $arg]} { + lassign [split [string trim $arg -] =] cfg val + set $cfg $val + } + } + } + if {$host ne $target && [info exists v::xtargets($target)]} { + setconfig $target + print stderr "Cross compiling using $target" + } + # XXX host != target, but not know as config ? + # XXX Currently ignored. + # XXX Throwing an error better ? + } + return +} + +# See (XX) at the end of the file (package state variable setup) +# for explanations of the exact differences between these. + +proc ::critcl::knowntargets {} { + return $v::knowntargets +} + +proc ::critcl::targetconfig {} { + return $v::targetconfig +} + +proc ::critcl::targetplatform {} { + return $v::targetplatform +} + +proc ::critcl::buildplatform {} { + return $v::buildplatform +} + +proc ::critcl::actualtarget {} { + # Check if the chosen target is a cross-compile target. If yes, + # we return the actual platform identifier of the target. This is + # used to select the proper platform director names in the critcl + # cache, generated packages, when searching for preload libraries, + # etc. Whereas the chosen target provides the proper compile + # configuration which will invoke the proper cross-compiler, etc. + + if {[info exists v::xtargets($v::targetplatform)]} { + return $v::xtargets($v::targetplatform) + } else { + return $v::targetplatform + } +} + +proc ::critcl::sharedlibext {} { + return [getconfigvalue sharedlibext] +} + +proc ::critcl::buildforpackage {{buildforpackage 1}} { + set v::buildforpackage $buildforpackage + return +} + +proc ::critcl::fastuuid {} { + set v::uuidcounter 1 ;# Activates it. + return +} + +proc ::critcl::cbuild {file {load 1}} { + if {[info exists v::code($file,failed)] && !$load} { + set v::buildforpackage 0 + return $v::code($file,failed) + } + + StatusReset + + # Determine if we should place stubs code into the generated file. + set placestubs [expr {!$v::buildforpackage}] + + # Determine the requested mode and reset for next call. + set buildforpackage $v::buildforpackage + set v::buildforpackage 0 + + if {$file eq ""} { + set file [This] + } + + # NOTE: The 4 pieces of data just below has to be copied into the + # result even if the build and link-steps are suppressed. Because + # the load-step must have this information. + + set shlib [DetermineShlibName $file] + set initname [DetermineInitName $file [expr {$buildforpackage ? "ns" : ""}]] + + dict set v::code($file) result tsources [GetParam $file tsources] + dict set v::code($file) result mintcl [MinTclVersion $file] + + set emsg {} + set msgs {} + + if {$v::options(force) || ![file exists $shlib]} { + LogOpen $file + set base [BaseOf $file] + set object [DetermineObjectName $file] + + API_setup $file + + # Generate the main C file + CollectEmbeddedSources $file $base.c $object $initname $placestubs + + # Set the marker for critcl::done and its user, HandleDeclAfterBuild. + dict set v::code($file) result closed mark + + # Compile main file + lappend objects [Compile $file $file $base.c $object] + + # Compile the companion C sources as well, if there are any. + foreach src [GetParam $file csources] { + lappend objects [Compile $file $src $src \ + [CompanionObject $src]] + } + + # NOTE: The data below has to be copied into the result even + # if the link-step is suppressed. Because the application + # (mode 'generate package') must have this information to be + # able to perform the final link. + + lappendlist objects [GetParam $file cobjects] + + dict set v::code($file) result clibraries [set clib [GetParam $file clibraries]] + dict set v::code($file) result libpaths [LibPaths $clib] + dict set v::code($file) result ldflags [GetParam $file ldflags] + dict set v::code($file) result objects $objects + dict set v::code($file) result tk [UsingTk $file] + dict set v::code($file) result preload [GetParam $file preload] + dict set v::code($file) result license [GetParam $file license <>] + dict set v::code($file) result log {} + dict set v::code($file) result meta [GetMeta $file] + + # Link and load steps. + if {$load || !$buildforpackage} { + Link $file + } + + lassign [LogClose] msgs emsg + + dict set v::code($file) result warnings [CheckForWarnings $emsg] + } + + dict set v::code($file) result log $msgs + dict set v::code($file) result exl $emsg + + if {$v::failed} { + if {!$buildforpackage} { + print stderr "$msgs\ncritcl build failed ($file)" + } + } elseif {$load && !$buildforpackage} { + Load $file + } + + # Release the data which was collected for the just-built file, as + # it is not needed any longer. + dict unset v::code($file) config + + return [StatusSave $file] +} + +proc ::critcl::cresults {{file {}}} { + if {$file eq ""} { set file [This] } + return [dict get $v::code($file) result] +} + +proc ::critcl::cnothingtodo {f} { + # No critcl definitions at all ? + if {![info exists v::code($f)]} { return 1 } + + # We have results already, so where had been something to do. + if {[dict exists $v::code($f) result]} { return 0 } + + # No C code collected for compilation ? + if {![dict exists $v::code($f) config fragments]} { return 1 } + + # Ok, something has to be done. + return 0 +} + +proc ::critcl::c++command {tclname class constructors methods} { + # Build the body of the function to define a new tcl command for + # the C++ class + set helpline {} + set classptr ptr_$tclname + set comproc " $class* $classptr;\n" + append comproc " switch (objc) \{\n" + + if {![llength $constructors]} { + set constructors {{}} + } + + foreach adefs $constructors { + array set types {} + set names {} + set cargs {} + set cnames {} + + foreach {t n} $adefs { + set types($n) $t + lappend names $n + lappend cnames _$n + lappend cargs "$t $n" + } + lappend helpline "$tclname pathName [join $names { }]" + set nargs [llength $names] + set ncargs [expr {$nargs + 2}] + append comproc " case $ncargs: \{\n" + + if {!$nargs} { + append comproc " $classptr = new $class\();\n" + } else { + append comproc [ProcessArgs types $names $cnames] + append comproc " $classptr = new $class\([join $cnames {, }]);\n" + } + append comproc " break;\n" + append comproc " \}\n" + + } + append comproc " default: \{\n" + append comproc " Tcl_SetResult(ip, \"wrong # args: should be either [join $helpline { or }]\",TCL_STATIC);\n" + append comproc " return TCL_ERROR;\n" + append comproc " \}\n" + append comproc " \}\n" + + append comproc " if ( $classptr == NULL ) \{\n" + append comproc " Tcl_SetResult(ip, \"Not enough memory to allocate a new $tclname\", TCL_STATIC);\n" + append comproc " return TCL_ERROR;\n" + append comproc " \}\n" + + append comproc " Tcl_CreateObjCommand2(ip, Tcl_GetString(objv\[1]), cmdproc_$tclname, (ClientData) $classptr, delproc_$tclname);\n" + append comproc " return TCL_OK;\n" + # + # Build the body of the c function called when the object is deleted + # + set delproc "void delproc_$tclname\(ClientData cd) \{\n" + append delproc " if (cd != NULL)\n" + append delproc " delete ($class*) cd;\n" + append delproc "\}\n" + + # + # Build the body of the function that processes the tcl commands for the class + # + set cmdproc "int cmdproc_$tclname\(ClientData cd, Tcl_Interp* ip, Tcl_Size objc, Tcl_Obj *CONST objv\[]) \{\n" + append cmdproc " int index;\n" + append cmdproc " $class* $classptr = ($class*) cd;\n" + + set rtypes {} + set tnames {} + set mnames {} + set adefs {} + foreach {rt n a} $methods { + lappend rtypes $rt + lappend tnames [lindex $n 0] + set tmp [lindex $n 1] + if {$tmp eq ""} { + lappend mnames [lindex $n 0] + } else { + lappend mnames [lindex $n 1] + } + lappend adefs $a + } + append cmdproc " static const char* cmds\[]=\{\"[join $tnames {","}]\",NULL\};\n" + append cmdproc " if (objc < 2) \{\n" + append cmdproc " Tcl_WrongNumArgs(ip, 1, objv, \"expecting pathName option\");\n" + append cmdproc " return TCL_ERROR;\n" + append cmdproc " \}\n\n" + append cmdproc " if (Tcl_GetIndexFromObj(ip, objv\[1], cmds, \"option\", TCL_EXACT, &index) != TCL_OK)\n" + append cmdproc " return TCL_ERROR;\n" + append cmdproc " switch (index) \{\n" + + set ndx 0 + foreach rtype $rtypes tname $tnames mname $mnames adef $adefs { + array set types {} + set names {} + set cargs {} + set cnames {} + + switch -- $rtype { + ok { set rtype2 "int" } + string - + dstring - + vstring { set rtype2 "char*" } + default { set rtype2 $rtype } + } + + foreach {t n} $adef { + set types($n) $t + lappend names $n + lappend cnames _$n + lappend cargs "$t $n" + } + set helpline "$tname [join $names { }]" + set nargs [llength $names] + set ncargs [expr {$nargs + 2}] + + append cmdproc " case $ndx: \{\n" + append cmdproc " if (objc == $ncargs) \{\n" + append cmdproc [ProcessArgs types $names $cnames] + append cmdproc " " + if {$rtype ne "void"} { + append cmdproc "$rtype2 rv = " + } + append cmdproc "$classptr->$mname\([join $cnames {, }]);\n" + append cmdproc " " + switch -- $rtype { + void { } + ok { append cmdproc "return rv;" } + int { append cmdproc "Tcl_SetIntObj(Tcl_GetObjResult(ip), rv);" } + long { append cmdproc " Tcl_SetLongObj(Tcl_GetObjResult(ip), rv);" } + float - + double { append cmdproc "Tcl_SetDoubleObj(Tcl_GetObjResult(ip), rv);" } + char* { append cmdproc "Tcl_SetResult(ip, rv, TCL_STATIC);" } + string - + dstring { append cmdproc "Tcl_SetResult(ip, rv, TCL_DYNAMIC);" } + vstring { append cmdproc "Tcl_SetResult(ip, rv, TCL_VOLATILE);" } + default { append cmdproc "if (rv == NULL) \{ return TCL_ERROR ; \}\n Tcl_SetObjResult(ip, rv); Tcl_DecrRefCount(rv);" } + } + append cmdproc "\n" + append cmdproc " " + if {$rtype ne "ok"} { append cmdproc "return TCL_OK;\n" } + + append cmdproc " \} else \{\n" + append cmdproc " Tcl_WrongNumArgs(ip, 1, objv, \"$helpline\");\n" + append cmdproc " return TCL_ERROR;\n" + append cmdproc " \}\n" + append cmdproc " \}\n" + incr ndx + } + append cmdproc " \}\n\}\n" + + # TODO: line pragma fix ?! + ccode $delproc + ccode $cmdproc + + # Force the new ccommand to be defined in the caller's namespace + # instead of improperly in ::critcl. + namespace eval [uplevel 1 namespace current] \ + [list critcl::ccommand $tclname {dummy ip objc objv} $comproc] + + return +} + +proc ::critcl::ProcessArgs {typesArray names cnames} { + upvar 1 $typesArray types + set body "" + foreach x $names c $cnames { + set t $types($x) + switch -- $t { + int - long - float - double - char* - Tcl_Obj* { + append body " $t $c;\n" + } + default { + append body " void* $c;\n" + } + } + } + set n 1 + foreach x $names c $cnames { + set t $types($x) + incr n + switch -- $t { + int { + append body " if (Tcl_GetIntFromObj(ip, objv\[$n], &$c) != TCL_OK)\n" + append body " return TCL_ERROR;\n" + } + long { + append body " if (Tcl_GetLongFromObj(ip, objv\[$n], &$c) != TCL_OK)\n" + append body " return TCL_ERROR;\n" + } + float { + append body " \{ double tmp;\n" + append body " if (Tcl_GetDoubleFromObj(ip, objv\[$n], &tmp) != TCL_OK)\n" + append body " return TCL_ERROR;\n" + append body " $c = (float) tmp;\n" + append body " \}\n" + } + double { + append body " if (Tcl_GetDoubleFromObj(ip, objv\[$n], &$c) != TCL_OK)\n" + append body " return TCL_ERROR;\n" + } + char* { + append body " $c = Tcl_GetString(objv\[$n]);\n" + } + default { + append body " $c = objv\[$n];\n" + } + } + } + return $body +} + +proc ::critcl::scan {file} { + set lines [split [Cat $file] \n] + + set scan::rkey require + set scan::base [file dirname [file normalize $file]] + set scan::capture { + org {} + version {} + files {} + imported {} + config {} + meta-user {} + meta-system {} + tsources {} + } + + ScanCore $lines { + critcl::api sub + critcl::api/extheader ok + critcl::api/function ok + critcl::api/header warn + critcl::api/import ok + critcl::source warn + critcl::cheaders warn + critcl::csources warn + critcl::license warn + critcl::meta warn + critcl::owns warn + critcl::tcl ok + critcl::tk ok + critcl::tsources warn + critcl::userconfig sub + critcl::userconfig/define ok + critcl::userconfig/query ok + critcl::userconfig/set ok + package warn + } + + set version [dict get $scan::capture version] + print "\tVersion: $version" + + # TODO : Report requirements. + # TODO : tsources - Scan files for dependencies! + + set n [llength [dict get $scan::capture files]] + print -nonewline "\tInput: $file" + if {$n} { + print -nonewline " + $n Companion" + if {$n > 1} { print -nonewline s } + } + print "" + + # Merge the system and user meta data, with system overriding the + # user. See 'GetMeta' for same operation when actually builing the + # package. Plus scan any Tcl companions for more requirements. + + set md {} + lappend md [dict get $scan::capture meta-user] + lappend md [dict get $scan::capture meta-system] + + foreach ts [dict get $scan::capture tsources] { + lappend md [dict get [ScanDependencies $file \ + [file join [file dirname $file] $ts] \ + capture] meta-system] + } + + dict unset scan::capture meta-user + dict unset scan::capture meta-system + dict unset scan::capture tsources + + dict set scan::capture meta \ + [eval [linsert $md 0 dict merge]] + # meta = dict merge {*}$md + + if {[dict exists $scan::capture meta require]} { + foreach r [dict get $scan::capture meta require] { + print "\tRequired: $r" + } + } + + return $scan::capture +} + +proc ::critcl::ScanDependencies {dfile file {mode plain}} { + set lines [split [Cat $file] \n] + + catch { + set saved $scan::capture + } + + set scan::rkey require + set scan::base [file dirname [file normalize $file]] + set scan::capture { + name {} + version {} + meta-system {} + } + + ScanCore $lines { + critcl::buildrequirement warn + package warn + } + + if {$mode eq "capture"} { + set result $scan::capture + set scan::capture $saved + return $result + } + + dict with scan::capture { + if {$mode eq "provide"} { + msg " (provide $name $version)" + + ImetaSet $dfile name $name + ImetaSet $dfile version $version + } + + dict for {k vlist} [dict get $scan::capture meta-system] { + if {$k eq "name"} continue + if {$k eq "version"} continue + + ImetaAdd $dfile $k $vlist + + if {$k ne "require"} continue + # vlist = package list, each element a package name, + # and optional version. + msg " ([file tail $file]: require [join [lsort -dict -unique $vlist] {, }])" + } + + # The above information also goes into the teapot meta data of + # the file in question. This however is defered until the meta + # data is actually pulled for delivery to the tool using the + # package. See 'GetMeta' for where the merging happens. + } + + return +} + +proc ::critcl::ScanCore {lines theconfig} { + # config = dictionary + # - => mode (ok, warn, sub) + # Unlisted commands are ignored. + + variable scan::config $theconfig + + set collect 0 + set buf {} + set lno -1 + foreach line $lines { + #puts |$line| + + incr lno + if {$collect} { + if {![info complete $buf]} { + append buf $line \n + continue + } + set collect 0 + + #puts %%$buf%% + + # Prevent heavily dynamic code from stopping the scan. + # WARN the user. + regexp {^(\S+)} $buf -> cmd + if {[dict exists $config $cmd]} { + set mode [dict get $config $cmd] + + if {[catch { + # Run in the scan namespace, with its special + # command implementations. + namespace eval ::critcl::scan $buf + } msg]} { + if {$mode eq "sub"} { + regexp {^(\S+)\s+(\S+)} $buf -> _ method + append cmd /$method + set mode [dict get $config $cmd] + } + if {$mode eq "warn"} { + msg "Line $lno, $cmd: Failed execution of dynamic command may" + msg "Line $lno, $cmd: cause incorrect TEA results. Please check." + msg "Line $lno, $cmd: $msg" + } + } + } + + set buf "" + # fall through, to handle the line which just got NOT + # added to the buf. + } + + set line [string trimleft $line " \t:"] + if {[string trim $line] eq {}} continue + + regexp {^(\S+)} $line -> cmd + if {[dict exists $config $cmd]} { + append buf $line \n + set collect 1 + } + } +} + +# Handle the extracted commands +namespace eval ::critcl::scan::critcl {} + +proc ::critcl::scan::critcl::buildrequirement {script} { + # Recursive scan of the script, same configuration, except + # switched to record 'package require's under the build::reqire + # key. + + variable ::critcl::scan::config + variable ::critcl::scan::rkey + + set saved $rkey + set rkey build::require + + ::critcl::ScanCore [split $script \n] $config + + set rkey $saved + return +} + +# Meta data. +# Capture specific dependencies +proc ::critcl::scan::critcl::tcl {version} { + variable ::critcl::scan::capture + dict update capture meta-system m { + dict lappend m require [list Tcl $version] + } + return +} + +proc ::critcl::scan::critcl::tk {} { + variable ::critcl::scan::capture + dict update capture meta-system m { + dict lappend m require Tk + } + return +} + +proc ::critcl::scan::critcl::description {text} { + variable ::critcl::scan::capture + dict set capture meta-system description \ + [::critcl::Text2Words $text] + return +} + +proc ::critcl::scan::critcl::summary {text} { + variable ::critcl::scan::capture + dict set capture meta-system summary \ + [::critcl::Text2Words $text] + return +} + +proc ::critcl::scan::critcl::subject {args} { + variable ::critcl::scan::capture + dict update capture meta-system m { + foreach word $args { + dict lappend m subject $word + } + } + return +} + +proc ::critcl::scan::critcl::meta {key args} { + variable ::critcl::scan::capture + dict update capture meta-user m { + foreach word $args { + dict lappend m $key $word + } + } + return +} + +# Capture files +proc ::critcl::scan::critcl::source {path} { + # Recursively scan the imported file. + # Keep the current context. + variable ::critcl::scan::config + + foreach f [Files $path] { + set lines [split [::critcl::Cat $f] \n] + ScanCore $lines $config + } + return +} +proc ::critcl::scan::critcl::owns {args} { eval [linsert $args 0 Files] } +proc ::critcl::scan::critcl::cheaders {args} { eval [linsert $args 0 Files] } +proc ::critcl::scan::critcl::csources {args} { eval [linsert $args 0 Files] } +proc ::critcl::scan::critcl::tsources {args} { + variable ::critcl::scan::capture + foreach ts [eval [linsert $args 0 Files]] { + dict lappend capture tsources $ts + } + return +} + +proc ::critcl::scan::critcl::Files {args} { + variable ::critcl::scan::capture + set res {} + foreach v $args { + if {[string match "-*" $v]} continue + foreach f [Expand $v] { + dict lappend capture files $f + lappend res $f + } + } + return $res +} + +proc ::critcl::scan::critcl::Expand {pattern} { + variable ::critcl::scan::base + + # Note: We cannot use -directory here. The PATTERN may already be + # an absolute path, in which case the join will return the + # unmodified PATTERN to glob on, whereas with -directory the final + # pattern will be BASE/PATTERN which won't find anything, even if + # PATTERN actually exists. + + set prefix [file split $base] + + set files {} + foreach vfile [glob [file join $base $pattern]] { + set xfile [file normalize $vfile] + if {![file exists $xfile]} { + error "$vfile: not found" + } + + # Constrain to be inside of the base directory. + # Snarfed from fileutil::stripPath + + set npath [file split $xfile] + + if {![string match -nocase "${prefix} *" $npath]} { + error "$vfile: Not inside of $base" + } + + set xfile [eval [linsert [lrange $npath [llength $prefix] end] 0 file join ]] + lappend files $xfile + } + return $files +} + +# Capture license (org name) +proc ::critcl::scan::critcl::license {who args} { + variable ::critcl::scan::capture + dict set capture org $who + + ::critcl::print "\tOrganization: $who" + + # Meta data. + set elicense [::critcl::LicenseText $args] + + dict set capture meta-system license \ + [::critcl::Text2Words $elicense] + dict set capture meta-system author \ + [::critcl::Text2Authors $who] + return +} + +# Capture version of the provided package. +proc ::critcl::scan::package {cmd args} { + if {$cmd eq "provide"} { + # Syntax: package provide + + variable capture + lassign $args name version + dict set capture name $name + dict set capture version $version + + # Save as meta data as well. + + dict set capture meta-system name $name + dict set capture meta-system version $version + dict set capture meta-system platform source + dict set capture meta-system generated::by \ + [list \ + [list critcl [::package present critcl]] \ + $::tcl_platform(user)] + dict set capture meta-system generated::date \ + [list [clock format [clock seconds] -format {%Y-%m-%d}]] + return + } elseif {$cmd eq "require"} { + # Syntax: package require ?-exact? + # : package require ... + + # Save dependencies as meta data. + + # Ignore the critcl core + if {[lindex $args 0] eq "critcl"} return + + variable capture + variable rkey + dict update capture meta-system m { + dict lappend m $rkey [::critcl::TeapotRequire $args] + } + return + } + + # ignore anything else. + return +} + +# Capture the APIs imported by the package +proc ::critcl::scan::critcl::api {cmd args} { + variable ::critcl::scan::capture + switch -exact -- $cmd { + header { + eval [linsert $args 0 Files] + } + import { + # Syntax: critcl::api import + lassign $args name _ + dict lappend capture imported $name + print "\tImported: $name" + } + default {} + } + return +} + +# Capture the user config options declared by the package +proc ::critcl::scan::critcl::userconfig {cmd args} { + variable ::critcl::scan::capture + switch -exact -- $cmd { + define { + # Syntax: critcl::userconfig define ?? + lassign $args oname odesc otype odefault + set odesc [string trim $odesc] + if {[llength $args] < 4} { + set odefault [::critcl::UcDefault $otype] + } + dict lappend capture config [list $oname $odesc $otype $odefault] + print "\tUser Config: $oname ([join $otype { }] -> $odefault) $odesc" + } + set - query - + default {} + } + return +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - cproc conversion helpers. + +proc ::critcl::EmitShimHeader {wname} { + # Function head + set ca "(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov\[])" + Emitln + Emitln "static int" + Emitln "$wname$ca" + Emitln \{ + return +} + +proc ::critcl::EmitShimVariables {adb rtype} { + foreach d [dict get $adb vardecls] { + Emitln " $d" + } + if {[dict get $adb hasoptional]} { + Emitln " int idx_;" + Emitln " int argc_;" + } + + # Result variable, source for the C -> Tcl conversion. + if {$rtype ne "void"} { Emit " [ResultCType $rtype] rv;" } + return +} + +proc ::critcl::EmitArgTracing {fun} { + if {!$v::options(trace)} return + Emitln "\n critcl_trace_cmd_args ($fun, oc, ov);" + return +} + +proc ::critcl::EmitWrongArgsCheck {adb} { + # Code checking for the correct count of arguments, and generating + # the proper error if not. + + set wac [dict get $adb wacondition] + if {$wac eq {}} return + + # Have a check, put the pieces together. + + set offset [dict get $adb skip] + set tsig [dict get $adb tsignature] + set min [dict get $adb min] + set max [dict get $adb max] + + incr min $offset + if {$max != Inf} { + incr max $offset + } + + lappend map MIN_ARGS $min + lappend map MAX_ARGS $max + set wac [string map $map $wac] + + Emitln "" + Emitln " if ($wac) \{" + Emitln " Tcl_WrongNumArgs(interp, $offset, ov, $tsig);" + Emitln [TraceReturns "wrong-arg-num check" " return TCL_ERROR;"] + Emitln " \}" + Emitln "" + return +} + +proc ::critcl::EmitSupport {adb} { + set s [dict get $adb support] + if {![llength $s]} return + if {[join $s {}] eq {}} return + Emit [join $s \n]\n + return +} + +proc ::critcl::EmitCall {cname cnames rtype} { + # Invoke the low-level function. + + Emitln " /* Call - - -- --- ----- -------- */" + Emit " " + if {$rtype ne "void"} { Emit "rv = " } + Emitln "${cname}([join $cnames {, }]);" + Emitln + return +} + +proc ::critcl::EmitConst {rtype rvalue} { + # Assign the constant directly to the shim's result variable. + + Emitln " /* Const - - -- --- ----- -------- */" + Emit " " + if {$rtype ne "void"} { Emit "rv = " } + Emitln "${rvalue};" + Emitln + return +} + +proc ::critcl::TraceReturns {label code} { + if {!$v::options(trace)} { + return $code + } + + # Inject tracing into the 'return's. + regsub -all \ + {return[[:space:]]*([^;]*);} $code \ + {return critcl_trace_cmd_result (\1, interp);} newcode + if {[string match {*return *} $code] && ($newcode eq $code)} { + error "Failed to inject tracing code into $label" + } + return $newcode +} + +proc ::critcl::EmitShimFooter {adb rtype} { + # Run release code for arguments which allocated temp memory. + set arelease [dict get $adb arelease] + if {[llength $arelease]} { + Emit "[join $arelease "\n "]\n" + } + + # Convert the returned low-level result from C to Tcl, if required. + # Return a standard status, if required. + + set code [Deline [ResultConversion $rtype]] + if {$code ne {}} { + set code [TraceReturns "\"$rtype\" result" $code] + Emitln " /* ($rtype return) - - -- --- ----- -------- */" + Emitln $code + } else { + if {$v::options(trace)} { + Emitln " critcl_trace_header (1, 0, 0);" + Emitln " critcl_trace_printf (1, \"RETURN (void)\");" + Emitln " critcl_trace_closer (1);" + Emitln " critcl_trace_pop();" + Emitln " return;" + } + } + Emitln \} + return +} + +proc ::critcl::ArgumentSupport {type} { + if {[info exists v::acsup($type)]} { return $v::acsup($type) } + return {} +} + +proc ::critcl::ArgumentRelease {type} { + if {[info exists v::acrel($type)]} { return $v::acrel($type) } + return {} +} + +proc ::critcl::ArgumentCType {type} { + if {[info exists v::actype($type)]} { return $v::actype($type) } + return -code error "Unknown argument type \"$type\"" +} + +proc ::critcl::ArgumentCTypeB {type} { + if {[info exists v::actypeb($type)]} { return $v::actypeb($type) } + return -code error "Unknown argument type \"$type\"" +} + +proc ::critcl::ArgumentConversion {type} { + if {[info exists v::aconv($type)]} { return $v::aconv($type) } + return -code error "Unknown argument type \"$type\"" +} + +proc ::critcl::ResultCType {type} { + if {[info exists v::rctype($type)]} { + return $v::rctype($type) + } + return -code error "Unknown result type \"$type\"" +} + +proc ::critcl::ResultConversion {type} { + if {[info exists v::rconv($type)]} { + return $v::rconv($type) + } + return -code error "Unknown result type \"$type\"" +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - Manage complex per-file settings. + +proc ::critcl::GetParam {file type {default {}}} { + if {[info exists v::code($file)] && + [dict exists $v::code($file) config $type]} { + return [dict get $v::code($file) config $type] + } else { + return $default + } +} + +proc ::critcl::SetParam {type values {expand 1} {uuid 0} {unique 0}} { + set file [This] + if {![llength $values]} return + + UUID.extend $file .$type $values + + if {$type ne "cobjects"} { + #todo (debug flag): msg "\t$type += $values" + set dtype [string map { + cheaders {headers: } + csources {companions: } + api_hdrs api-headers: + api_ehdrs {api-exthdr: } + clibraries {libraries: } + } $type] + set prefix " ($dtype " + msg "$prefix[join $values ")\n$prefix"])" + } + + # Process the list of flags, treat non-option arguments as glob + # patterns and expand them to a set of files, stored as absolute + # paths. + + set have {} + if {$unique && [dict exists $v::code($file) config $type]} { + foreach v [dict get $v::code($file) config $type] { + dict set have $v . + } + } + + set tmp {} + foreach v $values { + if {[string match "-*" $v]} { + lappend tmp $v + } else { + if {$expand} { + foreach f [Expand $file $v] { + if {$unique && [dict exists $have $f]} continue + lappend tmp $f + if {$unique} { dict set have $f . } + if {$uuid} { UUID.extend $file .$type.$f [Cat $f] } + } + } else { + if {$unique && [dict exists $have $v]} continue + lappend tmp $v + if {$unique} { dict set have $v . } + } + } + } + + if {$type eq "csources"} { + foreach v $tmp { + at::= $v 1 + Transition9Check [at::raw] [Cat $v] + } + } + + # And save into the system state. + dict update v::code($file) config c { + foreach v $tmp { + dict lappend c $type $v + } + } + + return +} + +proc ::critcl::Expand {file pattern} { + set base [file dirname $file] + + # Note: We cannot use -directory here. The PATTERN may already be + # an absolute path, in which case the join will return the + # unmodified PATTERN to glob on, whereas with -directory the final + # pattern will be BASE/PATTERN which won't find anything, even if + # PATTERN actually exists. + + set files {} + foreach vfile [glob [file join $base $pattern]] { + set vfile [file normalize $vfile] + if {![file exists $vfile]} { + error "$vfile: not found" + } + lappend files $vfile + } + return $files +} + +proc ::critcl::InitializeFile {file} { + if {![info exists v::code($file)]} { + set v::code($file) {} + + # Initialize the meta data sections (user (meta) and system + # (package)). + + dict set v::code($file) config meta {} + + dict set v::code($file) config package platform \ + [TeapotPlatform] + dict set v::code($file) config package build::date \ + [list [clock format [clock seconds] -format {%Y-%m-%d}]] + + # May not exist, bracket code. + if {![file exists $file]} return + + ScanDependencies $file $file provide + return + } + + if {![dict exists $v::code($file) config]} { + dict set v::code($file) config {} + } + return +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - Management of in-memory C source fragment. + +proc ::critcl::name2c {name} { + # Note: A slightly modified copy (different depth in the call-stack) of this + # is inlined into the internal command "BeginCommand". + + # Locate caller, as the data is saved per .tcl file. + set file [This] + + if {![string match ::* $name]} { + # Locate caller's namespace. Two up, skipping the + # ccommand/cproc frame. This is where the new Tcl command will + # be defined in. + + set ns [uplevel 1 namespace current] + if {$ns ne "::"} { append ns :: } + + set name ${ns}$name + } + + # First ensure that any namespace qualifiers found in the name + # itself are shifted over to the namespace information. + + set ns [namespace qualifiers $name] + set name [namespace tail $name] + + # Then ensure that everything is fully qualified, and that the C + # level name doesn't contain bad characters. We have to remove any + # non-alphabetic characters. A serial number is further required + # to distinguish identifiers which would, despite having different + # Tcl names, transform to the same C identifier. + + if {$ns ne "::"} { append ns :: } + set cns [string map {:: _} $ns] + + regsub -all -- {[^a-zA-Z0-9_]} $name _ cname + regsub -all -- {_+} $cname _ cname + + regsub -all -- {[^a-zA-Z0-9_]} $cns _ cns + regsub -all -- {_+} $cns _ cns + + set cname $cname[UUID.serial $file] + + return [list $ns $cns $name $cname] +} + +proc ::critcl::BeginCommand {visibility name args} { + # Locate caller, as the data is saved per .tcl file. + set file [This] + + # Inlined name2c + if {![string match ::* $name]} { + # Locate caller's namespace. Two up, skipping the + # ccommand/cproc frame. This is where the new Tcl command will + # be defined in. + + set ns [uplevel 2 namespace current] + if {$ns ne "::"} { append ns :: } + + set name ${ns}$name + } + + # First ensure that any namespace qualifiers found in the name + # itself are shifted over to the namespace information. + + set ns [namespace qualifiers $name] + set name [namespace tail $name] + + # Then ensure that everything is fully qualified, and that the C + # level identifiers don't contain bad characters. We have to + # remove any non-alphabetic characters. A serial number is further + # required to distinguish identifiers which would, despite having + # different Tcl names, transform to the same C identifier. + + if {$ns ne "::"} { append ns :: } + set cns [string map {:: _} $ns] + + regsub -all -- {[^a-zA-Z0-9_]} $name _ cname + regsub -all -- {_+} $cname _ cname + + regsub -all -- {[^a-zA-Z0-9_]} $cns _ cns + regsub -all -- {_+} $cns _ cns + + set cname $cname[UUID.serial $file] + + # Set the defered build-on-demand used by mode 'comile & run' up. + # Note: Removing the leading :: because it trips Tcl's unknown + # command, i.e. the command will not be found when called in a + # script without leading ::. + set ::auto_index([string trimleft $ns$name :]) [list [namespace current]::cbuild $file] + + set v::curr [UUID.extend $file .function "$ns $name $args"] + + dict update v::code($file) config c { + dict lappend c functions $cns$cname + dict lappend c fragments $v::curr + } + + if {$visibility eq "public"} { + Emitln "#define ns_$cns$cname \"$ns$name\"" + } + return [list $ns $cns $name $cname] +} + +proc ::critcl::EndCommand {} { + set file [This] + + set v::code($v::curr) $v::block + + dict set v::code($file) config block $v::curr $v::block + + unset v::curr + unset v::block + return +} + +proc ::critcl::Emit {s} { + append v::block $s + return +} + +proc ::critcl::Emitln {{s ""}} { + Emit $s\n + return +} + +# # ## ### ##### ######## ############# ##################### +## At internal processing + +proc ::critcl::at::Where {leadoffset level file} { + variable where + + set line 1 + + # If the interpreter running critcl has TIP 280 support use it to + # place more exact line number information into the generated C + # file. + + #puts "XXX-WHERE-($leadoffset $level $file)" + #set ::errorInfo {} + if {[catch { + #::critcl::msg [SHOWFRAMES $level 0] + array set loc [info frame $level] + #puts XXX-TYPE-$loc(type) + }]} { + #puts XXX-NO-DATA-$::errorInfo + set where {} + return + } + + if {$loc(type) eq "source"} { + #parray loc + set file $loc(file) + set fline $loc(line) + + # Adjust for removed leading whitespace. + ::incr fline $leadoffset + + # Keep the limitations of native compilers in mind and stay + # inside their bounds. + + if {$fline > $line} { + set line $fline + } + + set where [list [file tail $file] $line] + return + } + + if {($loc(type) eq "eval") && + [info exists loc(proc)] && + ($loc(proc) eq "::critcl::source") + } { + # A relative location in critcl::source is absolute in the + # sourced file. I.e. we can provide proper line information. + + set fline $loc(line) + # Adjust for removed leading whitespace. + ::incr fline $leadoffset + + # Keep the limitations of native compilers in mind and stay + # inside their bounds. + + if {$fline > $line} { + set line $fline + } + + variable ::critcl::v::source + set where [list [file tail $source] $line] + return + } + + #puts XXX-NO-DATA-$loc(type) + set where {} + return +} + +proc ::critcl::at::Loc {leadoffset level file} { + # internal variant of 'caller!' + ::incr level -1 + Where $leadoffset $level $file + return [raw] +} + +proc ::critcl::at::CPragma {leadoffset level file} { + # internal variant of 'caller!' + ::incr level -1 + Where $leadoffset $level $file + return [get] +} + +proc ::critcl::at::Format {loc} { + if {![llength $loc]} { + return "" + } + lassign $loc file line + #::critcl::msg "#line $line \"$file\"\n" + return "#line $line \"$file\"\n" +} + +proc ::critcl::at::SHOWFRAMES {level {all 1}} { + set lines {} + set n [info frame] + set i 0 + set id 1 + while {$n} { + lappend lines "[expr {$level == $id ? "**" : " "}] frame [format %3d $id]: [info frame $i]" + ::incr i -1 + ::incr id -1 + ::incr n -1 + if {($level > $id) && !$all} break + } + return [join $lines \n] +} + +# # ## ### ##### ######## ############# ##################### + +proc ::critcl::CollectEmbeddedSources {file destination libfile ininame placestubs} { + set fd [open $destination w] + + if {[dict exists $v::code($file) result apiprefix]} { + set api [dict get $v::code($file) result apiprefix] + } else { + set api "" + } + + # Boilerplate header. + puts $fd [subst [Cat [Template header.c]]] + # ^=> file, libfile, api + + # Make Tk available, if requested + if {[UsingTk $file]} { + puts $fd "\n#include \"tk.h\"" + } + + # Write the collected C fragments, in order of collection. + foreach digest [GetParam $file fragments] { + puts $fd "[Separator]\n" + puts $fd [dict get $v::code($file) config block $digest] + } + + # Boilerplate trailer. + + # Stubs setup, Tcl, and, if requested, Tk as well. + puts $fd [Separator] + set mintcl [MinTclVersion $file] + + if {$placestubs} { + # Put full stubs definitions into the code, which can be + # either the bracket generated for a -pkg, or the package + # itself, build in mode "compile & run". + msg " Stubs:" + set stubs [TclDecls $file] + set platstubs [TclPlatDecls $file] + puts -nonewline $fd [Deline [subst [Cat [Template stubs.c]]]] + # ^=> mintcl, stubs, platstubs + } else { + # Declarations only, for linking, in the sub-packages. + puts -nonewline $fd [Deline [subst [Cat [Template stubs_e.c]]]] + # ^=> mintcl + } + + if {[UsingTk $file]} { + SetupTkStubs $fd $mintcl + } + + # Initialization boilerplate. This ends in the middle of the + # FOO_Init() function, leaving it incomplete. + + set ext [GetParam $file edecls] + puts $fd [subst [Cat [Template pkginit.c]]] + # ^=> ext, ininame + + # From here on we are completing FOO_Init(). + # Tk setup first, if requested. (Tcl is already done). + if {[UsingTk $file]} { + puts $fd [Cat [Template pkginittk.c]] + } + + # User specified initialization code. + puts $fd "[GetParam $file initc] " + + # Setup of the variables serving up defined constants. + if {[dict exists $v::code($file) config const]} { + BuildDefines $fd $file + } + + # Take the names collected earlier and register them as Tcl + # commands. + set names [lsort [GetParam $file functions]] + set max [LengthLongestWord $names] + foreach name $names { + if {[info exists v::clientdata($name)]} { + set cd $v::clientdata($name) + } else { + set cd NULL + } + if {[info exists v::delproc($name)]} { + set dp $v::delproc($name) + } else { + set dp 0 + } + puts $fd " Tcl_CreateObjCommand2(interp, [PadRight [expr {$max+4}] ns_$name,] [PadRight [expr {$max+5}] tcl_$name,] $cd, $dp);" + } + + # Complete the trailer and be done. + puts $fd [Cat [Template pkginitend.c]] + close $fd + return +} + +proc ::critcl::MinTclVersion {file} { + # For the default differentiate 8.x and 9.x series. When running under 9+ an + # 8.x default is not sensible. + set mintcldefault 8.6 + if {[package vsatisfies [package provide Tcl] 9]} { set mintcldefault 9 } + + set required [GetParam $file mintcl $mintcldefault] + foreach version $v::hdrsavailable { + if {[package vsatisfies $version $required]} { + return $version + } + } + return $required +} + +proc ::critcl::UsingTk {file} { + return [GetParam $file tk 0] +} + +proc ::critcl::TclIncludes {file} { + # Provide access to the Tcl/Tk headers using a -I flag pointing + # into the critcl package directory hierarchy. No copying of files + # required. This also handles the case of the X11 headers on + # windows, for free. + + set hdrs tcl[MinTclVersion $file] + set path [file join $v::hdrdir $hdrs] + + if {[file system $path] ne "native"} { + # The critcl package is wrapped. Copy the relevant headers out + # to disk and change the include path appropriately. + + Copy $path [cache] + set path [file join [cache] $hdrs] + } + + return [list $c::include$path $c::include$v::hdrdir] +} + +proc ::critcl::TclHeader {file {header {}}} { + # Provide access to the Tcl/Tk headers in the critcl package + # directory hierarchy. No copying of files required. + set hdrs tcl[MinTclVersion $file] + return [file join $v::hdrdir $hdrs $header] +} + +proc ::critcl::SystemIncludes {file} { + set includes {} + foreach dir [SystemIncludePaths $file] { + lappend includes $c::include$dir + } + return $includes +} + +proc ::critcl::SystemIncludePaths {file} { + set paths {} + set has {} + + # critcl -I options. + foreach dir $v::options(I) { + if {[dict exists $has $dir]} continue + dict set has $dir yes + lappend paths $dir + } + + # Result cache. + lappend paths [cache] + + # critcl::cheaders + foreach flag [GetParam $file cheaders] { + if {![string match "-*" $flag]} { + # flag = normalized absolute path to a header file. + # Transform into a -I directory reference. + set dir [file dirname $flag] + } else { + # Chop leading -I + set dir [string range $flag 2 end] + } + + if {[dict exists $has $dir]} continue + dict set has $dir yes + lappend paths $dir + } + + return $paths +} + +proc ::critcl::SystemLibraries {} { + set libincludes {} + foreach dir [SystemLibraryPaths] { + lappend libincludes $c::libinclude$dir + } + return $libincludes +} + +proc ::critcl::SystemLibraryPaths {} { + set paths {} + set has {} + + # critcl -L options. + foreach dir $v::options(L) { + if {[dict exists $has $dir]} continue + dict set has $dir yes + lappend paths $dir + } + + return $paths +} + +proc ::critcl::Compile {tclfile origin cfile obj} { + StatusAbort? + + # tclfile = The .tcl file under whose auspices the C is compiled. + # origin = The origin of the C sources, either tclfile, or cfile. + # cfile = The file holding the C sources to compile. + # + # 'origin == cfile' for the companion C files of a critcl file, + # i.e. the csources. For a .tcl critcl file, the 'origin == + # tclfile', and the cfile is the .c derived from tclfile. + # + # obj = Object file to compile to, to generate. + + set cmdline [getconfigvalue compile] + lappendlist cmdline [GetParam $tclfile cflags] + lappendlist cmdline [getconfigvalue threadflags] + if {$v::options(combine) ne "standalone"} { + lappendlist cmdline [getconfigvalue tclstubs] + } + if {$v::options(language) ne "" && [file tail $tclfile] ne "critcl.tcl"} { + # XXX Is this gcc specific ? + # XXX Should this not be configurable via some c::* setting ? + # See also -x none below. + lappend cmdline -x $v::options(language) + } + lappendlist cmdline [TclIncludes $tclfile] + lappendlist cmdline [SystemIncludes $tclfile] + + if {[dict exists $v::code($tclfile) result apidefines]} { + lappendlist cmdline [dict get $v::code($tclfile) result apidefines] + } + + lappendlist cmdline [CompileResult $obj] + lappend cmdline $cfile + + if {$v::options(language) ne ""} { + # Allow the compiler to determine the type of file otherwise + # it will try to compile the libs + # XXX Is this gcc specific ? + # XXX Should this not be configurable via some c::* setting ? + lappend cmdline -x none + } + + # Add the Tk stubs to the command line, if requested and not suppressed + if {[UsingTk $tclfile] && ($v::options(combine) ne "standalone")} { + lappendlist cmdline [getconfigvalue tkstubs] + } + + if {!$option::debug_symbols} { + lappendlist cmdline [getconfigvalue optimize] + lappendlist cmdline [getconfigvalue noassert] + } + + if {[ExecWithLogging $cmdline \ + {$obj: [file size $obj] bytes} \ + {ERROR while compiling code in $origin:}]} { + if {!$v::options(keepsrc) && $cfile ne $origin} { + file delete $cfile + } + } + + return $obj +} + +proc ::critcl::MakePreloadLibrary {file} { + StatusAbort? + + # compile and link the preload support, if necessary, i.e. not yet + # done. + + set shlib [file join [cache] preload[getconfigvalue sharedlibext]] + if {[file exists $shlib]} return + + # Operate like TclIncludes. Use the template file directly, if + # possible, or, if we reside in a virtual filesystem, copy it to + # disk. + + set src [Template preload.c] + if {[file system $src] ne "native"} { + file mkdir [cache] + file copy -force $src [cache] + set src [file join [cache] preload.c] + } + + # Build the object for the helper package, 'preload' ... + + set obj [file join [cache] preload.o] + Compile $file $src $src $obj + + # ... and link it. + # Custom linker command. XXX Can we bent Link to the task? + set cmdline [getconfigvalue link] + lappend cmdline $obj + lappendlist cmdline [getconfigvalue strip] + lappendlist cmdline [LinkResult $shlib] + + ExecWithLogging $cmdline \ + {$shlib: [file size $shlib] bytes} \ + {ERROR while linking $shlib:} + + # Now the critcl application can pick up this helper shlib and + # stuff it into the package it is making. + return +} + +proc ::critcl::Link {file} { + StatusAbort? + + set shlib [dict get $v::code($file) result shlib] + set preload [dict get $v::code($file) result preload] + + # Assemble the link command. + set cmdline [getconfigvalue link] + + if {[llength $preload]} { + lappendlist cmdline [getconfigvalue link_preload] + } + + if {$option::debug_symbols} { + lappendlist cmdline [getconfigvalue link_debug] + } else { + lappendlist cmdline [getconfigvalue strip] + lappendlist cmdline [getconfigvalue link_release] + } + + lappendlist cmdline [LinkResult $shlib] + lappendlist cmdline [GetObjects $file] + lappendlist cmdline [SystemLibraries] + lappendlist cmdline [GetLibraries $file] + lappendlist cmdline [dict get $v::code($file) result ldflags] + # lappend cmdline bufferoverflowU.lib ;# msvc >=1400 && <1500 for amd64 + + # Extend library search paths with user-specified locations. + # (-L, clibraries) + set libpaths [dict get $v::code($file) result libpaths] + if {[llength $libpaths]} { + set opt [getconfigvalue link_rpath] + if {$opt ne {}} { + foreach path $libpaths { + # todo (debug flag) msg "\trpath += $path" + lappend cmdline [string map [list @ $path] $opt] + } + } + } + + # Run the linker + ExecWithLogging $cmdline \ + {$shlib: [file size $shlib] bytes} \ + {ERROR while linking $shlib:} + + # Now, if there is a manifest file around, and the + # 'embed_manifest' command defined we use its command to merge the + # manifest into the shared library. This is pretty much only + # happening on Windows platforms, and with newer dev environments + # actually using manifests. + + set em [getconfigvalue embed_manifest] + + critcl::Log "Manifest Command: $em" + critcl::Log "Manifest File: [expr {[file exists $shlib.manifest] + ? "$shlib.manifest" + : "<>, ignored"}]" + + if {[llength $em] && [file exists $shlib.manifest]} { + set cmdline [ManifestCommand $em $shlib] + + # Run the manifest tool + ExecWithLogging $cmdline \ + {$shlib: [file size $shlib] bytes, with manifest} \ + {ERROR while embedding the manifest into $shlib:} + } + + # At last, build the preload support library, if necessary. + if {[llength $preload]} { + MakePreloadLibrary $file + } + return +} + +proc ::critcl::ManifestCommand {em shlib} { + # Variable used by the subst'able config setting. + set outfile $shlib + return [subst $em] +} + +proc ::critcl::CompanionObject {src} { + set tail [file tail $src] + set srcbase [file rootname $tail] + + if {[cache] ne [file dirname $src]} { + set srcbase [file tail [file dirname $src]]_$srcbase + } + + return [file join [cache] ${srcbase}[getconfigvalue object]] +} + +proc ::critcl::CompileResult {object} { + # Variable used by the subst'able config setting. + set outfile $object + return [subst $c::output] +} + +proc ::critcl::LinkResult {shlib} { + # Variable used by the subst'able config setting. + set outfile $shlib + + set ldout [subst $c::ldoutput] + if {$ldout eq ""} { + set ldout [subst $c::output] + } + + return $ldout +} + +proc ::critcl::GetObjects {file} { + # On windows using the native MSVC compiler put the companion + # object files into a link file to read, instead of separately on + # the command line. + + set objects [dict get $v::code($file) result objects] + + if {![string match "win32-*-cl" $v::buildplatform]} { + return $objects + } + + set rsp [WriteCache link.fil \"[join $objects \"\n\"]\"] + return [list @$rsp] +} + +proc ::critcl::GetLibraries {file} { + # On windows using the native MSVC compiler, transform all -lFOO + # references into FOO.lib. + + return [FixLibraries [dict get $v::code($file) result clibraries]] +} + +proc ::critcl::FixLibraries {libraries} { + if {[string match "win32-*-cl" $v::buildplatform]} { + # On windows using the native MSVC compiler, transform all + # -lFOO references into FOO.lib. + + regsub -all -- {-l(\S+)} $libraries {\1.lib} libraries + } else { + # On unix we look for '-l:' references and rewrite them to the + # full path of the library, doing the search on our own. + # + # GNU ld understands this since at least 2.22 (don't know if + # earlier, 2.15 definitely doesn't), and it helps in + # specifying static libraries (Regular -l prefers .so over .a, + # and -l: overrides that). + + # Search paths specified via -L, -libdir. + set lpath [SystemLibraryPaths] + + set tmp {} + foreach word $libraries { + # Extend search path with -L options from clibraries. + if {[string match -L* $word]} { + lappend lpath [string range $word 2 end] + lappend tmp $word + continue + } + if {![string match -l:* $word]} { + lappend tmp $word + continue + } + # Search named library. + lappend tmp [ResolveColonSpec $lpath [string range $word 3 end]] + } + set libraries $tmp + } + + return $libraries +} + +proc ::critcl::ResolveColonSpec {lpath name} { + foreach path $lpath { + set f [file join $lpath $name] + if {![file exists $f]} continue + return $f + } + return -l:$name +} + +proc ::critcl::SetupTkStubs {fd mintcl} { + if {[package vcompare $mintcl 8.6] < 0} { + # Before 8.6+. tkStubsPtr and tkIntXlibStubsPtr are not const yet. + set contents [Cat [Template tkstubs_noconst.c]] + } else { + set contents [Cat [Template tkstubs.c]] + } + + puts -nonewline $fd $contents + return +} + +proc ::critcl::BuildDefines {fd file} { + # we process the cdefines in three steps + # - get the list of defines by preprocessing the source using the + # cpp -dM directive which causes any #defines to be output + # - extract the list of enums using regular expressions (not perfect, + # but will do for now) + # - generate Tcl_ObjSetVar2 commands to initialise Tcl variables + + # Pull the collected ccode blocks together into a transient file + # we then search in. + + set def [WriteCache define_[pid].c {}] + foreach digest [dict get $v::code($file) config defs] { + Append $def [dict get $v::code($file) config block $digest] + } + + # For the command lines to be constructed we need all the include + # information the regular files will get during their compilation. + + set hdrs [SystemIncludes $file] + + # The result of the next two steps, a list of triples (namespace + + # label + value) of the defines to export. + + set defines {} + + # First step - get list of matching defines + set cmd [getconfigvalue preproc_define] + lappendlist cmd $hdrs + lappend cmd $def + + set pipe [open "| $cmd" r] + while {[gets $pipe line] >= 0} { + # Check if the line contains a define. + set fields [split [string trim $line]] + if {[lindex $fields 0] ne "#define"} continue + + # Yes. Get name and value. The latter is the joining of all + # fields after the name, except for any enclosing parentheses, + # which we strip off. + + set var [lindex $fields 1] + set val [string trim [join [lrange $fields 2 end]] {()}] + + # We ignore however any and all defines the user is not + # interested in making public. This is, in essence, a set + # intersection on the names of the defines. + + if {![TakeDefine $file $var namespace]} continue + + # And for those which are kept we integrate the information + # from both sources, i.e. namespace, and definition, under a + # single name. + + lappend defines $namespace $var $val + } + close $pipe + + # Second step - get list of enums + + set cmd [getconfigvalue preproc_enum] + lappendlist cmd $hdrs + lappend cmd $def + + set pipe [open "| $cmd" r] + set code [read $pipe] + close $pipe + + set matches [regexp -all -inline {enum [^\{\(\)]*{([^\}]*)}} $code] + foreach {match submatch} $matches { + foreach line [split $submatch \n] { + foreach sub [split $line ,] { + set enum [lindex [split [string trim $sub]] 0] + + # We ignore however any and all enum values the user + # is not interested in making public. This is, in + # essence, a set intersection on the names of the + # enum values. + + if {![TakeDefine $file $enum namespace]} continue + + # And for those which are kept we integrate the + # information from both sources, i.e. namespace, and + # definition, under a single name. + + lappend defines $namespace $enum $enum + } + } + } + + # Third step - generate Tcl_ObjSetVar2 commands exporting the + # defines and their values as Tcl variables. + + foreach {namespace constname constvalue} $defines { + if {![info exists created($namespace)]} { + # we need to force the creation of the namespace + # because this code will be run before the user code + puts $fd " Tcl_Eval(ip, \"namespace eval $namespace {}\");" + set created($namespace) 1 + } + set var "Tcl_NewStringObj(\"${namespace}::$constname\", -1)" + if {$constname eq $constvalue} { + # enum - assume integer + set constvalue "Tcl_NewIntObj($constvalue)" + } else { + # text or int - force to string + set constvalue "Tcl_NewStringObj(\"$constvalue\", -1)" + } + puts $fd " Tcl_ObjSetVar2(ip, $var, NULL, $constvalue, TCL_GLOBAL_ONLY);" + } + + # Cleanup after ourselves, removing the helper file. + + if {!$v::options(keepsrc)} { file delete $def } + return +} + +proc ::critcl::TakeDefine {file identifier nsvar} { + upvar 1 $nsvar dst + if 0 {if {[dict exists $v::code($file) config const $identifier]} { + set dst [dict get $v::code($file) config const $identifier] + return 1 + }} + foreach {pattern def} [dict get $v::code($file) config const] { + if {[string match $pattern $identifier]} { + set dst $def + return 1 + } + } + return 0 +} + +proc ::critcl::Load {f} { + set shlib [dict get $v::code($f) result shlib] + set init [dict get $v::code($f) result initname] + set tsrc [dict get $v::code($f) result tsources] + set minv [dict get $v::code($f) result mintcl] + + # Using the renamed builtin. While this is a dependency it was + # recorded already. See 'critcl::tcl', and 'critcl::tk'. + #package require Tcl $minv + ::load $shlib $init + + # See the critcl application for equivalent code placing the + # companion tcl sources into the generated package. Here, for + # 'compile & run' we now source the companion files directly. + foreach t $tsrc { + Ignore $t + ::source $t + } + return +} + +proc ::critcl::ResolveRelative {prefixes flags} { + set new {} + set take no + foreach flag $flags { + if {$take} { + set take no + set flag [file normalize [file join [file dirname [This]] $flag]] + lappend new $flag + continue + } + foreach prefix $prefixes { + if {$flag eq $prefix} { + set take yes + lappend new $flag + break + } + set n [string length $prefix] + if {[string match ${prefix}* $flag]} { + set path [string range $flag $n end] + set flag ${prefix}[file normalize [file join [file dirname [This]] $path]] + break + } + if {[string match ${prefix}=* $flag]} { + incr n + set path [string range $flag $n end] + set flag ${prefix}[file normalize [file join [file dirname [This]] $path]] + break + } + } + lappend new $flag + } + return $new +} + +proc ::critcl::LibPaths {clibraries} { + set lpath {} + set take no + + set sa [string length -L] + set sb [string length --library-directory=] + + foreach word $clibraries { + # Get paths from -L..., --library-directory ..., + # --library-directory=... and full library paths. Ignore + # anything else. + + if {$take} { + # path argument separate from preceding option. + set take no + lappend lpath $word + continue + } + if {[string match -L* $word]} { + # path at tail of argument + lappend lpath [string range $word $sa end] + continue + } + if {[string match -l* $word]} { + # ignore + continue + } + if {[string match --library-directory=* $word]} { + # path at tail of argument + lappend lpath [string range $word $sb end] + continue + } + if {[string equal --library-directory $word]} { + # Next argument is the desired path + set take yes + continue + } + if {[file isfile $word]} { + # directory of the file + lappend lpath [file dirname $word] + } + # else ignore + } + return $lpath +} + +proc ::critcl::HandleDeclAfterBuild {} { + # Hook default, mode "compile & run". Clear existing build results + # for the file, make way for new declarations. + + set fx [This] + if {[info exists v::code($fx)] && + [dict exists $v::code($fx) result]} { + dict unset v::code($fx) result + } + return +} + +# XXX Refactor to avoid duplication of the memoization code. +proc ::critcl::DetermineShlibName {file} { + # Return cached information, if present. + if {[info exists v::code($file)] && + [dict exists $v::code($file) result shlib]} { + return [dict get $v::code($file) result shlib] + } + + # The name of the shared library we hope to produce (or use) + set shlib [BaseOf $file][getconfigvalue sharedlibext] + + dict set v::code($file) result shlib $shlib + return $shlib +} + +proc ::critcl::DetermineObjectName {file} { + # Return cached information, if present. + if {[info exists v::code($file)] && + [dict exists $v::code($file) result object]} { + return [dict get $v::code($file) result object] + } + + set object [BaseOf $file] + + # The generated object file will be saved for permanent use if the + # outdir option is set (in which case rebuilds will no longer be + # automatic). + if {$v::options(outdir) ne ""} { + set odir [file join [file dirname $file] $v::options(outdir)] + set oroot [file rootname [file tail $file]] + set object [file normalize [file join $odir $oroot]] + file mkdir $odir + } + + # Modify the output file name if debugging symbols are requested. + if {$option::debug_symbols} { + append object _g + } + + # Choose a distinct suffix so switching between them causes a + # rebuild. + switch -- $v::options(combine) { + "" - + dynamic { append object _pic[getconfigvalue object] } + static { append object _stub[getconfigvalue object] } + standalone { append object [getconfigvalue object] } + } + + dict set v::code($file) result object $object + return $object +} + +proc ::critcl::DetermineInitName {file prefix} { + set ininame [PkgInit $file] + + # Add in the build prefix, if specified. This is done in mode + # 'generate package', for the pieces, ensuring that the overall + # initialization function cannot be in conflict with the + # initialization functions of these same pieces. + + if {$prefix ne ""} { + set ininame "${prefix}_$ininame" + } + + dict set v::code($file) result initname $ininame + + catch { + dict set v::code($file) result pkgname \ + [dict get $v::code($file) config package name] + } + + return $ininame +} + +proc ::critcl::PkgInit {file} { + # The init function name takes a capitalized prefix from the name + # of the input file name (alphanumeric prefix, including + # underscores). This implicitly drops the file extension, as the + # '.' is not an allowed character. + + # While related to the package name, it can be different, + # especially if the package name contains :: separators. + + if {$file eq {}} { + return Stdin + } else { + set ininame [file rootname [file tail $file]] + regsub -all {[^[:alnum:]_]} $ininame {} ininame + return [string totitle $ininame] + } +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - Access to the log file + +proc ::critcl::LogFile {} { + file mkdir [cache] + return [file join [cache] [pid].log] +} + +proc ::critcl::LogFileExec {} { + file mkdir [cache] + return [file join [cache] [pid]_exec.log] +} + +proc ::critcl::LogOpen {file} { + set v::logfile [LogFile] + set v::log [open $v::logfile w] + puts $v::log "\n[clock format [clock seconds]] - $file" + # Create secondary file as well, leave empty, may not be used. + close [open ${v::logfile}_ w] + return +} + +proc ::critcl::LogCmdline {cmdline} { + set w [join [lassign $cmdline cmd] \n\t] + Log \n$cmd\n\t$w\n + return +} + +proc ::critcl::Log {msg} { + puts $v::log $msg + return +} + +proc ::critcl::Log* {msg} { + puts -nonewline $v::log $msg + return +} + +proc ::critcl::LogClose {} { + # Transfer the log messages for the current file over into the + # global critcl log, and cleanup. + + close $v::log + set msgs [Cat $v::logfile] + set emsg [Cat ${v::logfile}_] + + AppendCache $v::prefix.log $msgs + + file delete -force $v::logfile ${v::logfile}_ + unset v::log v::logfile + + return [list $msgs $emsg] +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - UUID management, change detection + +proc ::critcl::UUID.extend {file key value} { + set digest [md5_hex /$value] + InitializeFile $file + dict update v::code($file) config c { + dict lappend c uuid $key $digest + } + return $digest +} + +proc ::critcl::UUID.serial {file} { + InitializeFile $file + if {[catch { + set len [llength [dict get $v::code($file) config uuid]] + }]} { + set len 0 + } + return $len +} + +proc ::critcl::UUID {f} { + return [md5_hex "$f [GetParam $f uuid]"] +} + +proc ::critcl::BaseOf {f} { + # Return cached information, if present. + if {[info exists v::code($f)] && + [dict exists $v::code($f) result base]} { + return [dict get $v::code($f) result base] + } + + set base [file normalize \ + [file join [cache] ${v::prefix}_[UUID $f]]] + + dict set v::code($f) result base $base + return $base +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - Miscellanea + +proc ::critcl::Deline {text} { + if {![config lines]} { + set text [join [GrepV "\#line*" [split $text \n]] \n] + } + return $text +} + +proc ::critcl::Separator {} { + return "/* [string repeat - 70] */" +} + +proc ::critcl::Template {file} { + variable v::hdrdir + return [file join $hdrdir $file] +} + +proc ::critcl::Copy {src dst} { + foreach p [glob -nocomplain $src] { + if {[file isdirectory $p]} { + set stem [file tail $p] + file mkdir $dst/$stem + Copy $p/* $dst/$stem + } else { + file copy -force $p $dst + } + } +} + +proc ::critcl::Cat {path} { + # Easier to write our own copy than requiring fileutil and then + # using fileutil::cat. + + set fd [open $path r] + set data [read $fd] + close $fd + return $data +} + +proc ::critcl::WriteCache {name content} { + set dst [file join [cache] $name] + file mkdir [file dirname $dst] ;# just in case + return [Write [file normalize $dst] $content] +} + +proc ::critcl::Write {path content} { + set chan [open $path w] + puts $chan $content + close $chan + return $path +} + +proc ::critcl::AppendCache {name content} { + file mkdir [cache] ;# just in case + return [Append [file normalize [file join [cache] $name]] $content] +} + +proc ::critcl::Append {path content} { + set chan [open $path a] + puts $chan $content + close $chan + return $path +} + +# # ## ### ##### ######## ############# ##################### +## Implementation -- Internals - Status Operations, and execution +## of external commands. + +proc ::critcl::StatusReset {} { + set v::failed 0 + return +} + +proc ::critcl::StatusAbort? {} { + if {$v::failed} { return -code return } + return +} + +proc ::critcl::StatusSave {file} { + # XXX FUTURE Use '$(file) result failed' later + set result $v::failed + set v::code($file,failed) $v::failed + set v::failed 0 + return $result +} + +proc ::critcl::CheckForWarnings {text} { + set warnings [dict create] + foreach line [split $text \n] { + # Ignore everything not a warning. + if {![string match -nocase *warning* $line]} continue + # Ignore duplicates (which is why we store the lines as dict + # keys for now). + if {[dict exists $warnings $line]} continue + dict set warnings $line . + } + return [dict keys $warnings] +} + +proc ::critcl::Exec {cmdline} { + variable run + + set v::failed [catch { + interp eval $run [linsert $cmdline 0 exec] + } v::err] + + return [expr {!$v::failed}] +} + +proc ::critcl::ExecWithLogging {cmdline okmsg errmsg} { + variable run + + # todo (debug flag) msg "EXEC: $cmdline" + LogCmdline $cmdline + + # Extend the command, redirect all of its output (stdout and + # stderr) into a temp log. + set elogfile [LogFileExec] + set elog [open $elogfile w] + + lappend cmdline >&@ $elog + interp transfer {} $elog $run + + set ok [Exec $cmdline] + + interp transfer $run $elog {} + close $elog + + # Put the command output into the main log ... + set msgs [Cat $elogfile] + Log $msgs + + # ... as well as into a separate execution log. + Append ${v::logfile}_ $msgs + + file delete -force $elogfile + + if {$ok} { + Log [uplevel 1 [list subst $okmsg]] + } else { + Log [uplevel 1 [list subst $errmsg]] + Log $v::err + } + + return $ok +} + +proc ::critcl::BuildPlatform {} { + set platform [::platform::generic] + + # Behave like an autoconf generated configure + # - $CC (user's choice first) + # - gcc, if available. + # - cc/cl otherwise (without further check for availability) + + if {[info exists ::env(CC)]} { + # The compiler may be a gcc, despite being named .../cc. + + set cc $::env(CC) + if {[IsGCC $cc]} { + set cc gcc + } + } elseif {[llength [auto_execok gcc]]} { + set cc gcc + } else { + if {[string match "win32-*" $platform]} { + set cc cl + } else { + set cc cc + } + } + + # The cc may be specified with a full path, through the CC + # environment variable, which cannot be used as is in the platform + # code. Use only the last element of the path, without extensions + # (.exe). And it may be followed by options too, so look for and + # strip these off as well. This last part assumes that the path of + # the compiler itself doesn't contain spaces. + + regsub {( .*)$} [file tail $cc] {} cc + append platform -[file rootname $cc] + + # Memoize + proc ::critcl::BuildPlatform {} [list return $platform] + return $platform +} + +proc ::critcl::IsGCC {path} { + if {[catch { + set lines [exec $path -v |& grep gcc] + }] || ($lines eq {})} { return 0 } + return 1 +} + +proc ::critcl::This {} { + variable v::this + # For management of v::this see critcl::{source,collect*} + # If present, an output redirection is active. + if {[info exists this] && [llength $this]} { + return [lindex $this end] + } + return [file normalize [info script]] +} + +proc ::critcl::Here {} { + return [file dirname [This]] +} + +proc ::critcl::TclDecls {file} { + return [TclDef $file tclDecls.h tclStubsPtr {tclStubsPtr }] +} + +proc ::critcl::TclPlatDecls {file} { + return [TclDef $file tclPlatDecls.h tclPlatStubsPtr tclPlatStubsPtr] +} + +proc ::critcl::TclDef {file hdr var varlabel} { + #puts F|$file + set hdr [TclHeader $file $hdr] + + if {![file exists $hdr]} { error "Header file not found: $hdr" } + if {![file isfile $hdr]} { error "Header not a file: $hdr" } + if {![file readable $hdr]} { error "Header not readable: $hdr (no permission)" } + + #puts H|$hdr + if {[catch { + set hdrcontent [split [Cat $hdr] \n] + } msg]} { + error "Header not readable: $hdr ($msg)" + } + + # Note, Danger: The code below is able to use declarations which + # are commented out in various ways (#if 0, /* ... */, and // + # ...), because it is performing a simple line-oriented search + # without context, and not matching against comment syntax either. + + set ext [Grep *extern* $hdrcontent] + if {![llength $ext]} { + error "No extern declarations found in $hdr" + } + + set vardecl [Grep *${var}* $ext] + if {![llength $vardecl]} { + error "No declarations for $var found in $hdr" + } + + set def [string map {extern {}} [lindex $vardecl 0]] + msg " [join [lrange [file split $hdr] end-3 end] /]:" + msg " ($varlabel => $def)" + return $def +} + +proc ::critcl::Grep {pattern lines} { + set r {} + foreach line $lines { + if {![string match $pattern $line]} continue + lappend r $line + } + return $r +} + +proc ::critcl::GrepV {pattern lines} { + set r {} + foreach line $lines { + if {[string match $pattern $line]} continue + lappend r $line + } + return $r +} + +proc ::critcl::PadRight {len w} { + # <=> Left justified + format %-${len}s $w +} + +proc ::critcl::LengthLongestWord {words} { + set max 0 + foreach w $words { + set n [string length $w] + if {$n <= $max} continue + set max $n + } + return $max +} + +# # ## ### ##### ######## ############# ##################### +## Tcl 8.6 vs 9 checking. The check is simple, there is no C +## parsing. No detection of C comments either. + +proc ::critcl::Transition9Check {loc script} { + if {!$v::options(tcl9)} return + + lassign $loc filename lno + if {$filename eq {}} { set filename } + if {$lno eq {}} { set lno 1 } + + foreach line [split $script \n] { + Transition9CheckLine $filename $lno $line + incr lno + } + return +} + +proc ::critcl::Transition9CheckLine {file lno codeline} { + set reported 0 + + # TIP 568 Tcl_GetByteArrayFromObj transition to Tcl_GetBytesFromObj + if {[string match *Tcl_GetByteArrayFromObj* $codeline]} { + T9Report $file $lno $codeline "(TIP 568): Use `Tcl_GetBytesFromObj` and handle NULL results." + T9Report $file $lno $codeline "(TIP 568): Read the referenced TIP for the sordid details." + T9Report $file $lno $codeline "(TIP 568): Document the obligations of the script level." + } + + foreach fun { + Tcl_NewStringObj + Tcl_AppendToObj + Tcl_AddObjErrorInfo + Tcl_DStringAppend + Tcl_NumUtfChars + Tcl_UtfToUniCharDString + Tcl_LogCommandInfo + Tcl_AppendLimitedToObj + } { + if { [string match *${fun}* $codeline] && + [string match *-1* $codeline] && + ![string match {*OK tcl9*} $codeline]} { + T9Report $file $lno $codeline "(TIP 494): Use TCL_AUTO_LENGTH for string length." + } + } + + # Tcl_Size I + foreach {kind fun} [Transition9TclSize] { + if {![string match *${fun}* $codeline]} continue + if { [string match {*OK tcl9*} $codeline]} continue + T9Report $file $lno $codeline "(Tcl_Size): $fun ($kind)" + } + + # Tcl_Size II + foreach {fun replace} { + Tcl_GetIntFromObj Tcl_GetSizeIntFromObj + Tcl_NewIntObj Tcl_NewSizeIntObj + } { + if {![string match *${fun}* $codeline]} continue + if { [string match {*OK tcl9*} $codeline]} continue + T9Report $file $lno $codeline "(Tcl_Size): $fun, check if replacement $replace is needed" + } + + # Tcl Interp State handling + foreach {pattern message} { + Tcl_SavedResult {Reewrite to use type `Tcl_InterpState` instead} + Tcl_SaveResult {Rewrite to ` = Tcl_SaveInterpState (, TCL_OK)`} + Tcl_RestoreResult {Rewrite to `Tcl_RestoreInterpState (, )`} + Tcl_DiscardResult {Rewrite to `Tcl_DiscardInterpState ()`} + } { + if {![string match *${pattern}* $codeline]} continue + T9Report $file $lno $codeline "(Interp State handling): $message" + } + + # command creation + if { [string match *Tcl_CreateObjCommand* $codeline] && + ![string match *Tcl_CreateObjCommand2* $codeline]} { + T9Report $file $lno $codeline "(Tcl_Size): Use `Tcl_CreateObjCommand2` for command creation" + } + return +} + +proc ::critcl::T9Report {fname lno code msg} { + upvar 1 reported reported + + set prefix "File \"$fname\", line $lno: " + set common "Tcl 9 compatibility warning " + + set blue \033\[34m + set off \033\[0m + set mag \033\[35m + + if {!$reported} { critcl::msg "$prefix$blue[string trim $code]$off" } + incr reported + critcl::msg "$prefix${common}: $mag$msg$off" +} + +proc ::critcl::Transition9TclSize {} { + return { + InParam Tcl_AppendFormatToObj + InParam Tcl_AppendLimitedToObj + InParam Tcl_AppendLimitedToObj + InParam Tcl_AppendToObj + InParam Tcl_AppendUnicodeToObj + InParam Tcl_AttemptSetObjLength + InParam Tcl_Char16ToUtfDString + InParam Tcl_Concat + InParam Tcl_ConcatObj + InParam Tcl_ConvertCountedElement + InParam Tcl_CreateAlias + InParam Tcl_CreateAliasObj + InParam Tcl_CreateObjTrace + InParam Tcl_CreateObjTrace2 + InParam Tcl_CreateTrace + InParam Tcl_DbNewByteArrayObj + InParam Tcl_DbNewListObj + InParam Tcl_DbNewStringObj + InParam Tcl_DetachPids + InParam Tcl_DictObjPutKeyList + InParam Tcl_DictObjRemoveKeyList + InParam Tcl_DStringAppend + InParam Tcl_DStringSetLength + InParam Tcl_EvalEx + InParam Tcl_EvalObjv + InParam Tcl_EvalTokensStandard + InParam Tcl_ExternalToUtf + InParam Tcl_ExternalToUtf + InParam Tcl_ExternalToUtfDString + InParam Tcl_ExternalToUtfDStringEx + InParam Tcl_Format + InParam Tcl_FSJoinPath + InParam Tcl_FSJoinToPath + InParam Tcl_GetIndexFromObjStruct + InParam Tcl_GetIntForIndex + InParam Tcl_GetNumber + InParam Tcl_GetRange + InParam Tcl_GetRange + InParam Tcl_GetThreadData + InParam Tcl_GetUniChar + InParam Tcl_JoinPath + InParam Tcl_LimitSetCommands + InParam Tcl_LinkArray + InParam Tcl_ListObjIndex + InParam Tcl_ListObjReplace + InParam Tcl_ListObjReplace + InParam Tcl_ListObjReplace + InParam Tcl_LogCommandInfo + InParam Tcl_MacOSXOpenVersionedBundleResources + InParam Tcl_MainEx + InParam Tcl_Merge + InParam Tcl_NewByteArrayObj + InParam Tcl_NewListObj + InParam Tcl_NewStringObj + InParam Tcl_NewUnicodeObj + InParam Tcl_NRCallObjProc + InParam Tcl_NRCallObjProc2 + InParam Tcl_NRCmdSwap + InParam Tcl_NREvalObjv + InParam Tcl_NumUtfChars + InParam Tcl_OpenCommandChannel + InParam Tcl_ParseBraces + InParam Tcl_ParseCommand + InParam Tcl_ParseExpr + InParam Tcl_ParseQuotedString + InParam Tcl_ParseVarName + InParam Tcl_PkgRequireProc + InParam Tcl_ProcObjCmd + InParam Tcl_Read + InParam Tcl_ReadChars + InParam Tcl_ReadRaw + InParam Tcl_RegExpExecObj + InParam Tcl_RegExpExecObj + InParam Tcl_RegExpRange + InParam Tcl_ScanCountedElement + InParam Tcl_SetByteArrayLength + InParam Tcl_SetByteArrayObj + InParam Tcl_SetChannelBufferSize + InParam Tcl_SetListObj + InParam Tcl_SetObjLength + InParam Tcl_SetRecursionLimit + InParam Tcl_SetStringObj + InParam Tcl_SetUnicodeObj + InParam Tcl_Ungets + InParam Tcl_UniCharAtIndex + InParam Tcl_UniCharToUtfDString + InParam Tcl_UtfAtIndex + InParam Tcl_UtfCharComplete + InParam Tcl_UtfToChar16DString + InParam Tcl_UtfToExternal + InParam Tcl_UtfToExternal + InParam Tcl_UtfToExternalDString + InParam Tcl_UtfToExternalDStringEx + InParam Tcl_UtfToUniCharDString + InParam Tcl_Write + InParam Tcl_WriteChars + InParam Tcl_WriteRaw + InParam Tcl_WrongNumArgs + InParam Tcl_ZlibAdler32 + InParam Tcl_ZlibCRC32 + InParam Tcl_ZlibInflate + InParam Tcl_ZlibStreamGet + InParam TclGetRange + InParam TclGetRange + InParam TclGetUniChar + InParam TclNumUtfChars + InParam TclUtfAtIndex + InParam TclUtfCharComplete + + OutParam Tcl_DictObjSize + OutParam Tcl_ExternalToUtfDStringEx + OutParam Tcl_FSSplitPath + OutParam Tcl_GetByteArrayFromObj + OutParam Tcl_GetBytesFromObj + OutParam Tcl_GetIntForIndex + OutParam Tcl_GetSizeIntFromObj + OutParam Tcl_GetStringFromObj + OutParam Tcl_GetUnicodeFromObj + OutParam Tcl_ListObjGetElements + OutParam Tcl_ListObjLength + OutParam Tcl_ParseArgsObjv + OutParam Tcl_SplitList + OutParam Tcl_SplitPath + OutParam Tcl_UtfToExternalDStringEx + + Return Tcl_Char16Len + Return Tcl_ConvertCountedElement + Return Tcl_ConvertElement + Return Tcl_GetChannelBufferSize + Return Tcl_GetCharLength + Return Tcl_GetEncodingNulLength + Return Tcl_Gets + Return Tcl_GetsObj + Return Tcl_NumUtfChars + Return Tcl_Read + Return Tcl_ReadChars + Return Tcl_ReadRaw + Return Tcl_ScanCountedElement + Return Tcl_ScanElement + Return Tcl_SetRecursionLimit + Return Tcl_Ungets + Return Tcl_UniCharLen + Return Tcl_UniCharToUtf + Return Tcl_UtfBackslash + Return Tcl_UtfToChar16 + Return Tcl_UtfToLower + Return Tcl_UtfToTitle + Return Tcl_UtfToUniChar + Return Tcl_UtfToUpper + Return Tcl_Write + Return Tcl_WriteChars + Return Tcl_WriteObj + Return Tcl_WriteRaw + Return TclGetCharLength + Return TclNumUtfChars + } +} + +# # ## ### ##### ######## ############# ##################### +## Initialization + +proc ::critcl::Initialize {} { + variable mydir [Here] ; # Path of the critcl package directory. + + variable run [interp create] + variable v::buildplatform [BuildPlatform] + variable v::hdrdir [file join $mydir critcl_c] + variable v::hdrsavailable + variable v::storageclass [Cat [file join $hdrdir storageclass.c]] + + # Scan the directory holding the C fragments and our copies of the + # Tcl header and determine for which versions of Tcl we actually + # have headers. This allows distributions to modify the directory, + # i.e. drop our copies and refer to the system headers instead, as + # much as are installed, and critcl adapts. The tcl versions are + # recorded in ascending order, making upcoming searches easier, + # the first satisfying version is also always the smallest. + + foreach d [lsort -dict [glob -types {d r} -directory $hdrdir -tails tcl*]] { + lappend hdrsavailable [regsub {^tcl} $d {}] + } + + # The prefix is based on the package's version. This allows + # multiple versions of the package to use the same cache without + # interfering with each. Note that we cannot use 'pid' and similar + # information, because this would circumvent the goal of the + # cache, the reuse of binaries whose sources did not change. + + variable v::prefix "v[package require critcl]" + + regsub -all {\.} $prefix {} prefix + + # keep config options in a namespace + foreach var $v::configvars { + set c::$var {} + } + + # read default configuration. This also chooses and sets the + # target platform. + readconfig [file join $mydir Config] + + # Declare the standard argument types for cproc. + + argtype int { + if (Tcl_GetIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR; + } + argtype boolean { + if (Tcl_GetBooleanFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR; + } int int + argtype bool = boolean + + argtype long { + if (Tcl_GetLongFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR; + } + + argtype wideint { + if (Tcl_GetWideIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR; + } Tcl_WideInt Tcl_WideInt + + argtype double { + if (Tcl_GetDoubleFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR; + } + argtype float { + double t; + if (Tcl_GetDoubleFromObj(interp, @@, &t) != TCL_OK) return TCL_ERROR; + @A = (float) t; + } + + # Premade scalar type derivations for common range restrictions. + # Look to marker XXXA for the places where auto-creation would + # need fitting in (future). + # + # See also `MakeScalarLimited`, which is able to generate validators for extended forms of this + # kind (multiple relations, arbitrary limit values, ...) + foreach type { + int long wideint double float + } { + set ctype [ArgumentCType $type] + set code [ArgumentConversion $type] + foreach restriction { + {> 0} {>= 0} {> 1} {>= 1} + {< 0} {<= 0} {< 1} {<= 1} + } { + set ntype "$type $restriction" + set head "expected $ntype, but got \\\"" + set tail "\\\"" + set msg "\"$head\", Tcl_GetString (@@), \"$tail\"" + set new $code + append new \ + "\n\t/* Range check, assert (x $restriction) */" \ + "\n\tif (!(@A $restriction)) \{" \ + "\n\t Tcl_AppendResult (interp, $msg, NULL);" \ + "\n\t return TCL_ERROR;" \ + "\n\t\}" + + argtype $ntype $new $ctype $ctype + } + } + + argtype char* { + @A = Tcl_GetString(@@); + } {const char*} {const char*} + + argtype pstring { + @A.s = Tcl_GetStringFromObj(@@, &(@A.len)); + @A.o = @@; + } critcl_pstring critcl_pstring + + argtypesupport pstring { + typedef struct critcl_pstring { + Tcl_Obj* o; + const char* s; + Tcl_Size len; + } critcl_pstring; + } + + argtype dict { + Tcl_Size size; + if (Tcl_DictObjSize (interp, @@, &size) != TCL_OK) return TCL_ERROR; + @A = @@; + } Tcl_Obj* Tcl_Obj* + + argtype list { + if (Tcl_ListObjGetElements (interp, @@, /* OK tcl9 */ + &(@A.c), (Tcl_Obj***) &(@A.v)) != TCL_OK) return TCL_ERROR; + @A.o = @@; + } critcl_list critcl_list + + argtypesupport list { + typedef struct critcl_list { + Tcl_Obj* o; + Tcl_Obj* const* v; + Tcl_Size c; + } critcl_list; + } + + # See also `MakeList` which is able to generate arbitrary length-limited lists, lists over a + # base type, or a combination of both. This here defines the base case of the recognized syntax + # for "unlimited-length list with no base type". This shortcuts the operation of `MakeList`, no + # special types and code needed. + argtype {[]} = list + argtype {[*]} = list + + argtype Tcl_Obj* { + @A = @@; + } + argtype object = Tcl_Obj* + + # Predefined variadic type for the special Tcl_Obj*. + # - No actual conversion, nor allocation, copying, release needed. + # - Just point into and reuse the incoming ov[] array. + # This shortcuts the operation of 'MakeVariadicTypeFor'. + + argtype variadic_object { + @A.c = @C; + @A.v = &ov[@I]; + } critcl_variadic_object critcl_variadic_object + + argtypesupport variadic_object { + typedef struct critcl_variadic_object { + int c; + Tcl_Obj* const* v; + } critcl_variadic_object; + } + + argtype variadic_Tcl_Obj* = variadic_object + + # NEW Raw binary string _with_ length information. + + argtype bytes { + /* Raw binary string _with_ length information */ + @A.s = Tcl_GetBytesFromObj(interp, @@, &(@A.len)); + if (@A.s == NULL) return TCL_ERROR; + @A.o = @@; + } critcl_bytes critcl_bytes + + argtypesupport bytes { + typedef struct critcl_bytes { + Tcl_Obj* o; + const unsigned char* s; + Tcl_Size len; + } critcl_bytes; + } + + argtype channel { + int mode; + @A = Tcl_GetChannel(interp, Tcl_GetString (@@), &mode); + if (@A == NULL) return TCL_ERROR; + } Tcl_Channel Tcl_Channel + + argtype unshared-channel { + int mode; + @A = Tcl_GetChannel(interp, Tcl_GetString (@@), &mode); + if (@A == NULL) return TCL_ERROR; + if (Tcl_IsChannelShared (@A)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("channel is shared", -1)); + return TCL_ERROR; + } + } Tcl_Channel Tcl_Channel + + # Note, the complementary resulttype is `return-channel`. + argtype take-channel { + int mode; + @A = Tcl_GetChannel(interp, Tcl_GetString (@@), &mode); + if (@A == NULL) return TCL_ERROR; + if (Tcl_IsChannelShared (@A)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("channel is shared", -1)); + return TCL_ERROR; + } + { + /* Disable event processing for the channel, both by + * removing any registered handler, and forcing interest + * to none. This also disables the processing of pending + * events which are ready to fire for the given + * channel. If we do not do this, events will hit the + * detached channel and potentially wreck havoc on our + * memory and eventually badly hurt us... + */ + Tcl_DriverWatchProc *watchProc; + Tcl_ClearChannelHandlers(@A); + watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(@A)); + if (watchProc) { + (*watchProc)(Tcl_GetChannelInstanceData(@A), 0); + } + /* Next some fiddling with the reference count to prevent + * the unregistration from killing it. We basically record + * it as globally known before removing it from the + * current interpreter + */ + Tcl_RegisterChannel((Tcl_Interp *) NULL, @A); + Tcl_UnregisterChannel(interp, @A); + } + } Tcl_Channel Tcl_Channel + + resulttype void { + return TCL_OK; + } + + resulttype ok { + return rv; + } int + + resulttype int { + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; + } + resulttype boolean = int + resulttype bool = int + + resulttype long { + Tcl_SetObjResult(interp, Tcl_NewLongObj(rv)); + return TCL_OK; + } + + resulttype wideint { + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(rv)); + return TCL_OK; + } Tcl_WideInt + + resulttype double { + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rv)); + return TCL_OK; + } + resulttype float { + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rv)); + return TCL_OK; + } + + # Static and volatile strings. Duplicate. + resulttype char* { + Tcl_SetObjResult(interp, Tcl_NewStringObj(rv, -1)); + return TCL_OK; + } + resulttype {const char*} { + Tcl_SetObjResult(interp, Tcl_NewStringObj(rv, -1)); + return TCL_OK; + } + resulttype vstring = char* + + # Dynamic strings, allocated via Tcl_Alloc. + # + # We are avoiding the Tcl_Obj* API here, as its use requires an + # additional duplicate of the string, churning memory and + # requiring more copying. + # Tcl_SetObjResult(interp, Tcl_NewStringObj(rv, -1)); + # Tcl_Free (rv); + resulttype string { + Tcl_SetResult (interp, rv, TCL_DYNAMIC); + return TCL_OK; + } char* + resulttype dstring = string + + resulttype Tcl_Obj* { + if (rv == NULL) { return TCL_ERROR; } + Tcl_SetObjResult(interp, rv); + Tcl_DecrRefCount(rv); + return TCL_OK; + } + resulttype object = Tcl_Obj* + + critcl::resulttype Tcl_Obj*0 { + if (rv == NULL) { return TCL_ERROR; } + Tcl_SetObjResult(interp, rv); + /* No refcount adjustment */ + return TCL_OK; + } Tcl_Obj* + resulttype object0 = Tcl_Obj*0 + + resulttype new-channel { + if (rv == NULL) { return TCL_ERROR; } + Tcl_RegisterChannel (interp, rv); + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return TCL_OK; + } Tcl_Channel + + resulttype known-channel { + if (rv == NULL) { return TCL_ERROR; } + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return TCL_OK; + } Tcl_Channel + + # Note, this is complementary to argtype `take-channel`. + resulttype return-channel { + if (rv == NULL) { return TCL_ERROR; } + Tcl_RegisterChannel (interp, rv); + Tcl_UnregisterChannel(NULL, rv); + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return TCL_OK; + } Tcl_Channel + + rename ::critcl::Initialize {} + return +} + +# # ## ### ##### ######## ############# ##################### +## State + +namespace eval ::critcl { + variable mydir ;# Path of the critcl package directory. + variable run ;# interpreter to run commands, eval when, etc + + # XXX configfile - See the *config commands, path of last config file run through 'readconfig'. + + # namespace to flag when options set + namespace eval option { + variable debug_symbols 0 + } + + # keep all variables in a sub-namespace for easy access + namespace eval v { + variable cache ;# Path. Cache directory. Platform-dependent + # (target platform). + + # ---------------------------------------------------------------- + + # (XX) To understand the set of variables below and their + # differences some terminology is required. + # + # First we have to distinguish between "target identifiers" + # and "platform identifiers". The first is the name for a + # particular set of configuration settings specifying commands + # and command line arguments to use. The second is the name of + # a machine configuration, identifying both operating system, + # and cpu architecture. + # + # The problem critcl has is that in 99% of the cases found in + # a critcl config file the "target identifier" is also a valid + # "platform identifier". Example: "linux-ix86". That does not + # make them semantically interchangable however. + # + # Especially when we add cross-compilation to the mix, where + # we have to further distinguish between the platform critcl + # itself is running on (build), and the platform for which + # critcl is generating code (target), and the last one sounds + # similar to "target identifier". + + variable targetconfig ;# Target identifier. The chosen configuration. + variable targetplatform ;# Platform identifier. Type of generated binaries. + variable buildplatform ;# Platform identifier. We run here. + + variable knowntargets {} ;# List of all target identifiers found + # in the configuration file last processed by "readconfig". + + variable xtargets ;# Cross-compile targets. This array maps from + array set xtargets {} ;# the target identifier to the actual platform + # identifier of the target platform in question. If a target identifier + # has no entry here, it is assumed to be the platform identifier itself. + # See "critcl::actualtarget". + + # ---------------------------------------------------------------- + + variable version "" ;# String. Min version number on platform + variable hdrdir ;# Path. Directory containing the helper + # files of the package. A sub- + # directory of 'mydir', see above. + variable hdrsavailable ;# List. Of Tcl versions for which we have + # Tcl header files available. For details + # see procedure 'Initialize' above. + variable prefix ;# String. The string to start all file names + # generated by the package with. See + # 'Initialize' for our choice and + # explanation of it. + variable options ;# An array containing options + # controlling the code generator. + # For more details see below. + set options(outdir) "" ;# - Path. If set the place where the generated + # shared library is saved for permanent use. + set options(keepsrc) 0 ;# - Boolean. If set all generated .c files are + # kept after compilation. Helps with debugging + # the critcl package. + set options(combine) "" ;# - XXX standalone/dynamic/static + # XXX Meaning of combine? + set options(force) 0 ;# - Boolean. If set (re)compilation is + # forced, regardless of the state of + # the cache. + set options(I) "" ;# - List. Additional include + # directories, globally specified by + # the user for mode 'generate + # package', for all components put + # into the package's library. + set options(L) "" ;# - List. Additional library search + # directories, globally specified by + # the user for mode 'generate + # package'. + set options(language) "" ;# - String. XXX + set options(tcl9) 1 ;# - Boolean. If set critcl will check C code + # fragments for 8.6/9 compatibility problems. + set options(lines) 1 ;# - Boolean. If set the generator will + # emit #line-directives to help locating + # C code in the .tcl in case of compile + # warnings and errors. + set options(trace) 0 ;# - Boolean. If set the generator will + # emit code tracing command entry + # and return, for all cprocs and + # ccommands. The latter is done by + # creating a shim function. For + # cprocs their regular shim + # function is used and modified. + # The functionality is based on + # 'critcl::cutil's 'tracer' + # command and C code. + + # XXX clientdata() per-command (See ccommand). per-file+ccommand better? + # XXX delproc() per-command (See ccommand). s.a + + # XXX toolchain() , -> data + # XXX Used only in {read,set,show}config. + # XXX Seems to be a database holding the total contents of the + # XXX config file. + + # knowntargets - See the *config commands, list of all platforms we can compile for. + + # I suspect that this came later + + # Conversion maps, Tcl types for procedure arguments and + # results to C types and code fragments for the conversion + # between the realms. Used by the helper commands + # "ArgumentCType", "ArgumentConversion", and + # "ResultConversion". These commands also supply the default + # values for unknown types. + + variable actype + array set actype {} + + variable actypeb + array set actypeb {} + + # In the code fragments below we have the following environment (placeholders, variables): + # ip - C variable, Tcl_Interp* of the interpreter providing the arguments. + # @@ - Tcl_Obj* valued expression returning the Tcl argument value. + # @A - Name of the C-level argument variable. + # + variable aconv + array set aconv {} + + # Mapping from cproc result to C result type of the function. + # This is also the C type of the helper variable holding the result. + # NOTE: 'void' is special, as it has no result, nor result variable. + variable rctype + array set rctype {} + + # In the code fragments for result conversion: + # 'rv' == variable capturing the return value of the C function. + # 'ip' == variable containing pointer to the interp to set the result into. + variable rconv + array set rconv {} + + variable storageclass {} ;# See Initialize for setup. + + variable code ;# This array collects all code snippets and + # data about them. + + # Keys for 'code' (above) and their contents: + # + # -> Per-file information, nested dictionary. Sub keys: + # + # result - Results needed for 'generate package'. + # initname - String. Foo in Foo_Init(). + # tsources - List. The companion tcl sources for . + # object - String. Name of the object file backing . + # objects - List. All object files, main and companions. + # shlib - String. Name of the shared library backing . + # base - String. Common prefix (file root) of 'object' and 'shlib'. + # clibraries - List. See config. Copy for global linkage. + # ldflags - List. See config. Copy for global linkage. + # mintcl - String. Minimum version of Tcl required by the package. + # preload - List. Names of all libraries to load before the package library. + # license - String. License text. + # <= "critcl::cresults" + # + # config - Collected code and configuration (ccode, etc.). + # tsources - List. The companion tcl sources for . + # => "critcl::tsources". + # cheaders - List. => "critcl::cheaders" + # csources - List. => "critcl::csources" + # clibraries - List. => "critcl::clibraries" + # cflags - List. => "critcl::cflags", "critcl::framework", + # "critcl::debug", "critcl::include" + # ldflags - List. => "critcl::ldflags", "critcl::framework" + # initc - String. Initialization code for Foo_Init(), "critcl::cinit" + # edecls - String. Declarations of externals needed by Foo_Init(), "critcl::cinit" + # functions - List. Collected function names. + # fragments - List. Hashes of the collected C source bodies (functions, and unnamed code). + # block - Dictionary. Maps the hashes to their C sources for fragments. + # defs - List. Hashes of the collected C source bodies (only unnamed code), for extraction of defines. + # const - Dictionary. Maps the names of defines to the namespace their variables will be in. + # uuid - List. Strings used to generate the file's uuid/hash. + # mintcl - String. Minimum version of Tcl required by the package. + # preload - List. Names of all libraries to load + # before the package library. This + # information is used only by mode + # 'generate package'. This means that + # packages with preload can't be used + # in mode 'compile & run'. + # license - String. License text. + # api_self - String. Name of our API. Defaults to package name. + # api_hdrs - List. Exported public headers of the API. + # api_ehdrs - List. Exported external public headers of the API. + # api_fun - List. Exported functions (signatures of result type, name, and arguments (C syntax)) + # meta - Dictionary. Arbitrary keys to values, the user meta-data for the package. + # package - Dictionary. Keys, see below. System meta data for the package. Values are lists. + # name - Name of current package + # version - Version of same. + # description - Long description. + # summary - Short description (one line). + # subject - Keywords and -phrases. + # as::build::date - Date-stamp for the build. + # + # --------------------------------------------------------------------- + # + # ,failed -> Per-file information: Boolean. Build status. Failed or not. + # + # 'ccode' -> Accumulated in-memory storage of code-fragments. + # Extended by 'ccode', used by 'BuildDefines', + # called by 'cbuild'. Apparently tries to extract defines + # and enums, and their values, for comparison with 'cdefine'd + # values. + # + # NOTE: are normalized absolute path names for exact + # identification of the relevant .tcl file. + + # _____________________________________________________________________ + # State used by "cbuild" ______________________________________________ + + variable log "" ;# Log channel, opened to logfile. + variable logfile "" ;# Path of logfile. Accessed by + # "Log*" and "ExecWithLogging". + variable failed 0 ;# Build status. Used by "Status*" + variable err "" ;# and "Exec*". Build error text. + + variable uuidcounter 0 ;# Counter for uuid generation in package mode. + ;# md5 is bypassed when used. + + variable buildforpackage 0 ;# Boolean flag controlling + # cbuild's behaviour. Named after + # the mode 'generate package'. + # Auto-resets to OFF after each + # call of "cbuild". Can be activated + # by "buildforpackage". + + # _____________________________________________________________________ + # State used by "BeginCommand", "EndCommand", "Emit*" _________________ + + variable curr ;# Hash of the last BeginCommand. + variable block ;# C code assembled by Emit* calls + # between Begin- and EndCommand. + + # _____________________________________________________________________ + + variable compiling 0 ;# Boolean. Indicates that a C compiler + # (gcc, native, cl) is available. + + # _____________________________________________________________________ + # config variables + variable configvars { + compile + debug_memory + debug_symbols + include + libinclude + ldoutput + embed_manifest + link + link_debug + link_preload + link_release + link_rpath + noassert + object + optimize + output + platform + preproc_define + preproc_enum + sharedlibext + strip + tclstubs + threadflags + tkstubs + version + } + } + + # namespace holding the compiler configuration (commands and + # options for the various tasks, i.e. compilation, linking, etc.). + namespace eval c { + # See sibling file 'Config' for the detailed and full + # information about the variables in use. configvars above, and + # the code below list only the variables relevant to C. Keep this + # information in sync with the contents of 'Config'. + + # compile Command to compile a C source file to an object file + # debug_memory Compiler flags to enable memory debugging + # debug_symbols Compiler flags to add symbols to resulting library + # include Compiler flag to add an include directory + # libinclude Linker flag to add a library directory + # ldoutput - ? See 'Config' + # link Command to link one or more object files and create a shared library + # embed_manifest Command to embed a manifest into a DLL. (Win-specific) + # link_debug - ? See 'Config' + # link_preload Linker flags to use when dependent libraries are pre-loaded. + # link_release - ? See 'Config' + # noassert Compiler flag to turn off assertions in Tcl code + # object File extension for object files + # optimize Compiler flag to specify optimization level + # output Compiler flag to set output file, with argument $object => Use via [subst]. + # platform Platform identification string (defaults to platform::generic) + # preproc_define Command to preprocess C source file (for critcl::cdefines) + # preproc_enum ditto + # sharedlibext The platform's file extension used for shared library files. + # strip Compiler flag to tell the linker to strip symbols + # target Presence of this key indicates that this is a cross-compile target + # tclstubs Compiler flag to set USE_TCL_STUBS + # threadflags Compiler flags to enable threaded build + # tkstubs Compiler flag to set USE_TK_STUBS + # version Command to print the compiler version number + } +} + +# # ## ### ##### ######## ############# ##################### +## Export API + +namespace eval ::critcl { + namespace export \ + at cache ccode ccommand cdata cdefines cflags cheaders \ + check cinit clibraries compiled compiling config cproc \ + csources debug done failed framework ldflags platform \ + tk tsources preload license load tcl api userconfig meta \ + source include make + # This is exported for critcl::app to pick up when generating the + # dummy commands in the runtime support of a generated package. + namespace export Ignore + catch { namespace ensemble create } +} + +# # ## ### ##### ######## ############# ##################### +## Ready + +::critcl::Initialize +return diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/cdata.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/cdata.c new file mode 100644 index 00000000..da92e52b --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/cdata.c @@ -0,0 +1,5 @@ + static char script\[$count] = { + $inittext + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, $count); + return TCL_OK; diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/header.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/header.c new file mode 100644 index 00000000..f3018d6f --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/header.c @@ -0,0 +1,6 @@ +/* Generated by critcl on [clock format [clock seconds]] + * source: $file + * binary: $libfile + */ +$api +#include "tclpre9compat.h" /* tcl.h + Portability Tcl <=8.6 */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginit.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginit.c new file mode 100644 index 00000000..e4668847 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginit.c @@ -0,0 +1,12 @@ + +#ifdef __cplusplus +extern "C" { +#endif + ${ext} +DLLEXPORT int +${ininame}_Init(Tcl_Interp *interp) +{ +#define ip interp +#if USE_TCL_STUBS + if (!MyInitTclStubs(interp)) return TCL_ERROR; +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginitend.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginitend.c new file mode 100644 index 00000000..57450a19 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginitend.c @@ -0,0 +1,6 @@ + return TCL_OK; +#undef ip +} +#ifdef __cplusplus +} +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginittk.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginittk.c new file mode 100644 index 00000000..29945cf7 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/pkginittk.c @@ -0,0 +1,5 @@ + +# line 1 "MyInitTkStubs" +#if USE_TK_STUBS + if (!MyInitTkStubs(interp)) return TCL_ERROR; +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/preload.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/preload.c new file mode 100644 index 00000000..5ebccce7 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/preload.c @@ -0,0 +1,169 @@ +/* + * pre-load a shared library + * - for situations where a Tcl package depends on another library + * - will be superceded by the functionality in TIP #239 + * - based on tclLoad.c from Tcl 8.4.13 and MyInitTclStubs from Critcl + */ + +#include "tcl.h" + +TclStubs *tclStubsPtr; +TclPlatStubs *tclPlatStubsPtr; +struct TclIntStubs *tclIntStubsPtr; +struct TclIntPlatStubs *tclIntPlatStubsPtr; + +static int +MyInitTclStubs (Tcl_Interp *ip) +{ + typedef struct { + char *result; + Tcl_FreeProc *freeProc; + int errorLine; + TclStubs *stubTable; + } HeadOfInterp; + + HeadOfInterp *hoi = (HeadOfInterp*) ip; + + if (hoi->stubTable == NULL || hoi->stubTable->magic != TCL_STUB_MAGIC) { + ip->result = "This extension requires stubs-support."; + ip->freeProc = TCL_STATIC; + return 0; + } + + tclStubsPtr = hoi->stubTable; + + if (Tcl_PkgRequire(ip, "Tcl", "8.1", 0) == NULL) { + tclStubsPtr = NULL; + return 0; + } + + if (tclStubsPtr->hooks != NULL) { + tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; + tclIntStubsPtr = tclStubsPtr->hooks->tclIntStubs; + tclIntPlatStubsPtr = tclStubsPtr->hooks->tclIntPlatStubs; + } + + return 1; +} + +#ifdef WIN32 + +#include + +typedef struct PreloadInfo { + Tcl_Obj *dir; + Tcl_LoadHandle handle; +} PreloadInfo; + +static void +removeDLLCopy(ClientData clientData) { + PreloadInfo *preload = (PreloadInfo *) clientData; + Tcl_Obj *dir = preload->dir; + Tcl_LoadHandle handle = preload->handle; + Tcl_Obj *errorPtr; + + // no idea why, but we have to call FreeLibrary twice for the subsequent + // Tcl_FSRemoveDirectory to work + FreeLibrary((HINSTANCE) handle); + FreeLibrary((HINSTANCE) handle); + + if (Tcl_FSRemoveDirectory(dir, 1, &errorPtr) != TCL_OK) { + fprintf(stderr, "error removing dir = %s\n", Tcl_GetString(errorPtr)); + } +} + +#endif + +TCL_DECLARE_MUTEX(packageMutex) + +static int +Critcl_Preload( + ClientData dummy, + Tcl_Interp *interp, + int objc, + Tcl_Obj *objv[]) +{ + int code; + Tcl_PackageInitProc *proc1, *proc2; + Tcl_LoadHandle loadHandle; + Tcl_FSUnloadFileProc *unLoadProcPtr = NULL; + Tcl_Filesystem *fsPtr; +#ifdef WIN32 + PreloadInfo *preload = NULL; +#endif + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "fileName"); + return TCL_ERROR; + } + if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) { + return TCL_ERROR; + } + +#ifdef WIN32 + // if the filesystem holding the dll doesn't support direct loading + // we need to copy it to a temporary directory and load it from there + // - The command "critcl::runtime::precopy" is defined by the support + // file "critcl/lib/app-critcl/runtime.tcl". At load time this is + // the file "critcl-rt.tcl", sibling to "pkgIndex.tcl". + + if ((fsPtr = Tcl_FSGetFileSystemForPath(objv[1])) != NULL \ + && fsPtr->loadFileProc == NULL) { + int len; + Tcl_Obj *dirs; + objv[0] = Tcl_NewStringObj("::critcl::runtime::precopy", -1); + if ((code = Tcl_EvalObjv(interp, 2, objv, 0)) != TCL_OK) { + Tcl_SetErrorCode(interp, "could not preload ", + Tcl_GetString(objv[1]), 0); + return TCL_ERROR; + } + objv[1] = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(objv[1]); + dirs = Tcl_FSSplitPath(objv[1], &len); + preload = (PreloadInfo *) ckalloc(sizeof(PreloadInfo)); + preload->dir = Tcl_FSJoinPath(dirs, --len); + Tcl_IncrRefCount(preload->dir); + } +#endif + + Tcl_MutexLock(&packageMutex); + code = Tcl_FSLoadFile(interp, objv[1], NULL, NULL, NULL, NULL, + &loadHandle, &unLoadProcPtr); + Tcl_MutexUnlock(&packageMutex); +#ifdef WIN32 + if (preload) { + preload->handle = loadHandle; + Tcl_CreateExitHandler(removeDLLCopy, (ClientData) preload); + } +#endif + return code; +} + +DLLEXPORT int +Preload_Init(Tcl_Interp *interp) +{ + if (!MyInitTclStubs(interp)) + return TCL_ERROR; + // The Tcl command can't be "preload" because the Tcl source might + // be copied into the target package (so Tcl procs are available) + // and we want critcl::runtime::preload to then be a no-op because + // the preloading is done from the loadlib command when the target + // package is loaded + Tcl_CreateObjCommand(interp, "::critcl::runtime::preload", Critcl_Preload, NULL, 0); + return 0; +} + +DLLEXPORT int +Preload_SafeInit(Tcl_Interp *interp) +{ + if (!MyInitTclStubs(interp)) + return TCL_ERROR; + Tcl_CreateObjCommand(interp, "::critcl::runtime::preload", Critcl_Preload, NULL, 0); + return 0; +} + +DLLEXPORT int +Preload_Unload(Tcl_Interp *interp) {} + +DLLEXPORT int +Preload_SafeUnload(Tcl_Interp *interp) {} diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/storageclass.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/storageclass.c new file mode 100644 index 00000000..11e44f00 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/storageclass.c @@ -0,0 +1,26 @@ +/* + * 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_@cname@ +# define TCL_STORAGE_CLASS DLLEXPORT +#else +# ifdef USE_@up@_STUBS +# define TCL_STORAGE_CLASS +# else +# define TCL_STORAGE_CLASS DLLIMPORT +# endif +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/stubs.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/stubs.c new file mode 100644 index 00000000..19084328 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/stubs.c @@ -0,0 +1,43 @@ + +#line 1 "MyInitTclStubs" + +#if USE_TCL_STUBS + $stubs + $platstubs + const struct TclIntStubs *tclIntStubsPtr; + const struct TclIntPlatStubs *tclIntPlatStubsPtr; + + static int + MyInitTclStubs (Tcl_Interp *ip) + { + typedef struct { + char *result; + Tcl_FreeProc *freeProc; + int errorLine; + TclStubs *stubTable; + } HeadOfInterp; + + HeadOfInterp *hoi = (HeadOfInterp*) ip; + + if (hoi->stubTable == NULL || hoi->stubTable->magic != TCL_STUB_MAGIC) { + hoi->result = "This extension requires stubs-support."; + hoi->freeProc = TCL_STATIC; + return 0; + } + + tclStubsPtr = hoi->stubTable; + + if (Tcl_PkgRequire(ip, "Tcl", "$mintcl", 0) == NULL) { + tclStubsPtr = NULL; + return 0; + } + + if (tclStubsPtr->hooks != NULL) { + tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; + tclIntStubsPtr = tclStubsPtr->hooks->tclIntStubs; + tclIntPlatStubsPtr = tclStubsPtr->hooks->tclIntPlatStubs; + } + + return 1; + } +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/stubs_e.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/stubs_e.c new file mode 100644 index 00000000..42c17b61 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/stubs_e.c @@ -0,0 +1,10 @@ + +#line 1 "MyInitTclStubs" + +#if USE_TCL_STUBS + static int + MyInitTclStubs (Tcl_Interp *ip) + { + return 1; + } +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/X.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/X.h new file mode 100644 index 00000000..daf22830 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/X.h @@ -0,0 +1,677 @@ +/* + * $XConsortium: X.h,v 1.66 88/09/06 15:55:56 jim Exp $ + */ + +/* Definitions for the X window system likely to be used by applications */ + +#ifndef X_H +#define X_H + +/*********************************************************** +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, Massachusetts. + + All Rights Reserved + +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 and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or MIT not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#define X_PROTOCOL 11 /* current protocol version */ +#define X_PROTOCOL_REVISION 0 /* current minor version */ + +#if defined(MAC_OSX_TK) +# define Cursor XCursor +# define Region XRegion +#endif + +/* Resources */ + +#ifdef _WIN64 +typedef __int64 XID; +#else +typedef unsigned long XID; +#endif + +typedef XID Window; +typedef XID Drawable; +typedef XID Font; +typedef XID Pixmap; +typedef XID Cursor; +typedef XID Colormap; +typedef XID GContext; +typedef XID KeySym; + +typedef unsigned long Mask; + +typedef unsigned long Atom; + +typedef unsigned long VisualID; + +typedef unsigned long Time; + +typedef unsigned long KeyCode; /* In order to use IME, the Macintosh needs + * to pack 3 bytes into the keyCode field in + * the XEvent. In the real X.h, a KeyCode is + * defined as a short, which wouldn't be big + * enough. */ + +/***************************************************************** + * RESERVED RESOURCE AND CONSTANT DEFINITIONS + *****************************************************************/ + +#define None 0L /* universal null resource or null atom */ + +#define ParentRelative 1L /* background pixmap in CreateWindow + and ChangeWindowAttributes */ + +#define CopyFromParent 0L /* border pixmap in CreateWindow + and ChangeWindowAttributes + special VisualID and special window + class passed to CreateWindow */ + +#define PointerWindow 0L /* destination window in SendEvent */ +#define InputFocus 1L /* destination window in SendEvent */ + +#define PointerRoot 1L /* focus window in SetInputFocus */ + +#define AnyPropertyType 0L /* special Atom, passed to GetProperty */ + +#define AnyKey 0L /* special Key Code, passed to GrabKey */ + +#define AnyButton 0L /* special Button Code, passed to GrabButton */ + +#define AllTemporary 0L /* special Resource ID passed to KillClient */ + +#define CurrentTime 0L /* special Time */ + +#define NoSymbol 0L /* special KeySym */ + +/***************************************************************** + * EVENT DEFINITIONS + *****************************************************************/ + +/* Input Event Masks. Used as event-mask window attribute and as arguments + to Grab requests. Not to be confused with event names. */ + +#define NoEventMask 0L +#define KeyPressMask (1L<<0) +#define KeyReleaseMask (1L<<1) +#define ButtonPressMask (1L<<2) +#define ButtonReleaseMask (1L<<3) +#define EnterWindowMask (1L<<4) +#define LeaveWindowMask (1L<<5) +#define PointerMotionMask (1L<<6) +#define PointerMotionHintMask (1L<<7) +#define Button1MotionMask (1L<<8) +#define Button2MotionMask (1L<<9) +#define Button3MotionMask (1L<<10) +#define Button4MotionMask (1L<<11) +#define Button5MotionMask (1L<<12) +#define ButtonMotionMask (1L<<13) +#define KeymapStateMask (1L<<14) +#define ExposureMask (1L<<15) +#define VisibilityChangeMask (1L<<16) +#define StructureNotifyMask (1L<<17) +#define ResizeRedirectMask (1L<<18) +#define SubstructureNotifyMask (1L<<19) +#define SubstructureRedirectMask (1L<<20) +#define FocusChangeMask (1L<<21) +#define PropertyChangeMask (1L<<22) +#define ColormapChangeMask (1L<<23) +#define OwnerGrabButtonMask (1L<<24) + +/* Event names. Used in "type" field in XEvent structures. Not to be +confused with event masks above. They start from 2 because 0 and 1 +are reserved in the protocol for errors and replies. */ + +#define KeyPress 2 +#define KeyRelease 3 +#define ButtonPress 4 +#define ButtonRelease 5 +#define MotionNotify 6 +#define EnterNotify 7 +#define LeaveNotify 8 +#define FocusIn 9 +#define FocusOut 10 +#define KeymapNotify 11 +#define Expose 12 +#define GraphicsExpose 13 +#define NoExpose 14 +#define VisibilityNotify 15 +#define CreateNotify 16 +#define DestroyNotify 17 +#define UnmapNotify 18 +#define MapNotify 19 +#define MapRequest 20 +#define ReparentNotify 21 +#define ConfigureNotify 22 +#define ConfigureRequest 23 +#define GravityNotify 24 +#define ResizeRequest 25 +#define CirculateNotify 26 +#define CirculateRequest 27 +#define PropertyNotify 28 +#define SelectionClear 29 +#define SelectionRequest 30 +#define SelectionNotify 31 +#define ColormapNotify 32 +#define ClientMessage 33 +#define MappingNotify 34 +#define LASTEvent 35 /* must be bigger than any event # */ + + +/* Key masks. Used as modifiers to GrabButton and GrabKey, results of QueryPointer, + state in various key-, mouse-, and button-related events. */ + +#define ShiftMask (1<<0) +#define LockMask (1<<1) +#define ControlMask (1<<2) +#define Mod1Mask (1<<3) +#define Mod2Mask (1<<4) +#define Mod3Mask (1<<5) +#define Mod4Mask (1<<6) +#define Mod5Mask (1<<7) + +/* modifier names. Used to build a SetModifierMapping request or + to read a GetModifierMapping request. These correspond to the + masks defined above. */ +#define ShiftMapIndex 0 +#define LockMapIndex 1 +#define ControlMapIndex 2 +#define Mod1MapIndex 3 +#define Mod2MapIndex 4 +#define Mod3MapIndex 5 +#define Mod4MapIndex 6 +#define Mod5MapIndex 7 + + +/* button masks. Used in same manner as Key masks above. Not to be confused + with button names below. */ + +#define Button1Mask (1<<8) +#define Button2Mask (1<<9) +#define Button3Mask (1<<10) +#define Button4Mask (1<<11) +#define Button5Mask (1<<12) + +#define AnyModifier (1<<15) /* used in GrabButton, GrabKey */ + + +/* button names. Used as arguments to GrabButton and as detail in ButtonPress + and ButtonRelease events. Not to be confused with button masks above. + Note that 0 is already defined above as "AnyButton". */ + +#define Button1 1 +#define Button2 2 +#define Button3 3 +#define Button4 4 +#define Button5 5 + +/* Notify modes */ + +#define NotifyNormal 0 +#define NotifyGrab 1 +#define NotifyUngrab 2 +#define NotifyWhileGrabbed 3 + +#define NotifyHint 1 /* for MotionNotify events */ + +/* Notify detail */ + +#define NotifyAncestor 0 +#define NotifyVirtual 1 +#define NotifyInferior 2 +#define NotifyNonlinear 3 +#define NotifyNonlinearVirtual 4 +#define NotifyPointer 5 +#define NotifyPointerRoot 6 +#define NotifyDetailNone 7 + +/* Visibility notify */ + +#define VisibilityUnobscured 0 +#define VisibilityPartiallyObscured 1 +#define VisibilityFullyObscured 2 + +/* Circulation request */ + +#define PlaceOnTop 0 +#define PlaceOnBottom 1 + +/* protocol families */ + +#define FamilyInternet 0 +#define FamilyDECnet 1 +#define FamilyChaos 2 + +/* Property notification */ + +#define PropertyNewValue 0 +#define PropertyDelete 1 + +/* Color Map notification */ + +#define ColormapUninstalled 0 +#define ColormapInstalled 1 + +/* GrabPointer, GrabButton, GrabKeyboard, GrabKey Modes */ + +#define GrabModeSync 0 +#define GrabModeAsync 1 + +/* GrabPointer, GrabKeyboard reply status */ + +#define GrabSuccess 0 +#define AlreadyGrabbed 1 +#define GrabInvalidTime 2 +#define GrabNotViewable 3 +#define GrabFrozen 4 + +/* AllowEvents modes */ + +#define AsyncPointer 0 +#define SyncPointer 1 +#define ReplayPointer 2 +#define AsyncKeyboard 3 +#define SyncKeyboard 4 +#define ReplayKeyboard 5 +#define AsyncBoth 6 +#define SyncBoth 7 + +/* Used in SetInputFocus, GetInputFocus */ + +#define RevertToNone (int)None +#define RevertToPointerRoot (int)PointerRoot +#define RevertToParent 2 + +/***************************************************************** + * ERROR CODES + *****************************************************************/ + +#define Success 0 /* everything's okay */ +#define BadRequest 1 /* bad request code */ +#define BadValue 2 /* int parameter out of range */ +#define BadWindow 3 /* parameter not a Window */ +#define BadPixmap 4 /* parameter not a Pixmap */ +#define BadAtom 5 /* parameter not an Atom */ +#define BadCursor 6 /* parameter not a Cursor */ +#define BadFont 7 /* parameter not a Font */ +#define BadMatch 8 /* parameter mismatch */ +#define BadDrawable 9 /* parameter not a Pixmap or Window */ +#define BadAccess 10 /* depending on context: + - key/button already grabbed + - attempt to free an illegal + cmap entry + - attempt to store into a read-only + color map entry. + - attempt to modify the access control + list from other than the local host. + */ +#define BadAlloc 11 /* insufficient resources */ +#define BadColor 12 /* no such colormap */ +#define BadGC 13 /* parameter not a GC */ +#define BadIDChoice 14 /* choice not in range or already used */ +#define BadName 15 /* font or color name doesn't exist */ +#define BadLength 16 /* Request length incorrect */ +#define BadImplementation 17 /* server is defective */ + +#define FirstExtensionError 128 +#define LastExtensionError 255 + +/***************************************************************** + * WINDOW DEFINITIONS + *****************************************************************/ + +/* Window classes used by CreateWindow */ +/* Note that CopyFromParent is already defined as 0 above */ + +#define InputOutput 1 +#define InputOnly 2 + +/* Window attributes for CreateWindow and ChangeWindowAttributes */ + +#define CWBackPixmap (1L<<0) +#define CWBackPixel (1L<<1) +#define CWBorderPixmap (1L<<2) +#define CWBorderPixel (1L<<3) +#define CWBitGravity (1L<<4) +#define CWWinGravity (1L<<5) +#define CWBackingStore (1L<<6) +#define CWBackingPlanes (1L<<7) +#define CWBackingPixel (1L<<8) +#define CWOverrideRedirect (1L<<9) +#define CWSaveUnder (1L<<10) +#define CWEventMask (1L<<11) +#define CWDontPropagate (1L<<12) +#define CWColormap (1L<<13) +#define CWCursor (1L<<14) + +/* ConfigureWindow structure */ + +#define CWX (1<<0) +#define CWY (1<<1) +#define CWWidth (1<<2) +#define CWHeight (1<<3) +#define CWBorderWidth (1<<4) +#define CWSibling (1<<5) +#define CWStackMode (1<<6) + + +/* Bit Gravity */ + +#define ForgetGravity 0 +#define NorthWestGravity 1 +#define NorthGravity 2 +#define NorthEastGravity 3 +#define WestGravity 4 +#define CenterGravity 5 +#define EastGravity 6 +#define SouthWestGravity 7 +#define SouthGravity 8 +#define SouthEastGravity 9 +#define StaticGravity 10 + +/* Window gravity + bit gravity above */ + +#define UnmapGravity 0 + +/* Used in CreateWindow for backing-store hint */ + +#define NotUseful 0 +#define WhenMapped 1 +#define Always 2 + +/* Used in GetWindowAttributes reply */ + +#define IsUnmapped 0 +#define IsUnviewable 1 +#define IsViewable 2 + +/* Used in ChangeSaveSet */ + +#define SetModeInsert 0 +#define SetModeDelete 1 + +/* Used in ChangeCloseDownMode */ + +#define DestroyAll 0 +#define RetainPermanent 1 +#define RetainTemporary 2 + +/* Window stacking method (in configureWindow) */ + +#define Above 0 +#define Below 1 +#define TopIf 2 +#define BottomIf 3 +#define Opposite 4 + +/* Circulation direction */ + +#define RaiseLowest 0 +#define LowerHighest 1 + +/* Property modes */ + +#define PropModeReplace 0 +#define PropModePrepend 1 +#define PropModeAppend 2 + +/***************************************************************** + * GRAPHICS DEFINITIONS + *****************************************************************/ + +/* graphics functions, as in GC.alu */ + +#define GXclear 0x0 /* 0 */ +#define GXand 0x1 /* src AND dst */ +#define GXandReverse 0x2 /* src AND NOT dst */ +#define GXcopy 0x3 /* src */ +#define GXandInverted 0x4 /* NOT src AND dst */ +#define GXnoop 0x5 /* dst */ +#define GXxor 0x6 /* src XOR dst */ +#define GXor 0x7 /* src OR dst */ +#define GXnor 0x8 /* NOT src AND NOT dst */ +#define GXequiv 0x9 /* NOT src XOR dst */ +#define GXinvert 0xa /* NOT dst */ +#define GXorReverse 0xb /* src OR NOT dst */ +#define GXcopyInverted 0xc /* NOT src */ +#define GXorInverted 0xd /* NOT src OR dst */ +#define GXnand 0xe /* NOT src OR NOT dst */ +#define GXset 0xf /* 1 */ + +/* LineStyle */ + +#define LineSolid 0 +#define LineOnOffDash 1 +#define LineDoubleDash 2 + +/* capStyle */ + +#define CapNotLast 0 +#define CapButt 1 +#define CapRound 2 +#define CapProjecting 3 + +/* joinStyle */ + +#define JoinMiter 0 +#define JoinRound 1 +#define JoinBevel 2 + +/* fillStyle */ + +#define FillSolid 0 +#define FillTiled 1 +#define FillStippled 2 +#define FillOpaqueStippled 3 + +/* fillRule */ + +#define EvenOddRule 0 +#define WindingRule 1 + +/* subwindow mode */ + +#define ClipByChildren 0 +#define IncludeInferiors 1 + +/* SetClipRectangles ordering */ + +#define Unsorted 0 +#define YSorted 1 +#define YXSorted 2 +#define YXBanded 3 + +/* CoordinateMode for drawing routines */ + +#define CoordModeOrigin 0 /* relative to the origin */ +#define CoordModePrevious 1 /* relative to previous point */ + +/* Polygon shapes */ + +#define Complex 0 /* paths may intersect */ +#define Nonconvex 1 /* no paths intersect, but not convex */ +#define Convex 2 /* wholly convex */ + +/* Arc modes for PolyFillArc */ + +#define ArcChord 0 /* join endpoints of arc */ +#define ArcPieSlice 1 /* join endpoints to center of arc */ + +/* GC components: masks used in CreateGC, CopyGC, ChangeGC, OR'ed into + GC.stateChanges */ + +#define GCFunction (1L<<0) +#define GCPlaneMask (1L<<1) +#define GCForeground (1L<<2) +#define GCBackground (1L<<3) +#define GCLineWidth (1L<<4) +#define GCLineStyle (1L<<5) +#define GCCapStyle (1L<<6) +#define GCJoinStyle (1L<<7) +#define GCFillStyle (1L<<8) +#define GCFillRule (1L<<9) +#define GCTile (1L<<10) +#define GCStipple (1L<<11) +#define GCTileStipXOrigin (1L<<12) +#define GCTileStipYOrigin (1L<<13) +#define GCFont (1L<<14) +#define GCSubwindowMode (1L<<15) +#define GCGraphicsExposures (1L<<16) +#define GCClipXOrigin (1L<<17) +#define GCClipYOrigin (1L<<18) +#define GCClipMask (1L<<19) +#define GCDashOffset (1L<<20) +#define GCDashList (1L<<21) +#define GCArcMode (1L<<22) + +#define GCLastBit 22 +/***************************************************************** + * FONTS + *****************************************************************/ + +/* used in QueryFont -- draw direction */ + +#define FontLeftToRight 0 +#define FontRightToLeft 1 + +#define FontChange 255 + +/***************************************************************** + * IMAGING + *****************************************************************/ + +/* ImageFormat -- PutImage, GetImage */ + +#define XYBitmap 0 /* depth 1, XYFormat */ +#define XYPixmap 1 /* depth == drawable depth */ +#define ZPixmap 2 /* depth == drawable depth */ + +/***************************************************************** + * COLOR MAP STUFF + *****************************************************************/ + +/* For CreateColormap */ + +#define AllocNone 0 /* create map with no entries */ +#define AllocAll 1 /* allocate entire map writeable */ + + +/* Flags used in StoreNamedColor, StoreColors */ + +#define DoRed (1<<0) +#define DoGreen (1<<1) +#define DoBlue (1<<2) + +/***************************************************************** + * CURSOR STUFF + *****************************************************************/ + +/* QueryBestSize Class */ + +#define CursorShape 0 /* largest size that can be displayed */ +#define TileShape 1 /* size tiled fastest */ +#define StippleShape 2 /* size stippled fastest */ + +/***************************************************************** + * KEYBOARD/POINTER STUFF + *****************************************************************/ + +#define AutoRepeatModeOff 0 +#define AutoRepeatModeOn 1 +#define AutoRepeatModeDefault 2 + +#define LedModeOff 0 +#define LedModeOn 1 + +/* masks for ChangeKeyboardControl */ + +#define KBKeyClickPercent (1L<<0) +#define KBBellPercent (1L<<1) +#define KBBellPitch (1L<<2) +#define KBBellDuration (1L<<3) +#define KBLed (1L<<4) +#define KBLedMode (1L<<5) +#define KBKey (1L<<6) +#define KBAutoRepeatMode (1L<<7) + +#define MappingSuccess 0 +#define MappingBusy 1 +#define MappingFailed 2 + +#define MappingModifier 0 +#define MappingKeyboard 1 +#define MappingPointer 2 + +/***************************************************************** + * SCREEN SAVER STUFF + *****************************************************************/ + +#define DontPreferBlanking 0 +#define PreferBlanking 1 +#define DefaultBlanking 2 + +#define DisableScreenSaver 0 +#define DisableScreenInterval 0 + +#define DontAllowExposures 0 +#define AllowExposures 1 +#define DefaultExposures 2 + +/* for ForceScreenSaver */ + +#define ScreenSaverReset 0 +#define ScreenSaverActive 1 + +/***************************************************************** + * HOSTS AND CONNECTIONS + *****************************************************************/ + +/* for ChangeHosts */ + +#define HostInsert 0 +#define HostDelete 1 + +/* for ChangeAccessControl */ + +#define EnableAccess 1 +#define DisableAccess 0 + +/* Display classes used in opening the connection + * Note that the statically allocated ones are even numbered and the + * dynamically changeable ones are odd numbered */ + +#define StaticGray 0 +#define GrayScale 1 +#define StaticColor 2 +#define PseudoColor 3 +#define TrueColor 4 +#define DirectColor 5 + + +/* Byte order used in imageByteOrder and bitmapBitOrder */ + +#define LSBFirst 0 +#define MSBFirst 1 + +#if defined(MAC_OSX_TK) +# undef Cursor +# undef Region +#endif + +#endif /* X_H */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xatom.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xatom.h new file mode 100644 index 00000000..485a4236 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xatom.h @@ -0,0 +1,79 @@ +#ifndef XATOM_H +#define XATOM_H 1 + +/* THIS IS A GENERATED FILE + * + * Do not change! Changing this file implies a protocol change! + */ + +#define XA_PRIMARY ((Atom) 1) +#define XA_SECONDARY ((Atom) 2) +#define XA_ARC ((Atom) 3) +#define XA_ATOM ((Atom) 4) +#define XA_BITMAP ((Atom) 5) +#define XA_CARDINAL ((Atom) 6) +#define XA_COLORMAP ((Atom) 7) +#define XA_CURSOR ((Atom) 8) +#define XA_CUT_BUFFER0 ((Atom) 9) +#define XA_CUT_BUFFER1 ((Atom) 10) +#define XA_CUT_BUFFER2 ((Atom) 11) +#define XA_CUT_BUFFER3 ((Atom) 12) +#define XA_CUT_BUFFER4 ((Atom) 13) +#define XA_CUT_BUFFER5 ((Atom) 14) +#define XA_CUT_BUFFER6 ((Atom) 15) +#define XA_CUT_BUFFER7 ((Atom) 16) +#define XA_DRAWABLE ((Atom) 17) +#define XA_FONT ((Atom) 18) +#define XA_INTEGER ((Atom) 19) +#define XA_PIXMAP ((Atom) 20) +#define XA_POINT ((Atom) 21) +#define XA_RECTANGLE ((Atom) 22) +#define XA_RESOURCE_MANAGER ((Atom) 23) +#define XA_RGB_COLOR_MAP ((Atom) 24) +#define XA_RGB_BEST_MAP ((Atom) 25) +#define XA_RGB_BLUE_MAP ((Atom) 26) +#define XA_RGB_DEFAULT_MAP ((Atom) 27) +#define XA_RGB_GRAY_MAP ((Atom) 28) +#define XA_RGB_GREEN_MAP ((Atom) 29) +#define XA_RGB_RED_MAP ((Atom) 30) +#define XA_STRING ((Atom) 31) +#define XA_VISUALID ((Atom) 32) +#define XA_WINDOW ((Atom) 33) +#define XA_WM_COMMAND ((Atom) 34) +#define XA_WM_HINTS ((Atom) 35) +#define XA_WM_CLIENT_MACHINE ((Atom) 36) +#define XA_WM_ICON_NAME ((Atom) 37) +#define XA_WM_ICON_SIZE ((Atom) 38) +#define XA_WM_NAME ((Atom) 39) +#define XA_WM_NORMAL_HINTS ((Atom) 40) +#define XA_WM_SIZE_HINTS ((Atom) 41) +#define XA_WM_ZOOM_HINTS ((Atom) 42) +#define XA_MIN_SPACE ((Atom) 43) +#define XA_NORM_SPACE ((Atom) 44) +#define XA_MAX_SPACE ((Atom) 45) +#define XA_END_SPACE ((Atom) 46) +#define XA_SUPERSCRIPT_X ((Atom) 47) +#define XA_SUPERSCRIPT_Y ((Atom) 48) +#define XA_SUBSCRIPT_X ((Atom) 49) +#define XA_SUBSCRIPT_Y ((Atom) 50) +#define XA_UNDERLINE_POSITION ((Atom) 51) +#define XA_UNDERLINE_THICKNESS ((Atom) 52) +#define XA_STRIKEOUT_ASCENT ((Atom) 53) +#define XA_STRIKEOUT_DESCENT ((Atom) 54) +#define XA_ITALIC_ANGLE ((Atom) 55) +#define XA_X_HEIGHT ((Atom) 56) +#define XA_QUAD_WIDTH ((Atom) 57) +#define XA_WEIGHT ((Atom) 58) +#define XA_POINT_SIZE ((Atom) 59) +#define XA_RESOLUTION ((Atom) 60) +#define XA_COPYRIGHT ((Atom) 61) +#define XA_NOTICE ((Atom) 62) +#define XA_FONT_NAME ((Atom) 63) +#define XA_FAMILY_NAME ((Atom) 64) +#define XA_FULL_NAME ((Atom) 65) +#define XA_CAP_HEIGHT ((Atom) 66) +#define XA_WM_CLASS ((Atom) 67) +#define XA_WM_TRANSIENT_FOR ((Atom) 68) + +#define XA_LAST_PREDEFINED ((Atom) 68) +#endif /* XATOM_H */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xfuncproto.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xfuncproto.h new file mode 100644 index 00000000..6d63002e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xfuncproto.h @@ -0,0 +1,60 @@ +/* $XConsortium: Xfuncproto.h,v 1.7 91/05/13 20:49:21 rws Exp $ */ +/* + * Copyright 1989, 1991 by the Massachusetts Institute of Technology + * + * 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 and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + */ + +/* Definitions to make function prototypes manageable */ + +#ifndef _XFUNCPROTO_H_ +#define _XFUNCPROTO_H_ + +#ifndef NeedFunctionPrototypes +#define NeedFunctionPrototypes 1 +#endif /* NeedFunctionPrototypes */ + +#ifndef NeedVarargsPrototypes +#define NeedVarargsPrototypes 0 +#endif /* NeedVarargsPrototypes */ + +#if NeedFunctionPrototypes + +#ifndef NeedNestedPrototypes +#define NeedNestedPrototypes 1 +#endif /* NeedNestedPrototypes */ + +#ifndef _Xconst +#define _Xconst const +#endif /* _Xconst */ + +#ifndef NeedWidePrototypes +#ifdef NARROWPROTO +#define NeedWidePrototypes 0 +#else +#define NeedWidePrototypes 1 /* default to make interropt. easier */ +#endif +#endif /* NeedWidePrototypes */ + +#endif /* NeedFunctionPrototypes */ + +#ifdef __cplusplus +#define _XFUNCPROTOBEGIN extern "C" { +#define _XFUNCPROTOEND } +#endif + +#ifndef _XFUNCPROTOBEGIN +#define _XFUNCPROTOBEGIN +#define _XFUNCPROTOEND +#endif /* _XFUNCPROTOBEGIN */ + +#endif /* _XFUNCPROTO_H_ */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xlib.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xlib.h new file mode 100644 index 00000000..667bdc77 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xlib.h @@ -0,0 +1,1205 @@ +/* $XConsortium: Xlib.h,v 11.221 93/07/02 14:13:28 gildea Exp $ */ +/* + * Copyright 1985, 1986, 1987, 1991 by the Massachusetts Institute of Technology + * + * 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 and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * X Window System is a Trademark of MIT. + * + */ + + +/* + * Xlib.h - Header definition and support file for the C subroutine + * interface library (Xlib) to the X Window System Protocol (V11). + * Structures and symbols starting with "_" are private to the library. + */ +#ifndef _XLIB_H_ +#define _XLIB_H_ + +#define XlibSpecificationRelease 5 + +#if !defined(MAC_OSX_TK) +# include +#endif +#ifdef MAC_OSX_TK +# include +# define Cursor XCursor +# define Region XRegion +#endif + +/* applications should not depend on these two headers being included! */ +#include + +#ifndef X_WCHAR +#ifdef X_NOT_STDC_ENV +#define X_WCHAR +#endif +#endif + +#ifndef X_WCHAR +#include +#else +/* replace this with #include or typedef appropriate for your system */ +typedef unsigned long wchar_t; +#endif + +typedef char *XPointer; + +#define Bool int +#if defined(MAC_OSX_TK) +/* Use define rather than typedef, since may need to undefine this later */ +#define Status int +#else +typedef int Status; +#endif +#define True 1 +#define False 0 + +#define QueuedAlready 0 +#define QueuedAfterReading 1 +#define QueuedAfterFlush 2 + +#define ConnectionNumber(dpy) ((dpy)->fd) +#define RootWindow(dpy, scr) (((dpy)->screens[(scr)]).root) +#define DefaultScreen(dpy) ((dpy)->default_screen) +#define DefaultRootWindow(dpy) (((dpy)->screens[(dpy)->default_screen]).root) +#define DefaultVisual(dpy, scr) (((dpy)->screens[(scr)]).root_visual) +#define DefaultGC(dpy, scr) (((dpy)->screens[(scr)]).default_gc) +#define BlackPixel(dpy, scr) (((dpy)->screens[(scr)]).black_pixel) +#define WhitePixel(dpy, scr) (((dpy)->screens[(scr)]).white_pixel) +#define AllPlanes ((unsigned long)~0L) +#define QLength(dpy) ((dpy)->qlen) +#define DisplayWidth(dpy, scr) (((dpy)->screens[(scr)]).width) +#define DisplayHeight(dpy, scr) (((dpy)->screens[(scr)]).height) +#define DisplayWidthMM(dpy, scr)(((dpy)->screens[(scr)]).mwidth) +#define DisplayHeightMM(dpy, scr)(((dpy)->screens[(scr)]).mheight) +#define DisplayPlanes(dpy, scr) (((dpy)->screens[(scr)]).root_depth) +#define DisplayCells(dpy, scr) (DefaultVisual((dpy), (scr))->map_entries) +#define ScreenCount(dpy) ((dpy)->nscreens) +#define ServerVendor(dpy) ((dpy)->vendor) +#define ProtocolVersion(dpy) ((dpy)->proto_major_version) +#define ProtocolRevision(dpy) ((dpy)->proto_minor_version) +#define VendorRelease(dpy) ((dpy)->release) +#define DisplayString(dpy) ((dpy)->display_name) +#define DefaultDepth(dpy, scr) (((dpy)->screens[(scr)]).root_depth) +#define DefaultColormap(dpy, scr)(((dpy)->screens[(scr)]).cmap) +#define BitmapUnit(dpy) ((dpy)->bitmap_unit) +#define BitmapBitOrder(dpy) ((dpy)->bitmap_bit_order) +#define BitmapPad(dpy) ((dpy)->bitmap_pad) +#define ImageByteOrder(dpy) ((dpy)->byte_order) +#define NextRequest(dpy) ((dpy)->request + 1) +#define LastKnownRequestProcessed(dpy) ((dpy)->request) + +/* macros for screen oriented applications (toolkit) */ +#define ScreenOfDisplay(dpy, scr)(&((dpy)->screens[(scr)])) +#define DefaultScreenOfDisplay(dpy) (&((dpy)->screens[(dpy)->default_screen])) +#define DisplayOfScreen(s) ((s)->display) +#define RootWindowOfScreen(s) ((s)->root) +#define BlackPixelOfScreen(s) ((s)->black_pixel) +#define WhitePixelOfScreen(s) ((s)->white_pixel) +#define DefaultColormapOfScreen(s)((s)->cmap) +#define DefaultDepthOfScreen(s) ((s)->root_depth) +#define DefaultGCOfScreen(s) ((s)->default_gc) +#define DefaultVisualOfScreen(s)((s)->root_visual) +#define WidthOfScreen(s) ((s)->width) +#define HeightOfScreen(s) ((s)->height) +#define WidthMMOfScreen(s) ((s)->mwidth) +#define HeightMMOfScreen(s) ((s)->mheight) +#define PlanesOfScreen(s) ((s)->root_depth) +#define CellsOfScreen(s) (DefaultVisualOfScreen((s))->map_entries) +#define MinCmapsOfScreen(s) ((s)->min_maps) +#define MaxCmapsOfScreen(s) ((s)->max_maps) +#define DoesSaveUnders(s) ((s)->save_unders) +#define DoesBackingStore(s) ((s)->backing_store) +#define EventMaskOfScreen(s) ((s)->root_input_mask) + +/* + * Extensions need a way to hang private data on some structures. + */ +typedef struct _XExtData { + int number; /* number returned by XRegisterExtension */ + struct _XExtData *next; /* next item on list of data for structure */ + int (*free_private)(); /* called to free private storage */ + XPointer private_data; /* data private to this extension. */ +} XExtData; + +/* + * This file contains structures used by the extension mechanism. + */ +typedef struct { /* public to extension, cannot be changed */ + int extension; /* extension number */ + int major_opcode; /* major op-code assigned by server */ + int first_event; /* first event number for the extension */ + int first_error; /* first error number for the extension */ +} XExtCodes; + +/* + * Data structure for retrieving info about pixmap formats. + */ + +typedef struct { + int depth; + int bits_per_pixel; + int scanline_pad; +} XPixmapFormatValues; + + +/* + * Data structure for setting graphics context. + */ +typedef struct { + int function; /* logical operation */ + unsigned long plane_mask;/* plane mask */ + unsigned long foreground;/* foreground pixel */ + unsigned long background;/* background pixel */ + int line_width; /* line width */ + int line_style; /* LineSolid, LineOnOffDash, LineDoubleDash */ + int cap_style; /* CapNotLast, CapButt, + CapRound, CapProjecting */ + int join_style; /* JoinMiter, JoinRound, JoinBevel */ + int fill_style; /* FillSolid, FillTiled, + FillStippled, FillOpaeueStippled */ + int fill_rule; /* EvenOddRule, WindingRule */ + int arc_mode; /* ArcChord, ArcPieSlice */ + Pixmap tile; /* tile pixmap for tiling operations */ + Pixmap stipple; /* stipple 1 plane pixmap for stipping */ + int ts_x_origin; /* offset for tile or stipple operations */ + int ts_y_origin; + Font font; /* default text font for text operations */ + int subwindow_mode; /* ClipByChildren, IncludeInferiors */ + Bool graphics_exposures;/* boolean, should exposures be generated */ + int clip_x_origin; /* origin for clipping */ + int clip_y_origin; + Pixmap clip_mask; /* bitmap clipping; other calls for rects */ + int dash_offset; /* patterned/dashed line information */ + char dashes; +} XGCValues; + +/* + * Graphics context. The contents of this structure are implementation + * dependent. A GC should be treated as opaque by application code. + */ + +typedef XGCValues *GC; + +/* + * Visual structure; contains information about colormapping possible. + */ +typedef struct { + XExtData *ext_data; /* hook for extension to hang data */ + VisualID visualid; /* visual id of this visual */ +#if defined(__cplusplus) || defined(c_plusplus) + int c_class; /* C++ class of screen (monochrome, etc.) */ +#else + int class; /* class of screen (monochrome, etc.) */ +#endif + unsigned long red_mask, green_mask, blue_mask; /* mask values */ + int bits_per_rgb; /* log base 2 of distinct color values */ + int map_entries; /* color map entries */ +} Visual; + +/* + * Depth structure; contains information for each possible depth. + */ +typedef struct { + int depth; /* this depth (Z) of the depth */ + int nvisuals; /* number of Visual types at this depth */ + Visual *visuals; /* list of visuals possible at this depth */ +} Depth; + +/* + * Information about the screen. The contents of this structure are + * implementation dependent. A Screen should be treated as opaque + * by application code. + */ +typedef struct { + XExtData *ext_data; /* hook for extension to hang data */ + struct _XDisplay *display;/* back pointer to display structure */ + Window root; /* Root window id. */ + int width, height; /* width and height of screen */ + int mwidth, mheight; /* width and height of in millimeters */ + int ndepths; /* number of depths possible */ + Depth *depths; /* list of allowable depths on the screen */ + int root_depth; /* bits per pixel */ + Visual *root_visual; /* root visual */ + GC default_gc; /* GC for the root root visual */ + Colormap cmap; /* default color map */ + unsigned long white_pixel; + unsigned long black_pixel; /* White and Black pixel values */ + int max_maps, min_maps; /* max and min color maps */ + int backing_store; /* Never, WhenMapped, Always */ + Bool save_unders; + long root_input_mask; /* initial root input mask */ +} Screen; + +/* + * Format structure; describes ZFormat data the screen will understand. + */ +typedef struct { + XExtData *ext_data; /* hook for extension to hang data */ + int depth; /* depth of this image format */ + int bits_per_pixel; /* bits/pixel at this depth */ + int scanline_pad; /* scanline must padded to this multiple */ +} ScreenFormat; + +/* + * Data structure for setting window attributes. + */ +typedef struct { + Pixmap background_pixmap; /* background or None or ParentRelative */ + unsigned long background_pixel; /* background pixel */ + Pixmap border_pixmap; /* border of the window */ + unsigned long border_pixel; /* border pixel value */ + int bit_gravity; /* one of bit gravity values */ + int win_gravity; /* one of the window gravity values */ + int backing_store; /* NotUseful, WhenMapped, Always */ + unsigned long backing_planes;/* planes to be preseved if possible */ + unsigned long backing_pixel;/* value to use in restoring planes */ + Bool save_under; /* should bits under be saved? (popups) */ + long event_mask; /* set of events that should be saved */ + long do_not_propagate_mask; /* set of events that should not propagate */ + Bool override_redirect; /* boolean value for override-redirect */ + Colormap colormap; /* color map to be associated with window */ + Cursor cursor; /* cursor to be displayed (or None) */ +} XSetWindowAttributes; + +typedef struct { + int x, y; /* location of window */ + int width, height; /* width and height of window */ + int border_width; /* border width of window */ + int depth; /* depth of window */ + Visual *visual; /* the associated visual structure */ + Window root; /* root of screen containing window */ +#if defined(__cplusplus) || defined(c_plusplus) + int c_class; /* C++ InputOutput, InputOnly*/ +#else + int class; /* InputOutput, InputOnly*/ +#endif + int bit_gravity; /* one of bit gravity values */ + int win_gravity; /* one of the window gravity values */ + int backing_store; /* NotUseful, WhenMapped, Always */ + unsigned long backing_planes;/* planes to be preserved if possible */ + unsigned long backing_pixel;/* value to be used when restoring planes */ + Bool save_under; /* boolean, should bits under be saved? */ + Colormap colormap; /* color map to be associated with window */ + Bool map_installed; /* boolean, is color map currently installed*/ + int map_state; /* IsUnmapped, IsUnviewable, IsViewable */ + long all_event_masks; /* set of events all people have interest in*/ + long your_event_mask; /* my event mask */ + long do_not_propagate_mask; /* set of events that should not propagate */ + Bool override_redirect; /* boolean value for override-redirect */ + Screen *screen; /* back pointer to correct screen */ +} XWindowAttributes; + +/* + * Data structure for host setting; getting routines. + * + */ + +typedef struct { + int family; /* for example FamilyInternet */ + int length; /* length of address, in bytes */ + char *address; /* pointer to where to find the bytes */ +} XHostAddress; + +/* + * Data structure for "image" data, used by image manipulation routines. + */ +typedef struct _XImage { + int width, height; /* size of image */ + int xoffset; /* number of pixels offset in X direction */ + int format; /* XYBitmap, XYPixmap, ZPixmap */ + char *data; /* pointer to image data */ + int byte_order; /* data byte order, LSBFirst, MSBFirst */ + int bitmap_unit; /* quant. of scanline 8, 16, 32 */ + int bitmap_bit_order; /* LSBFirst, MSBFirst */ + int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */ + int depth; /* depth of image */ + int bytes_per_line; /* accelarator to next line */ + int bits_per_pixel; /* bits per pixel (ZPixmap) */ + unsigned long red_mask; /* bits in z arrangment */ + unsigned long green_mask; + unsigned long blue_mask; + XPointer obdata; /* hook for the object routines to hang on */ + struct funcs { /* image manipulation routines */ + struct _XImage *(*create_image)(); +#if NeedFunctionPrototypes + int (*destroy_image) (struct _XImage *); + unsigned long (*get_pixel) (struct _XImage *, int, int); + int (*put_pixel) (struct _XImage *, int, int, unsigned long); + struct _XImage *(*sub_image)(struct _XImage *, int, int, unsigned int, unsigned int); + int (*add_pixel) (struct _XImage *, long); +#else + int (*destroy_image)(); + unsigned long (*get_pixel)(); + int (*put_pixel)(); + struct _XImage *(*sub_image)(); + int (*add_pixel)(); +#endif + } f; +} XImage; + +/* + * Data structure for XReconfigureWindow + */ +typedef struct { + int x, y; + int width, height; + int border_width; + Window sibling; + int stack_mode; +} XWindowChanges; + +/* + * Data structure used by color operations + */ +typedef struct { + unsigned long pixel; + unsigned short red, green, blue; + char flags; /* do_red, do_green, do_blue */ + char pad; +} XColor; + +/* + * Data structures for graphics operations. On most machines, these are + * congruent with the wire protocol structures, so reformatting the data + * can be avoided on these architectures. + */ +typedef struct { + short x1, y1, x2, y2; +} XSegment; + +typedef struct { + short x, y; +} XPoint; + +typedef struct { + short x, y; + unsigned short width, height; +} XRectangle; + +typedef struct { + short x, y; + unsigned short width, height; + short angle1, angle2; +} XArc; + + +/* Data structure for XChangeKeyboardControl */ + +typedef struct { + int key_click_percent; + int bell_percent; + int bell_pitch; + int bell_duration; + int led; + int led_mode; + int key; + int auto_repeat_mode; /* On, Off, Default */ +} XKeyboardControl; + +/* Data structure for XGetKeyboardControl */ + +typedef struct { + int key_click_percent; + int bell_percent; + unsigned int bell_pitch, bell_duration; + unsigned long led_mask; + int global_auto_repeat; + char auto_repeats[32]; +} XKeyboardState; + +/* Data structure for XGetMotionEvents. */ + +typedef struct { + Time time; + short x, y; +} XTimeCoord; + +/* Data structure for X{Set,Get}ModifierMapping */ + +typedef struct { + int max_keypermod; /* The server's max # of keys per modifier */ + KeyCode *modifiermap; /* An 8 by max_keypermod array of modifiers */ +} XModifierKeymap; + + +/* + * Display datatype maintaining display specific data. + * The contents of this structure are implementation dependent. + * A Display should be treated as opaque by application code. + */ +typedef struct _XDisplay { + XExtData *ext_data; /* hook for extension to hang data */ + struct _XFreeFuncs *free_funcs; /* internal free functions */ + int fd; /* Network socket. */ + int conn_checker; /* ugly thing used by _XEventsQueued */ + int proto_major_version;/* maj. version of server's X protocol */ + int proto_minor_version;/* minor version of servers X protocol */ + char *vendor; /* vendor of the server hardware */ + XID resource_base; /* resource ID base */ + XID resource_mask; /* resource ID mask bits */ + XID resource_id; /* allocator current ID */ + int resource_shift; /* allocator shift to correct bits */ + XID (*resource_alloc)(); /* allocator function */ + int byte_order; /* screen byte order, LSBFirst, MSBFirst */ + int bitmap_unit; /* padding and data requirements */ + int bitmap_pad; /* padding requirements on bitmaps */ + int bitmap_bit_order; /* LeastSignificant or MostSignificant */ + int nformats; /* number of pixmap formats in list */ + ScreenFormat *pixmap_format; /* pixmap format list */ + int vnumber; /* Xlib's X protocol version number. */ + int release; /* release of the server */ + struct _XSQEvent *head, *tail; /* Input event queue. */ + int qlen; /* Length of input event queue */ + unsigned long request; /* sequence number of last request. */ + char *last_req; /* beginning of last request, or dummy */ + char *buffer; /* Output buffer starting address. */ + char *bufptr; /* Output buffer index pointer. */ + char *bufmax; /* Output buffer maximum+1 address. */ + unsigned max_request_size; /* maximum number 32 bit words in request*/ + struct _XrmHashBucketRec *db; + int (*synchandler)(); /* Synchronization handler */ + char *display_name; /* "host:display" string used on this connect*/ + int default_screen; /* default screen for operations */ + int nscreens; /* number of screens on this server*/ + Screen *screens; /* pointer to list of screens */ + unsigned long motion_buffer; /* size of motion buffer */ + unsigned long flags; /* internal connection flags */ + int min_keycode; /* minimum defined keycode */ + int max_keycode; /* maximum defined keycode */ + KeySym *keysyms; /* This server's keysyms */ + XModifierKeymap *modifiermap; /* This server's modifier keymap */ + int keysyms_per_keycode;/* number of rows */ + char *xdefaults; /* contents of defaults from server */ + char *scratch_buffer; /* place to hang scratch buffer */ + unsigned long scratch_length; /* length of scratch buffer */ + int ext_number; /* extension number on this display */ + struct _XExten *ext_procs; /* extensions initialized on this display */ + /* + * the following can be fixed size, as the protocol defines how + * much address space is available. + * While this could be done using the extension vector, there + * may be MANY events processed, so a search through the extension + * list to find the right procedure for each event might be + * expensive if many extensions are being used. + */ + Bool (*event_vec[128])(); /* vector for wire to event */ + Status (*wire_vec[128])(); /* vector for event to wire */ + KeySym lock_meaning; /* for XLookupString */ + struct _XLockInfo *lock; /* multi-thread state, display lock */ + struct _XInternalAsync *async_handlers; /* for internal async */ + unsigned long bigreq_size; /* max size of big requests */ + struct _XLockPtrs *lock_fns; /* pointers to threads functions */ + /* things above this line should not move, for binary compatibility */ + struct _XKeytrans *key_bindings; /* for XLookupString */ + Font cursor_font; /* for XCreateFontCursor */ + struct _XDisplayAtoms *atoms; /* for XInternAtom */ + unsigned int mode_switch; /* keyboard group modifiers */ + struct _XContextDB *context_db; /* context database */ + Bool (**error_vec)(); /* vector for wire to error */ + /* + * Xcms information + */ + struct { + XPointer defaultCCCs; /* pointer to an array of default XcmsCCC */ + XPointer clientCmaps; /* pointer to linked list of XcmsCmapRec */ + XPointer perVisualIntensityMaps; + /* linked list of XcmsIntensityMap */ + } cms; + struct _XIMFilter *im_filters; + struct _XSQEvent *qfree; /* unallocated event queue elements */ + unsigned long next_event_serial_num; /* inserted into next queue elt */ + int (*savedsynchandler)(); /* user synchandler when Xlib usurps */ +} Display; + +#if NeedFunctionPrototypes /* prototypes require event type definitions */ +#undef _XEVENT_ +#endif +#ifndef _XEVENT_ + +#define XMaxTransChars 4 + +/* + * Definitions of specific events. + */ +typedef struct { + int type; /* of event */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* "event" window it is reported relative to */ + Window root; /* root window that the event occured on */ + Window subwindow; /* child window */ + Time time; /* milliseconds */ + int x, y; /* pointer x, y coordinates in event window */ + int x_root, y_root; /* coordinates relative to root */ + unsigned int state; /* key or button mask */ + unsigned int keycode; /* detail */ + Bool same_screen; /* same screen flag */ + char trans_chars[XMaxTransChars]; + /* translated characters */ + int nbytes; +} XKeyEvent; +typedef XKeyEvent XKeyPressedEvent; +typedef XKeyEvent XKeyReleasedEvent; + +typedef struct { + int type; /* of event */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* "event" window it is reported relative to */ + Window root; /* root window that the event occured on */ + Window subwindow; /* child window */ + Time time; /* milliseconds */ + int x, y; /* pointer x, y coordinates in event window */ + int x_root, y_root; /* coordinates relative to root */ + unsigned int state; /* key or button mask */ + unsigned int button; /* detail */ + Bool same_screen; /* same screen flag */ +} XButtonEvent; +typedef XButtonEvent XButtonPressedEvent; +typedef XButtonEvent XButtonReleasedEvent; + +typedef struct { + int type; /* of event */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* "event" window reported relative to */ + Window root; /* root window that the event occured on */ + Window subwindow; /* child window */ + Time time; /* milliseconds */ + int x, y; /* pointer x, y coordinates in event window */ + int x_root, y_root; /* coordinates relative to root */ + unsigned int state; /* key or button mask */ + char is_hint; /* detail */ + Bool same_screen; /* same screen flag */ +} XMotionEvent; +typedef XMotionEvent XPointerMovedEvent; + +typedef struct { + int type; /* of event */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* "event" window reported relative to */ + Window root; /* root window that the event occured on */ + Window subwindow; /* child window */ + Time time; /* milliseconds */ + int x, y; /* pointer x, y coordinates in event window */ + int x_root, y_root; /* coordinates relative to root */ + int mode; /* NotifyNormal, NotifyGrab, NotifyUngrab */ + int detail; + /* + * NotifyAncestor, NotifyVirtual, NotifyInferior, + * NotifyNonlinear,NotifyNonlinearVirtual + */ + Bool same_screen; /* same screen flag */ + Bool focus; /* boolean focus */ + unsigned int state; /* key or button mask */ +} XCrossingEvent; +typedef XCrossingEvent XEnterWindowEvent; +typedef XCrossingEvent XLeaveWindowEvent; + +typedef struct { + int type; /* FocusIn or FocusOut */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* window of event */ + int mode; /* NotifyNormal, NotifyGrab, NotifyUngrab */ + int detail; + /* + * NotifyAncestor, NotifyVirtual, NotifyInferior, + * NotifyNonlinear,NotifyNonlinearVirtual, NotifyPointer, + * NotifyPointerRoot, NotifyDetailNone + */ +} XFocusChangeEvent; +typedef XFocusChangeEvent XFocusInEvent; +typedef XFocusChangeEvent XFocusOutEvent; + +/* generated on EnterWindow and FocusIn when KeyMapState selected */ +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + char key_vector[32]; +} XKeymapEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + int x, y; + int width, height; + int count; /* if non-zero, at least this many more */ +} XExposeEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Drawable drawable; + int x, y; + int width, height; + int count; /* if non-zero, at least this many more */ + int major_code; /* core is CopyArea or CopyPlane */ + int minor_code; /* not defined in the core */ +} XGraphicsExposeEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Drawable drawable; + int major_code; /* core is CopyArea or CopyPlane */ + int minor_code; /* not defined in the core */ +} XNoExposeEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + int state; /* Visibility state */ +} XVisibilityEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window parent; /* parent of the window */ + Window window; /* window id of window created */ + int x, y; /* window location */ + int width, height; /* size of window */ + int border_width; /* border width */ + Bool override_redirect; /* creation should be overridden */ +} XCreateWindowEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; +} XDestroyWindowEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; + Bool from_configure; +} XUnmapEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; + Bool override_redirect; /* boolean, is override set... */ +} XMapEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window parent; + Window window; +} XMapRequestEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; + Window parent; + int x, y; + Bool override_redirect; +} XReparentEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; + int x, y; + int width, height; + int border_width; + Window above; + Bool override_redirect; +} XConfigureEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; + int x, y; +} XGravityEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + int width, height; +} XResizeRequestEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window parent; + Window window; + int x, y; + int width, height; + int border_width; + Window above; + int detail; /* Above, Below, TopIf, BottomIf, Opposite */ + unsigned long value_mask; +} XConfigureRequestEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window event; + Window window; + int place; /* PlaceOnTop, PlaceOnBottom */ +} XCirculateEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window parent; + Window window; + int place; /* PlaceOnTop, PlaceOnBottom */ +} XCirculateRequestEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + Atom atom; + Time time; + int state; /* NewValue, Deleted */ +} XPropertyEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + Atom selection; + Time time; +} XSelectionClearEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window owner; + Window requestor; + Atom selection; + Atom target; + Atom property; + Time time; +} XSelectionRequestEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window requestor; + Atom selection; + Atom target; + Atom property; /* ATOM or None */ + Time time; +} XSelectionEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + Colormap colormap; /* COLORMAP or None */ +#if defined(__cplusplus) || defined(c_plusplus) + Bool c_new; /* C++ */ +#else + Bool new; +#endif + int state; /* ColormapInstalled, ColormapUninstalled */ +} XColormapEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; + Atom message_type; + int format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +} XClientMessageEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* unused */ + int request; /* one of MappingModifier, MappingKeyboard, + MappingPointer */ + int first_keycode; /* first keycode */ + int count; /* defines range of change w. first_keycode*/ +} XMappingEvent; + +typedef struct { + int type; + Display *display; /* Display the event was read from */ + XID resourceid; /* resource id */ + unsigned long serial; /* serial number of failed request */ + unsigned char error_code; /* error code of failed request */ + unsigned char request_code; /* Major op-code of failed request */ + unsigned char minor_code; /* Minor op-code of failed request */ +} XErrorEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display;/* Display the event was read from */ + Window window; /* window on which event was requested in event mask */ +} XAnyEvent; + +/* + * this union is defined so Xlib can always use the same sized + * event structure internally, to avoid memory fragmentation. + */ +typedef union _XEvent { + int type; /* must not be changed; first element */ + XAnyEvent xany; + XKeyEvent xkey; + XButtonEvent xbutton; + XMotionEvent xmotion; + XCrossingEvent xcrossing; + XFocusChangeEvent xfocus; + XExposeEvent xexpose; + XGraphicsExposeEvent xgraphicsexpose; + XNoExposeEvent xnoexpose; + XVisibilityEvent xvisibility; + XCreateWindowEvent xcreatewindow; + XDestroyWindowEvent xdestroywindow; + XUnmapEvent xunmap; + XMapEvent xmap; + XMapRequestEvent xmaprequest; + XReparentEvent xreparent; + XConfigureEvent xconfigure; + XGravityEvent xgravity; + XResizeRequestEvent xresizerequest; + XConfigureRequestEvent xconfigurerequest; + XCirculateEvent xcirculate; + XCirculateRequestEvent xcirculaterequest; + XPropertyEvent xproperty; + XSelectionClearEvent xselectionclear; + XSelectionRequestEvent xselectionrequest; + XSelectionEvent xselection; + XColormapEvent xcolormap; + XClientMessageEvent xclient; + XMappingEvent xmapping; + XErrorEvent xerror; + XKeymapEvent xkeymap; + long pad[24]; +} XEvent; +#endif + +#define XAllocID(dpy) ((*(dpy)->resource_alloc)((dpy))) + +/* + * per character font metric information. + */ +typedef struct { + short lbearing; /* origin to left edge of raster */ + short rbearing; /* origin to right edge of raster */ + short width; /* advance to next char's origin */ + short ascent; /* baseline to top edge of raster */ + short descent; /* baseline to bottom edge of raster */ + unsigned short attributes; /* per char flags (not predefined) */ +} XCharStruct; + +/* + * To allow arbitrary information with fonts, there are additional properties + * returned. + */ +typedef struct { + Atom name; + unsigned long card32; +} XFontProp; + +typedef struct { + XExtData *ext_data; /* hook for extension to hang data */ + Font fid; /* Font id for this font */ + unsigned direction; /* hint about direction the font is painted */ + unsigned min_char_or_byte2;/* first character */ + unsigned max_char_or_byte2;/* last character */ + unsigned min_byte1; /* first row that exists */ + unsigned max_byte1; /* last row that exists */ + Bool all_chars_exist;/* flag if all characters have non-zero size*/ + unsigned default_char; /* char to print for undefined character */ + int n_properties; /* how many properties there are */ + XFontProp *properties; /* pointer to array of additional properties*/ + XCharStruct min_bounds; /* minimum bounds over all existing char*/ + XCharStruct max_bounds; /* maximum bounds over all existing char*/ + XCharStruct *per_char; /* first_char to last_char information */ + int ascent; /* log. extent above baseline for spacing */ + int descent; /* log. descent below baseline for spacing */ +} XFontStruct; + +/* + * PolyText routines take these as arguments. + */ +typedef struct { + char *chars; /* pointer to string */ + int nchars; /* number of characters */ + int delta; /* delta between strings */ + Font font; /* font to print it in, None don't change */ +} XTextItem; + +typedef struct { /* normal 16 bit characters are two bytes */ + unsigned char byte1; + unsigned char byte2; +} XChar2b; + +typedef struct { + XChar2b *chars; /* two byte characters */ + int nchars; /* number of characters */ + int delta; /* delta between strings */ + Font font; /* font to print it in, None don't change */ +} XTextItem16; + + +typedef union { Display *display; + GC gc; + Visual *visual; + Screen *screen; + ScreenFormat *pixmap_format; + XFontStruct *font; } XEDataObject; + +typedef struct { + XRectangle max_ink_extent; + XRectangle max_logical_extent; +} XFontSetExtents; + +typedef struct _XFontSet *XFontSet; + +typedef struct { + char *chars; + int nchars; + int delta; + XFontSet font_set; +} XmbTextItem; + +typedef struct { + wchar_t *chars; + int nchars; + int delta; + XFontSet font_set; +} XwcTextItem; + +typedef void (*XIMProc)(); + +typedef struct _XIM *XIM; +typedef struct _XIC *XIC; + +typedef unsigned long XIMStyle; + +typedef struct { + unsigned short count_styles; + XIMStyle *supported_styles; +} XIMStyles; + +#define XIMPreeditArea 0x0001L +#define XIMPreeditCallbacks 0x0002L +#define XIMPreeditPosition 0x0004L +#define XIMPreeditNothing 0x0008L +#define XIMPreeditNone 0x0010L +#define XIMStatusArea 0x0100L +#define XIMStatusCallbacks 0x0200L +#define XIMStatusNothing 0x0400L +#define XIMStatusNone 0x0800L + +#define XNVaNestedList "XNVaNestedList" +#define XNClientWindow "clientWindow" +#define XNInputStyle "inputStyle" +#define XNFocusWindow "focusWindow" +#define XNResourceName "resourceName" +#define XNResourceClass "resourceClass" +#define XNGeometryCallback "geometryCallback" +#define XNFilterEvents "filterEvents" +#define XNPreeditStartCallback "preeditStartCallback" +#define XNPreeditDoneCallback "preeditDoneCallback" +#define XNPreeditDrawCallback "preeditDrawCallback" +#define XNPreeditCaretCallback "preeditCaretCallback" +#define XNPreeditAttributes "preeditAttributes" +#define XNStatusStartCallback "statusStartCallback" +#define XNStatusDoneCallback "statusDoneCallback" +#define XNStatusDrawCallback "statusDrawCallback" +#define XNStatusAttributes "statusAttributes" +#define XNArea "area" +#define XNAreaNeeded "areaNeeded" +#define XNSpotLocation "spotLocation" +#define XNColormap "colorMap" +#define XNStdColormap "stdColorMap" +#define XNForeground "foreground" +#define XNBackground "background" +#define XNBackgroundPixmap "backgroundPixmap" +#define XNFontSet "fontSet" +#define XNLineSpace "lineSpace" +#define XNCursor "cursor" + +#define XBufferOverflow -1 +#define XLookupNone 1 +#define XLookupChars 2 +#define XLookupKeySym 3 +#define XLookupBoth 4 + +#if NeedFunctionPrototypes +typedef void *XVaNestedList; +#else +typedef XPointer XVaNestedList; +#endif + +typedef struct { + XPointer client_data; + XIMProc callback; +} XIMCallback; + +typedef unsigned long XIMFeedback; + +#define XIMReverse 1 +#define XIMUnderline (1<<1) +#define XIMHighlight (1<<2) +#define XIMPrimary (1<<5) +#define XIMSecondary (1<<6) +#define XIMTertiary (1<<7) + +typedef struct _XIMText { + unsigned short length; + XIMFeedback *feedback; + Bool encoding_is_wchar; + union { + char *multi_byte; + wchar_t *wide_char; + } string; +} XIMText; + +typedef struct _XIMPreeditDrawCallbackStruct { + int caret; /* Cursor offset within pre-edit string */ + int chg_first; /* Starting change position */ + int chg_length; /* Length of the change in character count */ + XIMText *text; +} XIMPreeditDrawCallbackStruct; + +typedef enum { + XIMForwardChar, XIMBackwardChar, + XIMForwardWord, XIMBackwardWord, + XIMCaretUp, XIMCaretDown, + XIMNextLine, XIMPreviousLine, + XIMLineStart, XIMLineEnd, + XIMAbsolutePosition, + XIMDontChange +} XIMCaretDirection; + +typedef enum { + XIMIsInvisible, /* Disable caret feedback */ + XIMIsPrimary, /* UI defined caret feedback */ + XIMIsSecondary /* UI defined caret feedback */ +} XIMCaretStyle; + +typedef struct _XIMPreeditCaretCallbackStruct { + int position; /* Caret offset within pre-edit string */ + XIMCaretDirection direction; /* Caret moves direction */ + XIMCaretStyle style; /* Feedback of the caret */ +} XIMPreeditCaretCallbackStruct; + +typedef enum { + XIMTextType, + XIMBitmapType +} XIMStatusDataType; + +typedef struct _XIMStatusDrawCallbackStruct { + XIMStatusDataType type; + union { + XIMText *text; + Pixmap bitmap; + } data; +} XIMStatusDrawCallbackStruct; + +typedef int (*XErrorHandler) ( /* WARNING, this type not in Xlib spec */ +#if NeedFunctionPrototypes + Display* /* display */, + XErrorEvent* /* error_event */ +#endif +); + +_XFUNCPROTOBEGIN + + + +#include "tkIntXlibDecls.h" + +_XFUNCPROTOEND + +#if defined(MAC_OSX_TK) +# undef Cursor +# undef Region +#endif + +#endif /* _XLIB_H_ */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xutil.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xutil.h new file mode 100644 index 00000000..58124b04 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/Xutil.h @@ -0,0 +1,855 @@ +/* $XConsortium: Xutil.h,v 11.73 91/07/30 16:21:37 rws Exp $ */ + +/*********************************************************** +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, Massachusetts. + + All Rights Reserved + +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 and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or MIT not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifndef _XUTIL_H_ +#define _XUTIL_H_ + +/* You must include before including this file */ + +#if defined(MAC_OSX_TK) +# define Region XRegion +#endif + +/* + * Bitmask returned by XParseGeometry(). Each bit tells if the corresponding + * value (x, y, width, height) was found in the parsed string. + */ +#define NoValue 0x0000 +#define XValue 0x0001 +#define YValue 0x0002 +#define WidthValue 0x0004 +#define HeightValue 0x0008 +#define AllValues 0x000F +#define XNegative 0x0010 +#define YNegative 0x0020 + +/* + * new version containing base_width, base_height, and win_gravity fields; + * used with WM_NORMAL_HINTS. + */ +typedef struct { + long flags; /* marks which fields in this structure are defined */ + int x, y; /* obsolete for new window mgrs, but clients */ + int width, height; /* should set so old wm's don't mess up */ + int min_width, min_height; + int max_width, max_height; + int width_inc, height_inc; + struct { + int x; /* numerator */ + int y; /* denominator */ + } min_aspect, max_aspect; + int base_width, base_height; /* added by ICCCM version 1 */ + int win_gravity; /* added by ICCCM version 1 */ +} XSizeHints; + +/* + * The next block of definitions are for window manager properties that + * clients and applications use for communication. + */ + +/* flags argument in size hints */ +#define USPosition (1L << 0) /* user specified x, y */ +#define USSize (1L << 1) /* user specified width, height */ + +#define PPosition (1L << 2) /* program specified position */ +#define PSize (1L << 3) /* program specified size */ +#define PMinSize (1L << 4) /* program specified minimum size */ +#define PMaxSize (1L << 5) /* program specified maximum size */ +#define PResizeInc (1L << 6) /* program specified resize increments */ +#define PAspect (1L << 7) /* program specified min and max aspect ratios */ +#define PBaseSize (1L << 8) /* program specified base for incrementing */ +#define PWinGravity (1L << 9) /* program specified window gravity */ + +/* obsolete */ +#define PAllHints (PPosition|PSize|PMinSize|PMaxSize|PResizeInc|PAspect) + + + +typedef struct { + long flags; /* marks which fields in this structure are defined */ + Bool input; /* does this application rely on the window manager to + get keyboard input? */ + int initial_state; /* see below */ + Pixmap icon_pixmap; /* pixmap to be used as icon */ + Window icon_window; /* window to be used as icon */ + int icon_x, icon_y; /* initial position of icon */ + Pixmap icon_mask; /* icon mask bitmap */ + XID window_group; /* id of related window group */ + /* this structure may be extended in the future */ +} XWMHints; + +/* definition for flags of XWMHints */ + +#define InputHint (1L << 0) +#define StateHint (1L << 1) +#define IconPixmapHint (1L << 2) +#define IconWindowHint (1L << 3) +#define IconPositionHint (1L << 4) +#define IconMaskHint (1L << 5) +#define WindowGroupHint (1L << 6) +#define AllHints (InputHint|StateHint|IconPixmapHint|IconWindowHint| \ +IconPositionHint|IconMaskHint|WindowGroupHint) + +/* definitions for initial window state */ +#define WithdrawnState 0 /* for windows that are not mapped */ +#define NormalState 1 /* most applications want to start this way */ +#define IconicState 3 /* application wants to start as an icon */ + +/* + * Obsolete states no longer defined by ICCCM + */ +#define DontCareState 0 /* don't know or care */ +#define ZoomState 2 /* application wants to start zoomed */ +#define InactiveState 4 /* application believes it is seldom used; */ + /* some wm's may put it on inactive menu */ + + +/* + * new structure for manipulating TEXT properties; used with WM_NAME, + * WM_ICON_NAME, WM_CLIENT_MACHINE, and WM_COMMAND. + */ +typedef struct { + unsigned char *value; /* same as Property routines */ + Atom encoding; /* prop type */ + int format; /* prop data format: 8, 16, or 32 */ + unsigned long nitems; /* number of data items in value */ +} XTextProperty; + +#define XNoMemory -1 +#define XLocaleNotSupported -2 +#define XConverterNotFound -3 + +typedef enum { + XStringStyle, /* STRING */ + XCompoundTextStyle, /* COMPOUND_TEXT */ + XTextStyle, /* text in owner's encoding (current locale)*/ + XStdICCTextStyle /* STRING, else COMPOUND_TEXT */ +} XICCEncodingStyle; + +typedef struct { + int min_width, min_height; + int max_width, max_height; + int width_inc, height_inc; +} XIconSize; + +typedef struct { + char *res_name; + char *res_class; +} XClassHint; + +/* + * These macros are used to give some sugar to the image routines so that + * naive people are more comfortable with them. + */ +#define XDestroyImage(ximage) \ + ((*((ximage)->f.destroy_image))((ximage))) +#define XGetPixel(ximage, x, y) \ + ((*((ximage)->f.get_pixel))((ximage), (x), (y))) +#define XPutPixel(ximage, x, y, pixel) \ + ((*((ximage)->f.put_pixel))((ximage), (x), (y), (pixel))) +#define XSubImage(ximage, x, y, width, height) \ + ((*((ximage)->f.sub_image))((ximage), (x), (y), (width), (height))) +#define XAddPixel(ximage, value) \ + ((*((ximage)->f.add_pixel))((ximage), (value))) + +/* + * Compose sequence status structure, used in calling XLookupString. + */ +typedef struct _XComposeStatus { + XPointer compose_ptr; /* state table pointer */ + int chars_matched; /* match state */ +} XComposeStatus; + +/* + * Keysym macros, used on Keysyms to test for classes of symbols + */ +#define IsKeypadKey(keysym) \ + (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal)) + +#define IsCursorKey(keysym) \ + (((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select)) + +#define IsPFKey(keysym) \ + (((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4)) + +#define IsFunctionKey(keysym) \ + (((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35)) + +#define IsMiscFunctionKey(keysym) \ + (((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) <= XK_Break)) + +#define IsModifierKey(keysym) \ + ((((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R)) \ + || ((unsigned)(keysym) == XK_Mode_switch) \ + || ((unsigned)(keysym) == XK_Num_Lock)) +/* + * opaque reference to Region data type + */ +typedef struct _XRegion *Region; + +/* Return values from XRectInRegion() */ + +#define RectangleOut 0 +#define RectangleIn 1 +#define RectanglePart 2 + + +/* + * Information used by the visual utility routines to find desired visual + * type from the many visuals a display may support. + */ + +typedef struct { + Visual *visual; + VisualID visualid; + int screen; + int depth; +#if defined(__cplusplus) || defined(c_plusplus) + int c_class; /* C++ */ +#else + int class; +#endif + unsigned long red_mask; + unsigned long green_mask; + unsigned long blue_mask; + int colormap_size; + int bits_per_rgb; +} XVisualInfo; + +#define VisualNoMask 0x0 +#define VisualIDMask 0x1 +#define VisualScreenMask 0x2 +#define VisualDepthMask 0x4 +#define VisualClassMask 0x8 +#define VisualRedMaskMask 0x10 +#define VisualGreenMaskMask 0x20 +#define VisualBlueMaskMask 0x40 +#define VisualColormapSizeMask 0x80 +#define VisualBitsPerRGBMask 0x100 +#define VisualAllMask 0x1FF + +/* + * This defines a window manager property that clients may use to + * share standard color maps of type RGB_COLOR_MAP: + */ +typedef struct { + Colormap colormap; + unsigned long red_max; + unsigned long red_mult; + unsigned long green_max; + unsigned long green_mult; + unsigned long blue_max; + unsigned long blue_mult; + unsigned long base_pixel; + VisualID visualid; /* added by ICCCM version 1 */ + XID killid; /* added by ICCCM version 1 */ +} XStandardColormap; + +#define ReleaseByFreeingColormap ((XID) 1L) /* for killid field above */ + + +/* + * return codes for XReadBitmapFile and XWriteBitmapFile + */ +#define BitmapSuccess 0 +#define BitmapOpenFailed 1 +#define BitmapFileInvalid 2 +#define BitmapNoMemory 3 + +/**************************************************************** + * + * Context Management + * + ****************************************************************/ + + +/* Associative lookup table return codes */ + +#define XCSUCCESS 0 /* No error. */ +#define XCNOMEM 1 /* Out of memory */ +#define XCNOENT 2 /* No entry in table */ + +typedef int XContext; + +#define XUniqueContext() ((XContext) XrmUniqueQuark()) +#define XStringToContext(string) ((XContext) XrmStringToQuark(string)) + +_XFUNCPROTOBEGIN + +/* The following declarations are alphabetized. */ + +extern XClassHint *XAllocClassHint ( +#if NeedFunctionPrototypes + void +#endif +); + +extern XIconSize *XAllocIconSize ( +#if NeedFunctionPrototypes + void +#endif +); + +extern XSizeHints *XAllocSizeHints ( +#if NeedFunctionPrototypes + void +#endif +); + +extern XStandardColormap *XAllocStandardColormap ( +#if NeedFunctionPrototypes + void +#endif +); + +extern XWMHints *XAllocWMHints ( +#if NeedFunctionPrototypes + void +#endif +); + +extern void XClipBox( +#if NeedFunctionPrototypes + Region /* r */, + XRectangle* /* rect_return */ +#endif +); + +extern Region XCreateRegion( +#if NeedFunctionPrototypes + void +#endif +); + +extern char *XDefaultString( +#if NeedFunctionPrototypes + void +#endif +); + +extern int XDeleteContext( +#if NeedFunctionPrototypes + Display* /* display */, + XID /* rid */, + XContext /* context */ +#endif +); + +extern void XDestroyRegion( +#if NeedFunctionPrototypes + Region /* r */ +#endif +); + +extern Bool XEmptyRegion( +#if NeedFunctionPrototypes + Region /* r */ +#endif +); + +extern Bool XEqualRegion( +#if NeedFunctionPrototypes + Region /* r1 */, + Region /* r2 */ +#endif +); + +extern int XFindContext( +#if NeedFunctionPrototypes + Display* /* display */, + XID /* rid */, + XContext /* context */, + XPointer* /* data_return */ +#endif +); + +extern Status XGetClassHint( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XClassHint* /* class_hints_return */ +#endif +); + +extern Status XGetIconSizes( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XIconSize** /* size_list_return */, + int* /* count_return */ +#endif +); + +extern Status XGetNormalHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints_return */ +#endif +); + +extern Status XGetRGBColormaps( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XStandardColormap** /* stdcmap_return */, + int* /* count_return */, + Atom /* property */ +#endif +); + +extern Status XGetSizeHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints_return */, + Atom /* property */ +#endif +); + +extern Status XGetStandardColormap( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XStandardColormap* /* colormap_return */, + Atom /* property */ +#endif +); + +extern Status XGetTextProperty( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* window */, + XTextProperty* /* text_prop_return */, + Atom /* property */ +#endif +); + + +extern Status XGetWMClientMachine( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* text_prop_return */ +#endif +); + +extern XWMHints *XGetWMHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */ +#endif +); + +extern Status XGetWMIconName( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* text_prop_return */ +#endif +); + +extern Status XGetWMName( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* text_prop_return */ +#endif +); + +extern Status XGetWMNormalHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints_return */, + long* /* supplied_return */ +#endif +); + +extern Status XGetWMSizeHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints_return */, + long* /* supplied_return */, + Atom /* property */ +#endif +); + +extern Status XGetZoomHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* zhints_return */ +#endif +); + +extern void XIntersectRegion( +#if NeedFunctionPrototypes + Region /* sra */, + Region /* srb */, + Region /* dr_return */ +#endif +); + +extern int XLookupString( +#if NeedFunctionPrototypes + XKeyEvent* /* event_struct */, + char* /* buffer_return */, + int /* bytes_buffer */, + KeySym* /* keysym_return */, + XComposeStatus* /* status_in_out */ +#endif +); + +extern Status XMatchVisualInfo( +#if NeedFunctionPrototypes + Display* /* display */, + int /* screen */, + int /* depth */, + int /* class */, + XVisualInfo* /* vinfo_return */ +#endif +); + +extern void XOffsetRegion( +#if NeedFunctionPrototypes + Region /* r */, + int /* dx */, + int /* dy */ +#endif +); + +extern Bool XPointInRegion( +#if NeedFunctionPrototypes + Region /* r */, + int /* x */, + int /* y */ +#endif +); + +extern Region XPolygonRegion( +#if NeedFunctionPrototypes + XPoint* /* points */, + int /* n */, + int /* fill_rule */ +#endif +); + +extern int XRectInRegion( +#if NeedFunctionPrototypes + Region /* r */, + int /* x */, + int /* y */, + unsigned int /* width */, + unsigned int /* height */ +#endif +); + +extern int XSaveContext( +#if NeedFunctionPrototypes + Display* /* display */, + XID /* rid */, + XContext /* context */, + _Xconst char* /* data */ +#endif +); + +extern void XSetClassHint( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XClassHint* /* class_hints */ +#endif +); + +extern void XSetIconSizes( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XIconSize* /* size_list */, + int /* count */ +#endif +); + +extern void XSetNormalHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints */ +#endif +); + +extern void XSetRGBColormaps( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XStandardColormap* /* stdcmaps */, + int /* count */, + Atom /* property */ +#endif +); + +extern void XSetSizeHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints */, + Atom /* property */ +#endif +); + +extern void XSetStandardProperties( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + _Xconst char* /* window_name */, + _Xconst char* /* icon_name */, + Pixmap /* icon_pixmap */, + char** /* argv */, + int /* argc */, + XSizeHints* /* hints */ +#endif +); + +extern void XSetTextProperty( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* text_prop */, + Atom /* property */ +#endif +); + +extern void XSetWMHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XWMHints* /* wm_hints */ +#endif +); + +extern void XSetWMIconName( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* text_prop */ +#endif +); + +extern void XSetWMName( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* text_prop */ +#endif +); + +extern void XSetWMNormalHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints */ +#endif +); + +extern void XSetWMProperties( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XTextProperty* /* window_name */, + XTextProperty* /* icon_name */, + char** /* argv */, + int /* argc */, + XSizeHints* /* normal_hints */, + XWMHints* /* wm_hints */, + XClassHint* /* class_hints */ +#endif +); + +extern void XmbSetWMProperties( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + _Xconst char* /* window_name */, + _Xconst char* /* icon_name */, + char** /* argv */, + int /* argc */, + XSizeHints* /* normal_hints */, + XWMHints* /* wm_hints */, + XClassHint* /* class_hints */ +#endif +); + +extern void XSetWMSizeHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* hints */, + Atom /* property */ +#endif +); + +extern void XSetRegion( +#if NeedFunctionPrototypes + Display* /* display */, + GC /* gc */, + Region /* r */ +#endif +); + +extern void XSetStandardColormap( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XStandardColormap* /* colormap */, + Atom /* property */ +#endif +); + +extern void XSetZoomHints( +#if NeedFunctionPrototypes + Display* /* display */, + Window /* w */, + XSizeHints* /* zhints */ +#endif +); + +extern void XShrinkRegion( +#if NeedFunctionPrototypes + Region /* r */, + int /* dx */, + int /* dy */ +#endif +); + +extern void XSubtractRegion( +#if NeedFunctionPrototypes + Region /* sra */, + Region /* srb */, + Region /* dr_return */ +#endif +); + +extern int XmbTextListToTextProperty( +#if NeedFunctionPrototypes + Display* /* display */, + char** /* list */, + int /* count */, + XICCEncodingStyle /* style */, + XTextProperty* /* text_prop_return */ +#endif +); + +extern int XwcTextListToTextProperty( +#if NeedFunctionPrototypes + Display* /* display */, + wchar_t** /* list */, + int /* count */, + XICCEncodingStyle /* style */, + XTextProperty* /* text_prop_return */ +#endif +); + +extern void XwcFreeStringList( +#if NeedFunctionPrototypes + wchar_t** /* list */ +#endif +); + +extern Status XTextPropertyToStringList( +#if NeedFunctionPrototypes + XTextProperty* /* text_prop */, + char*** /* list_return */, + int* /* count_return */ +#endif +); + +extern int XmbTextPropertyToTextList( +#if NeedFunctionPrototypes + Display* /* display */, + XTextProperty* /* text_prop */, + char*** /* list_return */, + int* /* count_return */ +#endif +); + +extern int XwcTextPropertyToTextList( +#if NeedFunctionPrototypes + Display* /* display */, + XTextProperty* /* text_prop */, + wchar_t*** /* list_return */, + int* /* count_return */ +#endif +); + +extern void XUnionRectWithRegion( +#if NeedFunctionPrototypes + XRectangle* /* rectangle */, + Region /* src_region */, + Region /* dest_region_return */ +#endif +); + +extern void XUnionRegion( +#if NeedFunctionPrototypes + Region /* sra */, + Region /* srb */, + Region /* dr_return */ +#endif +); + +extern int XWMGeometry( +#if NeedFunctionPrototypes + Display* /* display */, + int /* screen_number */, + _Xconst char* /* user_geometry */, + _Xconst char* /* default_geometry */, + unsigned int /* border_width */, + XSizeHints* /* hints */, + int* /* x_return */, + int* /* y_return */, + int* /* width_return */, + int* /* height_return */, + int* /* gravity_return */ +#endif +); + +extern void XXorRegion( +#if NeedFunctionPrototypes + Region /* sra */, + Region /* srb */, + Region /* dr_return */ +#endif +); + +_XFUNCPROTOEND + +#if defined(MAC_OSX_TK) +# undef Region +#endif + +#endif /* _XUTIL_H_ */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/cursorfont.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/cursorfont.h new file mode 100644 index 00000000..617274fa --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/cursorfont.h @@ -0,0 +1,79 @@ +/* $XConsortium: cursorfont.h,v 1.2 88/09/06 16:44:27 jim Exp $ */ +#define XC_num_glyphs 154 +#define XC_X_cursor 0 +#define XC_arrow 2 +#define XC_based_arrow_down 4 +#define XC_based_arrow_up 6 +#define XC_boat 8 +#define XC_bogosity 10 +#define XC_bottom_left_corner 12 +#define XC_bottom_right_corner 14 +#define XC_bottom_side 16 +#define XC_bottom_tee 18 +#define XC_box_spiral 20 +#define XC_center_ptr 22 +#define XC_circle 24 +#define XC_clock 26 +#define XC_coffee_mug 28 +#define XC_cross 30 +#define XC_cross_reverse 32 +#define XC_crosshair 34 +#define XC_diamond_cross 36 +#define XC_dot 38 +#define XC_dotbox 40 +#define XC_double_arrow 42 +#define XC_draft_large 44 +#define XC_draft_small 46 +#define XC_draped_box 48 +#define XC_exchange 50 +#define XC_fleur 52 +#define XC_gobbler 54 +#define XC_gumby 56 +#define XC_hand1 58 +#define XC_hand2 60 +#define XC_heart 62 +#define XC_icon 64 +#define XC_iron_cross 66 +#define XC_left_ptr 68 +#define XC_left_side 70 +#define XC_left_tee 72 +#define XC_leftbutton 74 +#define XC_ll_angle 76 +#define XC_lr_angle 78 +#define XC_man 80 +#define XC_middlebutton 82 +#define XC_mouse 84 +#define XC_pencil 86 +#define XC_pirate 88 +#define XC_plus 90 +#define XC_question_arrow 92 +#define XC_right_ptr 94 +#define XC_right_side 96 +#define XC_right_tee 98 +#define XC_rightbutton 100 +#define XC_rtl_logo 102 +#define XC_sailboat 104 +#define XC_sb_down_arrow 106 +#define XC_sb_h_double_arrow 108 +#define XC_sb_left_arrow 110 +#define XC_sb_right_arrow 112 +#define XC_sb_up_arrow 114 +#define XC_sb_v_double_arrow 116 +#define XC_shuttle 118 +#define XC_sizing 120 +#define XC_spider 122 +#define XC_spraycan 124 +#define XC_star 126 +#define XC_target 128 +#define XC_tcross 130 +#define XC_top_left_arrow 132 +#define XC_top_left_corner 134 +#define XC_top_right_corner 136 +#define XC_top_side 138 +#define XC_top_tee 140 +#define XC_trek 142 +#define XC_ul_angle 144 +#define XC_umbrella 146 +#define XC_ur_angle 148 +#define XC_watch 150 +#define XC_xterm 152 diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/keysym.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/keysym.h new file mode 100644 index 00000000..550b76db --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/keysym.h @@ -0,0 +1,35 @@ +/* $XConsortium: keysym.h,v 1.13 91/03/13 20:09:49 rws Exp $ */ + +/*********************************************************** +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, Massachusetts. + + All Rights Reserved + +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 and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or MIT not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* default keysyms */ +#define XK_MISCELLANY +#define XK_LATIN1 +#define XK_LATIN2 +#define XK_LATIN3 +#define XK_LATIN4 +#define XK_GREEK + +#include diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/keysymdef.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/keysymdef.h new file mode 100644 index 00000000..b22d41b3 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/keysymdef.h @@ -0,0 +1,1169 @@ +/* $XConsortium: keysymdef.h,v 1.15 93/04/02 10:57:36 rws Exp $ */ + +/*********************************************************** +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, Massachusetts. + + All Rights Reserved + +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 and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or MIT not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#define XK_VoidSymbol 0xFFFFFF /* void symbol */ + +#ifdef XK_MISCELLANY +/* + * TTY Functions, cleverly chosen to map to ascii, for convenience of + * programming, but could have been arbitrary (at the cost of lookup + * tables in client code. + */ + +#define XK_BackSpace 0xFF08 /* back space, back char */ +#define XK_Tab 0xFF09 +#define XK_Linefeed 0xFF0A /* Linefeed, LF */ +#define XK_Clear 0xFF0B +#define XK_Return 0xFF0D /* Return, enter */ +#define XK_Pause 0xFF13 /* Pause, hold */ +#define XK_Scroll_Lock 0xFF14 +#define XK_Sys_Req 0xFF15 +#define XK_Escape 0xFF1B +#define XK_Delete 0xFFFF /* Delete, rubout */ + + + +/* International & multi-key character composition */ + +#define XK_Multi_key 0xFF20 /* Multi-key character compose */ + +/* Japanese keyboard support */ + +#define XK_Kanji 0xFF21 /* Kanji, Kanji convert */ +#define XK_Muhenkan 0xFF22 /* Cancel Conversion */ +#define XK_Henkan_Mode 0xFF23 /* Start/Stop Conversion */ +#define XK_Henkan 0xFF23 /* Alias for Henkan_Mode */ +#define XK_Romaji 0xFF24 /* to Romaji */ +#define XK_Hiragana 0xFF25 /* to Hiragana */ +#define XK_Katakana 0xFF26 /* to Katakana */ +#define XK_Hiragana_Katakana 0xFF27 /* Hiragana/Katakana toggle */ +#define XK_Zenkaku 0xFF28 /* to Zenkaku */ +#define XK_Hankaku 0xFF29 /* to Hankaku */ +#define XK_Zenkaku_Hankaku 0xFF2A /* Zenkaku/Hankaku toggle */ +#define XK_Touroku 0xFF2B /* Add to Dictionary */ +#define XK_Massyo 0xFF2C /* Delete from Dictionary */ +#define XK_Kana_Lock 0xFF2D /* Kana Lock */ +#define XK_Kana_Shift 0xFF2E /* Kana Shift */ +#define XK_Eisu_Shift 0xFF2F /* Alphanumeric Shift */ +#define XK_Eisu_toggle 0xFF30 /* Alphanumeric toggle */ + +/* Cursor control & motion */ + +#define XK_Home 0xFF50 +#define XK_Left 0xFF51 /* Move left, left arrow */ +#define XK_Up 0xFF52 /* Move up, up arrow */ +#define XK_Right 0xFF53 /* Move right, right arrow */ +#define XK_Down 0xFF54 /* Move down, down arrow */ +#define XK_Prior 0xFF55 /* Prior, previous */ +#define XK_Page_Up 0xFF55 +#define XK_Next 0xFF56 /* Next */ +#define XK_Page_Down 0xFF56 +#define XK_End 0xFF57 /* EOL */ +#define XK_Begin 0xFF58 /* BOL */ + +/* Special Windows keyboard keys */ + +#define XK_Win_L 0xFF5B /* Left-hand Windows */ +#define XK_Win_R 0xFF5C /* Right-hand Windows */ +#define XK_App 0xFF5D /* Menu key */ + +/* Misc Functions */ + +#define XK_Select 0xFF60 /* Select, mark */ +#define XK_Print 0xFF61 +#define XK_Execute 0xFF62 /* Execute, run, do */ +#define XK_Insert 0xFF63 /* Insert, insert here */ +#define XK_Undo 0xFF65 /* Undo, oops */ +#define XK_Redo 0xFF66 /* redo, again */ +#define XK_Menu 0xFF67 +#define XK_Find 0xFF68 /* Find, search */ +#define XK_Cancel 0xFF69 /* Cancel, stop, abort, exit */ +#define XK_Help 0xFF6A /* Help, ? */ +#define XK_Break 0xFF6B +#define XK_Mode_switch 0xFF7E /* Character set switch */ +#define XK_script_switch 0xFF7E /* Alias for mode_switch */ +#define XK_Num_Lock 0xFF7F + +/* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ + +#define XK_KP_Space 0xFF80 /* space */ +#define XK_KP_Tab 0xFF89 +#define XK_KP_Enter 0xFF8D /* enter */ +#define XK_KP_F1 0xFF91 /* PF1, KP_A, ... */ +#define XK_KP_F2 0xFF92 +#define XK_KP_F3 0xFF93 +#define XK_KP_F4 0xFF94 +#define XK_KP_Home 0xFF95 +#define XK_KP_Left 0xFF96 +#define XK_KP_Up 0xFF97 +#define XK_KP_Right 0xFF98 +#define XK_KP_Down 0xFF99 +#define XK_KP_Prior 0xFF9A +#define XK_KP_Page_Up 0xFF9A +#define XK_KP_Next 0xFF9B +#define XK_KP_Page_Down 0xFF9B +#define XK_KP_End 0xFF9C +#define XK_KP_Begin 0xFF9D +#define XK_KP_Insert 0xFF9E +#define XK_KP_Delete 0xFF9F +#define XK_KP_Equal 0xFFBD /* equals */ +#define XK_KP_Multiply 0xFFAA +#define XK_KP_Add 0xFFAB +#define XK_KP_Separator 0xFFAC /* separator, often comma */ +#define XK_KP_Subtract 0xFFAD +#define XK_KP_Decimal 0xFFAE +#define XK_KP_Divide 0xFFAF + +#define XK_KP_0 0xFFB0 +#define XK_KP_1 0xFFB1 +#define XK_KP_2 0xFFB2 +#define XK_KP_3 0xFFB3 +#define XK_KP_4 0xFFB4 +#define XK_KP_5 0xFFB5 +#define XK_KP_6 0xFFB6 +#define XK_KP_7 0xFFB7 +#define XK_KP_8 0xFFB8 +#define XK_KP_9 0xFFB9 + + + +/* + * Auxilliary Functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufactures have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ + +#define XK_F1 0xFFBE +#define XK_F2 0xFFBF +#define XK_F3 0xFFC0 +#define XK_F4 0xFFC1 +#define XK_F5 0xFFC2 +#define XK_F6 0xFFC3 +#define XK_F7 0xFFC4 +#define XK_F8 0xFFC5 +#define XK_F9 0xFFC6 +#define XK_F10 0xFFC7 +#define XK_F11 0xFFC8 +#define XK_L1 0xFFC8 +#define XK_F12 0xFFC9 +#define XK_L2 0xFFC9 +#define XK_F13 0xFFCA +#define XK_L3 0xFFCA +#define XK_F14 0xFFCB +#define XK_L4 0xFFCB +#define XK_F15 0xFFCC +#define XK_L5 0xFFCC +#define XK_F16 0xFFCD +#define XK_L6 0xFFCD +#define XK_F17 0xFFCE +#define XK_L7 0xFFCE +#define XK_F18 0xFFCF +#define XK_L8 0xFFCF +#define XK_F19 0xFFD0 +#define XK_L9 0xFFD0 +#define XK_F20 0xFFD1 +#define XK_L10 0xFFD1 +#define XK_F21 0xFFD2 +#define XK_R1 0xFFD2 +#define XK_F22 0xFFD3 +#define XK_R2 0xFFD3 +#define XK_F23 0xFFD4 +#define XK_R3 0xFFD4 +#define XK_F24 0xFFD5 +#define XK_R4 0xFFD5 +#define XK_F25 0xFFD6 +#define XK_R5 0xFFD6 +#define XK_F26 0xFFD7 +#define XK_R6 0xFFD7 +#define XK_F27 0xFFD8 +#define XK_R7 0xFFD8 +#define XK_F28 0xFFD9 +#define XK_R8 0xFFD9 +#define XK_F29 0xFFDA +#define XK_R9 0xFFDA +#define XK_F30 0xFFDB +#define XK_R10 0xFFDB +#define XK_F31 0xFFDC +#define XK_R11 0xFFDC +#define XK_F32 0xFFDD +#define XK_R12 0xFFDD +#define XK_F33 0xFFDE +#define XK_R13 0xFFDE +#define XK_F34 0xFFDF +#define XK_R14 0xFFDF +#define XK_F35 0xFFE0 +#define XK_R15 0xFFE0 + +/* Modifiers */ + +#define XK_Shift_L 0xFFE1 /* Left shift */ +#define XK_Shift_R 0xFFE2 /* Right shift */ +#define XK_Control_L 0xFFE3 /* Left control */ +#define XK_Control_R 0xFFE4 /* Right control */ +#define XK_Caps_Lock 0xFFE5 /* Caps lock */ +#define XK_Shift_Lock 0xFFE6 /* Shift lock */ + +#define XK_Meta_L 0xFFE7 /* Left meta */ +#define XK_Meta_R 0xFFE8 /* Right meta */ +#define XK_Alt_L 0xFFE9 /* Left alt */ +#define XK_Alt_R 0xFFEA /* Right alt */ +#define XK_Super_L 0xFFEB /* Left super */ +#define XK_Super_R 0xFFEC /* Right super */ +#define XK_Hyper_L 0xFFED /* Left hyper */ +#define XK_Hyper_R 0xFFEE /* Right hyper */ +#endif /* XK_MISCELLANY */ + +/* + * Latin 1 + * Byte 3 = 0 + */ +#ifdef XK_LATIN1 +#define XK_space 0x020 +#define XK_exclam 0x021 +#define XK_quotedbl 0x022 +#define XK_numbersign 0x023 +#define XK_dollar 0x024 +#define XK_percent 0x025 +#define XK_ampersand 0x026 +#define XK_apostrophe 0x027 +#define XK_quoteright 0x027 /* deprecated */ +#define XK_parenleft 0x028 +#define XK_parenright 0x029 +#define XK_asterisk 0x02a +#define XK_plus 0x02b +#define XK_comma 0x02c +#define XK_minus 0x02d +#define XK_period 0x02e +#define XK_slash 0x02f +#define XK_0 0x030 +#define XK_1 0x031 +#define XK_2 0x032 +#define XK_3 0x033 +#define XK_4 0x034 +#define XK_5 0x035 +#define XK_6 0x036 +#define XK_7 0x037 +#define XK_8 0x038 +#define XK_9 0x039 +#define XK_colon 0x03a +#define XK_semicolon 0x03b +#define XK_less 0x03c +#define XK_equal 0x03d +#define XK_greater 0x03e +#define XK_question 0x03f +#define XK_at 0x040 +#define XK_A 0x041 +#define XK_B 0x042 +#define XK_C 0x043 +#define XK_D 0x044 +#define XK_E 0x045 +#define XK_F 0x046 +#define XK_G 0x047 +#define XK_H 0x048 +#define XK_I 0x049 +#define XK_J 0x04a +#define XK_K 0x04b +#define XK_L 0x04c +#define XK_M 0x04d +#define XK_N 0x04e +#define XK_O 0x04f +#define XK_P 0x050 +#define XK_Q 0x051 +#define XK_R 0x052 +#define XK_S 0x053 +#define XK_T 0x054 +#define XK_U 0x055 +#define XK_V 0x056 +#define XK_W 0x057 +#define XK_X 0x058 +#define XK_Y 0x059 +#define XK_Z 0x05a +#define XK_bracketleft 0x05b +#define XK_backslash 0x05c +#define XK_bracketright 0x05d +#define XK_asciicircum 0x05e +#define XK_underscore 0x05f +#define XK_grave 0x060 +#define XK_quoteleft 0x060 /* deprecated */ +#define XK_a 0x061 +#define XK_b 0x062 +#define XK_c 0x063 +#define XK_d 0x064 +#define XK_e 0x065 +#define XK_f 0x066 +#define XK_g 0x067 +#define XK_h 0x068 +#define XK_i 0x069 +#define XK_j 0x06a +#define XK_k 0x06b +#define XK_l 0x06c +#define XK_m 0x06d +#define XK_n 0x06e +#define XK_o 0x06f +#define XK_p 0x070 +#define XK_q 0x071 +#define XK_r 0x072 +#define XK_s 0x073 +#define XK_t 0x074 +#define XK_u 0x075 +#define XK_v 0x076 +#define XK_w 0x077 +#define XK_x 0x078 +#define XK_y 0x079 +#define XK_z 0x07a +#define XK_braceleft 0x07b +#define XK_bar 0x07c +#define XK_braceright 0x07d +#define XK_asciitilde 0x07e + +#define XK_nobreakspace 0x0a0 +#define XK_exclamdown 0x0a1 +#define XK_cent 0x0a2 +#define XK_sterling 0x0a3 +#define XK_currency 0x0a4 +#define XK_yen 0x0a5 +#define XK_brokenbar 0x0a6 +#define XK_section 0x0a7 +#define XK_diaeresis 0x0a8 +#define XK_copyright 0x0a9 +#define XK_ordfeminine 0x0aa +#define XK_guillemotleft 0x0ab /* left angle quotation mark */ +#define XK_notsign 0x0ac +#define XK_hyphen 0x0ad +#define XK_registered 0x0ae +#define XK_macron 0x0af +#define XK_degree 0x0b0 +#define XK_plusminus 0x0b1 +#define XK_twosuperior 0x0b2 +#define XK_threesuperior 0x0b3 +#define XK_acute 0x0b4 +#define XK_mu 0x0b5 +#define XK_paragraph 0x0b6 +#define XK_periodcentered 0x0b7 +#define XK_cedilla 0x0b8 +#define XK_onesuperior 0x0b9 +#define XK_masculine 0x0ba +#define XK_guillemotright 0x0bb /* right angle quotation mark */ +#define XK_onequarter 0x0bc +#define XK_onehalf 0x0bd +#define XK_threequarters 0x0be +#define XK_questiondown 0x0bf +#define XK_Agrave 0x0c0 +#define XK_Aacute 0x0c1 +#define XK_Acircumflex 0x0c2 +#define XK_Atilde 0x0c3 +#define XK_Adiaeresis 0x0c4 +#define XK_Aring 0x0c5 +#define XK_AE 0x0c6 +#define XK_Ccedilla 0x0c7 +#define XK_Egrave 0x0c8 +#define XK_Eacute 0x0c9 +#define XK_Ecircumflex 0x0ca +#define XK_Ediaeresis 0x0cb +#define XK_Igrave 0x0cc +#define XK_Iacute 0x0cd +#define XK_Icircumflex 0x0ce +#define XK_Idiaeresis 0x0cf +#define XK_ETH 0x0d0 +#define XK_Eth 0x0d0 /* deprecated */ +#define XK_Ntilde 0x0d1 +#define XK_Ograve 0x0d2 +#define XK_Oacute 0x0d3 +#define XK_Ocircumflex 0x0d4 +#define XK_Otilde 0x0d5 +#define XK_Odiaeresis 0x0d6 +#define XK_multiply 0x0d7 +#define XK_Ooblique 0x0d8 +#define XK_Ugrave 0x0d9 +#define XK_Uacute 0x0da +#define XK_Ucircumflex 0x0db +#define XK_Udiaeresis 0x0dc +#define XK_Yacute 0x0dd +#define XK_THORN 0x0de +#define XK_Thorn 0x0de /* deprecated */ +#define XK_ssharp 0x0df +#define XK_agrave 0x0e0 +#define XK_aacute 0x0e1 +#define XK_acircumflex 0x0e2 +#define XK_atilde 0x0e3 +#define XK_adiaeresis 0x0e4 +#define XK_aring 0x0e5 +#define XK_ae 0x0e6 +#define XK_ccedilla 0x0e7 +#define XK_egrave 0x0e8 +#define XK_eacute 0x0e9 +#define XK_ecircumflex 0x0ea +#define XK_ediaeresis 0x0eb +#define XK_igrave 0x0ec +#define XK_iacute 0x0ed +#define XK_icircumflex 0x0ee +#define XK_idiaeresis 0x0ef +#define XK_eth 0x0f0 +#define XK_ntilde 0x0f1 +#define XK_ograve 0x0f2 +#define XK_oacute 0x0f3 +#define XK_ocircumflex 0x0f4 +#define XK_otilde 0x0f5 +#define XK_odiaeresis 0x0f6 +#define XK_division 0x0f7 +#define XK_oslash 0x0f8 +#define XK_ugrave 0x0f9 +#define XK_uacute 0x0fa +#define XK_ucircumflex 0x0fb +#define XK_udiaeresis 0x0fc +#define XK_yacute 0x0fd +#define XK_thorn 0x0fe +#define XK_ydiaeresis 0x0ff +#endif /* XK_LATIN1 */ + +/* + * Latin 2 + * Byte 3 = 1 + */ + +#ifdef XK_LATIN2 +#define XK_Aogonek 0x1a1 +#define XK_breve 0x1a2 +#define XK_Lstroke 0x1a3 +#define XK_Lcaron 0x1a5 +#define XK_Sacute 0x1a6 +#define XK_Scaron 0x1a9 +#define XK_Scedilla 0x1aa +#define XK_Tcaron 0x1ab +#define XK_Zacute 0x1ac +#define XK_Zcaron 0x1ae +#define XK_Zabovedot 0x1af +#define XK_aogonek 0x1b1 +#define XK_ogonek 0x1b2 +#define XK_lstroke 0x1b3 +#define XK_lcaron 0x1b5 +#define XK_sacute 0x1b6 +#define XK_caron 0x1b7 +#define XK_scaron 0x1b9 +#define XK_scedilla 0x1ba +#define XK_tcaron 0x1bb +#define XK_zacute 0x1bc +#define XK_doubleacute 0x1bd +#define XK_zcaron 0x1be +#define XK_zabovedot 0x1bf +#define XK_Racute 0x1c0 +#define XK_Abreve 0x1c3 +#define XK_Lacute 0x1c5 +#define XK_Cacute 0x1c6 +#define XK_Ccaron 0x1c8 +#define XK_Eogonek 0x1ca +#define XK_Ecaron 0x1cc +#define XK_Dcaron 0x1cf +#define XK_Dstroke 0x1d0 +#define XK_Nacute 0x1d1 +#define XK_Ncaron 0x1d2 +#define XK_Odoubleacute 0x1d5 +#define XK_Rcaron 0x1d8 +#define XK_Uring 0x1d9 +#define XK_Udoubleacute 0x1db +#define XK_Tcedilla 0x1de +#define XK_racute 0x1e0 +#define XK_abreve 0x1e3 +#define XK_lacute 0x1e5 +#define XK_cacute 0x1e6 +#define XK_ccaron 0x1e8 +#define XK_eogonek 0x1ea +#define XK_ecaron 0x1ec +#define XK_dcaron 0x1ef +#define XK_dstroke 0x1f0 +#define XK_nacute 0x1f1 +#define XK_ncaron 0x1f2 +#define XK_odoubleacute 0x1f5 +#define XK_udoubleacute 0x1fb +#define XK_rcaron 0x1f8 +#define XK_uring 0x1f9 +#define XK_tcedilla 0x1fe +#define XK_abovedot 0x1ff +#endif /* XK_LATIN2 */ + +/* + * Latin 3 + * Byte 3 = 2 + */ + +#ifdef XK_LATIN3 +#define XK_Hstroke 0x2a1 +#define XK_Hcircumflex 0x2a6 +#define XK_Iabovedot 0x2a9 +#define XK_Gbreve 0x2ab +#define XK_Jcircumflex 0x2ac +#define XK_hstroke 0x2b1 +#define XK_hcircumflex 0x2b6 +#define XK_idotless 0x2b9 +#define XK_gbreve 0x2bb +#define XK_jcircumflex 0x2bc +#define XK_Cabovedot 0x2c5 +#define XK_Ccircumflex 0x2c6 +#define XK_Gabovedot 0x2d5 +#define XK_Gcircumflex 0x2d8 +#define XK_Ubreve 0x2dd +#define XK_Scircumflex 0x2de +#define XK_cabovedot 0x2e5 +#define XK_ccircumflex 0x2e6 +#define XK_gabovedot 0x2f5 +#define XK_gcircumflex 0x2f8 +#define XK_ubreve 0x2fd +#define XK_scircumflex 0x2fe +#endif /* XK_LATIN3 */ + + +/* + * Latin 4 + * Byte 3 = 3 + */ + +#ifdef XK_LATIN4 +#define XK_kra 0x3a2 +#define XK_kappa 0x3a2 /* deprecated */ +#define XK_Rcedilla 0x3a3 +#define XK_Itilde 0x3a5 +#define XK_Lcedilla 0x3a6 +#define XK_Emacron 0x3aa +#define XK_Gcedilla 0x3ab +#define XK_Tslash 0x3ac +#define XK_rcedilla 0x3b3 +#define XK_itilde 0x3b5 +#define XK_lcedilla 0x3b6 +#define XK_emacron 0x3ba +#define XK_gcedilla 0x3bb +#define XK_tslash 0x3bc +#define XK_ENG 0x3bd +#define XK_eng 0x3bf +#define XK_Amacron 0x3c0 +#define XK_Iogonek 0x3c7 +#define XK_Eabovedot 0x3cc +#define XK_Imacron 0x3cf +#define XK_Ncedilla 0x3d1 +#define XK_Omacron 0x3d2 +#define XK_Kcedilla 0x3d3 +#define XK_Uogonek 0x3d9 +#define XK_Utilde 0x3dd +#define XK_Umacron 0x3de +#define XK_amacron 0x3e0 +#define XK_iogonek 0x3e7 +#define XK_eabovedot 0x3ec +#define XK_imacron 0x3ef +#define XK_ncedilla 0x3f1 +#define XK_omacron 0x3f2 +#define XK_kcedilla 0x3f3 +#define XK_uogonek 0x3f9 +#define XK_utilde 0x3fd +#define XK_umacron 0x3fe +#endif /* XK_LATIN4 */ + +/* + * Katakana + * Byte 3 = 4 + */ + +#ifdef XK_KATAKANA +#define XK_overline 0x47e +#define XK_kana_fullstop 0x4a1 +#define XK_kana_openingbracket 0x4a2 +#define XK_kana_closingbracket 0x4a3 +#define XK_kana_comma 0x4a4 +#define XK_kana_conjunctive 0x4a5 +#define XK_kana_middledot 0x4a5 /* deprecated */ +#define XK_kana_WO 0x4a6 +#define XK_kana_a 0x4a7 +#define XK_kana_i 0x4a8 +#define XK_kana_u 0x4a9 +#define XK_kana_e 0x4aa +#define XK_kana_o 0x4ab +#define XK_kana_ya 0x4ac +#define XK_kana_yu 0x4ad +#define XK_kana_yo 0x4ae +#define XK_kana_tsu 0x4af +#define XK_kana_tu 0x4af /* deprecated */ +#define XK_prolongedsound 0x4b0 +#define XK_kana_A 0x4b1 +#define XK_kana_I 0x4b2 +#define XK_kana_U 0x4b3 +#define XK_kana_E 0x4b4 +#define XK_kana_O 0x4b5 +#define XK_kana_KA 0x4b6 +#define XK_kana_KI 0x4b7 +#define XK_kana_KU 0x4b8 +#define XK_kana_KE 0x4b9 +#define XK_kana_KO 0x4ba +#define XK_kana_SA 0x4bb +#define XK_kana_SHI 0x4bc +#define XK_kana_SU 0x4bd +#define XK_kana_SE 0x4be +#define XK_kana_SO 0x4bf +#define XK_kana_TA 0x4c0 +#define XK_kana_CHI 0x4c1 +#define XK_kana_TI 0x4c1 /* deprecated */ +#define XK_kana_TSU 0x4c2 +#define XK_kana_TU 0x4c2 /* deprecated */ +#define XK_kana_TE 0x4c3 +#define XK_kana_TO 0x4c4 +#define XK_kana_NA 0x4c5 +#define XK_kana_NI 0x4c6 +#define XK_kana_NU 0x4c7 +#define XK_kana_NE 0x4c8 +#define XK_kana_NO 0x4c9 +#define XK_kana_HA 0x4ca +#define XK_kana_HI 0x4cb +#define XK_kana_FU 0x4cc +#define XK_kana_HU 0x4cc /* deprecated */ +#define XK_kana_HE 0x4cd +#define XK_kana_HO 0x4ce +#define XK_kana_MA 0x4cf +#define XK_kana_MI 0x4d0 +#define XK_kana_MU 0x4d1 +#define XK_kana_ME 0x4d2 +#define XK_kana_MO 0x4d3 +#define XK_kana_YA 0x4d4 +#define XK_kana_YU 0x4d5 +#define XK_kana_YO 0x4d6 +#define XK_kana_RA 0x4d7 +#define XK_kana_RI 0x4d8 +#define XK_kana_RU 0x4d9 +#define XK_kana_RE 0x4da +#define XK_kana_RO 0x4db +#define XK_kana_WA 0x4dc +#define XK_kana_N 0x4dd +#define XK_voicedsound 0x4de +#define XK_semivoicedsound 0x4df +#define XK_kana_switch 0xFF7E /* Alias for mode_switch */ +#endif /* XK_KATAKANA */ + +/* + * Arabic + * Byte 3 = 5 + */ + +#ifdef XK_ARABIC +#define XK_Arabic_comma 0x5ac +#define XK_Arabic_semicolon 0x5bb +#define XK_Arabic_question_mark 0x5bf +#define XK_Arabic_hamza 0x5c1 +#define XK_Arabic_maddaonalef 0x5c2 +#define XK_Arabic_hamzaonalef 0x5c3 +#define XK_Arabic_hamzaonwaw 0x5c4 +#define XK_Arabic_hamzaunderalef 0x5c5 +#define XK_Arabic_hamzaonyeh 0x5c6 +#define XK_Arabic_alef 0x5c7 +#define XK_Arabic_beh 0x5c8 +#define XK_Arabic_tehmarbuta 0x5c9 +#define XK_Arabic_teh 0x5ca +#define XK_Arabic_theh 0x5cb +#define XK_Arabic_jeem 0x5cc +#define XK_Arabic_hah 0x5cd +#define XK_Arabic_khah 0x5ce +#define XK_Arabic_dal 0x5cf +#define XK_Arabic_thal 0x5d0 +#define XK_Arabic_ra 0x5d1 +#define XK_Arabic_zain 0x5d2 +#define XK_Arabic_seen 0x5d3 +#define XK_Arabic_sheen 0x5d4 +#define XK_Arabic_sad 0x5d5 +#define XK_Arabic_dad 0x5d6 +#define XK_Arabic_tah 0x5d7 +#define XK_Arabic_zah 0x5d8 +#define XK_Arabic_ain 0x5d9 +#define XK_Arabic_ghain 0x5da +#define XK_Arabic_tatweel 0x5e0 +#define XK_Arabic_feh 0x5e1 +#define XK_Arabic_qaf 0x5e2 +#define XK_Arabic_kaf 0x5e3 +#define XK_Arabic_lam 0x5e4 +#define XK_Arabic_meem 0x5e5 +#define XK_Arabic_noon 0x5e6 +#define XK_Arabic_ha 0x5e7 +#define XK_Arabic_heh 0x5e7 /* deprecated */ +#define XK_Arabic_waw 0x5e8 +#define XK_Arabic_alefmaksura 0x5e9 +#define XK_Arabic_yeh 0x5ea +#define XK_Arabic_fathatan 0x5eb +#define XK_Arabic_dammatan 0x5ec +#define XK_Arabic_kasratan 0x5ed +#define XK_Arabic_fatha 0x5ee +#define XK_Arabic_damma 0x5ef +#define XK_Arabic_kasra 0x5f0 +#define XK_Arabic_shadda 0x5f1 +#define XK_Arabic_sukun 0x5f2 +#define XK_Arabic_switch 0xFF7E /* Alias for mode_switch */ +#endif /* XK_ARABIC */ + +/* + * Cyrillic + * Byte 3 = 6 + */ +#ifdef XK_CYRILLIC +#define XK_Serbian_dje 0x6a1 +#define XK_Macedonia_gje 0x6a2 +#define XK_Cyrillic_io 0x6a3 +#define XK_Ukrainian_ie 0x6a4 +#define XK_Ukranian_je 0x6a4 /* deprecated */ +#define XK_Macedonia_dse 0x6a5 +#define XK_Ukrainian_i 0x6a6 +#define XK_Ukranian_i 0x6a6 /* deprecated */ +#define XK_Ukrainian_yi 0x6a7 +#define XK_Ukranian_yi 0x6a7 /* deprecated */ +#define XK_Cyrillic_je 0x6a8 +#define XK_Serbian_je 0x6a8 /* deprecated */ +#define XK_Cyrillic_lje 0x6a9 +#define XK_Serbian_lje 0x6a9 /* deprecated */ +#define XK_Cyrillic_nje 0x6aa +#define XK_Serbian_nje 0x6aa /* deprecated */ +#define XK_Serbian_tshe 0x6ab +#define XK_Macedonia_kje 0x6ac +#define XK_Byelorussian_shortu 0x6ae +#define XK_Cyrillic_dzhe 0x6af +#define XK_Serbian_dze 0x6af /* deprecated */ +#define XK_numerosign 0x6b0 +#define XK_Serbian_DJE 0x6b1 +#define XK_Macedonia_GJE 0x6b2 +#define XK_Cyrillic_IO 0x6b3 +#define XK_Ukrainian_IE 0x6b4 +#define XK_Ukranian_JE 0x6b4 /* deprecated */ +#define XK_Macedonia_DSE 0x6b5 +#define XK_Ukrainian_I 0x6b6 +#define XK_Ukranian_I 0x6b6 /* deprecated */ +#define XK_Ukrainian_YI 0x6b7 +#define XK_Ukranian_YI 0x6b7 /* deprecated */ +#define XK_Cyrillic_JE 0x6b8 +#define XK_Serbian_JE 0x6b8 /* deprecated */ +#define XK_Cyrillic_LJE 0x6b9 +#define XK_Serbian_LJE 0x6b9 /* deprecated */ +#define XK_Cyrillic_NJE 0x6ba +#define XK_Serbian_NJE 0x6ba /* deprecated */ +#define XK_Serbian_TSHE 0x6bb +#define XK_Macedonia_KJE 0x6bc +#define XK_Byelorussian_SHORTU 0x6be +#define XK_Cyrillic_DZHE 0x6bf +#define XK_Serbian_DZE 0x6bf /* deprecated */ +#define XK_Cyrillic_yu 0x6c0 +#define XK_Cyrillic_a 0x6c1 +#define XK_Cyrillic_be 0x6c2 +#define XK_Cyrillic_tse 0x6c3 +#define XK_Cyrillic_de 0x6c4 +#define XK_Cyrillic_ie 0x6c5 +#define XK_Cyrillic_ef 0x6c6 +#define XK_Cyrillic_ghe 0x6c7 +#define XK_Cyrillic_ha 0x6c8 +#define XK_Cyrillic_i 0x6c9 +#define XK_Cyrillic_shorti 0x6ca +#define XK_Cyrillic_ka 0x6cb +#define XK_Cyrillic_el 0x6cc +#define XK_Cyrillic_em 0x6cd +#define XK_Cyrillic_en 0x6ce +#define XK_Cyrillic_o 0x6cf +#define XK_Cyrillic_pe 0x6d0 +#define XK_Cyrillic_ya 0x6d1 +#define XK_Cyrillic_er 0x6d2 +#define XK_Cyrillic_es 0x6d3 +#define XK_Cyrillic_te 0x6d4 +#define XK_Cyrillic_u 0x6d5 +#define XK_Cyrillic_zhe 0x6d6 +#define XK_Cyrillic_ve 0x6d7 +#define XK_Cyrillic_softsign 0x6d8 +#define XK_Cyrillic_yeru 0x6d9 +#define XK_Cyrillic_ze 0x6da +#define XK_Cyrillic_sha 0x6db +#define XK_Cyrillic_e 0x6dc +#define XK_Cyrillic_shcha 0x6dd +#define XK_Cyrillic_che 0x6de +#define XK_Cyrillic_hardsign 0x6df +#define XK_Cyrillic_YU 0x6e0 +#define XK_Cyrillic_A 0x6e1 +#define XK_Cyrillic_BE 0x6e2 +#define XK_Cyrillic_TSE 0x6e3 +#define XK_Cyrillic_DE 0x6e4 +#define XK_Cyrillic_IE 0x6e5 +#define XK_Cyrillic_EF 0x6e6 +#define XK_Cyrillic_GHE 0x6e7 +#define XK_Cyrillic_HA 0x6e8 +#define XK_Cyrillic_I 0x6e9 +#define XK_Cyrillic_SHORTI 0x6ea +#define XK_Cyrillic_KA 0x6eb +#define XK_Cyrillic_EL 0x6ec +#define XK_Cyrillic_EM 0x6ed +#define XK_Cyrillic_EN 0x6ee +#define XK_Cyrillic_O 0x6ef +#define XK_Cyrillic_PE 0x6f0 +#define XK_Cyrillic_YA 0x6f1 +#define XK_Cyrillic_ER 0x6f2 +#define XK_Cyrillic_ES 0x6f3 +#define XK_Cyrillic_TE 0x6f4 +#define XK_Cyrillic_U 0x6f5 +#define XK_Cyrillic_ZHE 0x6f6 +#define XK_Cyrillic_VE 0x6f7 +#define XK_Cyrillic_SOFTSIGN 0x6f8 +#define XK_Cyrillic_YERU 0x6f9 +#define XK_Cyrillic_ZE 0x6fa +#define XK_Cyrillic_SHA 0x6fb +#define XK_Cyrillic_E 0x6fc +#define XK_Cyrillic_SHCHA 0x6fd +#define XK_Cyrillic_CHE 0x6fe +#define XK_Cyrillic_HARDSIGN 0x6ff +#endif /* XK_CYRILLIC */ + +/* + * Greek + * Byte 3 = 7 + */ + +#ifdef XK_GREEK +#define XK_Greek_ALPHAaccent 0x7a1 +#define XK_Greek_EPSILONaccent 0x7a2 +#define XK_Greek_ETAaccent 0x7a3 +#define XK_Greek_IOTAaccent 0x7a4 +#define XK_Greek_IOTAdiaeresis 0x7a5 +#define XK_Greek_OMICRONaccent 0x7a7 +#define XK_Greek_UPSILONaccent 0x7a8 +#define XK_Greek_UPSILONdieresis 0x7a9 +#define XK_Greek_OMEGAaccent 0x7ab +#define XK_Greek_accentdieresis 0x7ae +#define XK_Greek_horizbar 0x7af +#define XK_Greek_alphaaccent 0x7b1 +#define XK_Greek_epsilonaccent 0x7b2 +#define XK_Greek_etaaccent 0x7b3 +#define XK_Greek_iotaaccent 0x7b4 +#define XK_Greek_iotadieresis 0x7b5 +#define XK_Greek_iotaaccentdieresis 0x7b6 +#define XK_Greek_omicronaccent 0x7b7 +#define XK_Greek_upsilonaccent 0x7b8 +#define XK_Greek_upsilondieresis 0x7b9 +#define XK_Greek_upsilonaccentdieresis 0x7ba +#define XK_Greek_omegaaccent 0x7bb +#define XK_Greek_ALPHA 0x7c1 +#define XK_Greek_BETA 0x7c2 +#define XK_Greek_GAMMA 0x7c3 +#define XK_Greek_DELTA 0x7c4 +#define XK_Greek_EPSILON 0x7c5 +#define XK_Greek_ZETA 0x7c6 +#define XK_Greek_ETA 0x7c7 +#define XK_Greek_THETA 0x7c8 +#define XK_Greek_IOTA 0x7c9 +#define XK_Greek_KAPPA 0x7ca +#define XK_Greek_LAMDA 0x7cb +#define XK_Greek_LAMBDA 0x7cb +#define XK_Greek_MU 0x7cc +#define XK_Greek_NU 0x7cd +#define XK_Greek_XI 0x7ce +#define XK_Greek_OMICRON 0x7cf +#define XK_Greek_PI 0x7d0 +#define XK_Greek_RHO 0x7d1 +#define XK_Greek_SIGMA 0x7d2 +#define XK_Greek_TAU 0x7d4 +#define XK_Greek_UPSILON 0x7d5 +#define XK_Greek_PHI 0x7d6 +#define XK_Greek_CHI 0x7d7 +#define XK_Greek_PSI 0x7d8 +#define XK_Greek_OMEGA 0x7d9 +#define XK_Greek_alpha 0x7e1 +#define XK_Greek_beta 0x7e2 +#define XK_Greek_gamma 0x7e3 +#define XK_Greek_delta 0x7e4 +#define XK_Greek_epsilon 0x7e5 +#define XK_Greek_zeta 0x7e6 +#define XK_Greek_eta 0x7e7 +#define XK_Greek_theta 0x7e8 +#define XK_Greek_iota 0x7e9 +#define XK_Greek_kappa 0x7ea +#define XK_Greek_lamda 0x7eb +#define XK_Greek_lambda 0x7eb +#define XK_Greek_mu 0x7ec +#define XK_Greek_nu 0x7ed +#define XK_Greek_xi 0x7ee +#define XK_Greek_omicron 0x7ef +#define XK_Greek_pi 0x7f0 +#define XK_Greek_rho 0x7f1 +#define XK_Greek_sigma 0x7f2 +#define XK_Greek_finalsmallsigma 0x7f3 +#define XK_Greek_tau 0x7f4 +#define XK_Greek_upsilon 0x7f5 +#define XK_Greek_phi 0x7f6 +#define XK_Greek_chi 0x7f7 +#define XK_Greek_psi 0x7f8 +#define XK_Greek_omega 0x7f9 +#define XK_Greek_switch 0xFF7E /* Alias for mode_switch */ +#endif /* XK_GREEK */ + +/* + * Technical + * Byte 3 = 8 + */ + +#ifdef XK_TECHNICAL +#define XK_leftradical 0x8a1 +#define XK_topleftradical 0x8a2 +#define XK_horizconnector 0x8a3 +#define XK_topintegral 0x8a4 +#define XK_botintegral 0x8a5 +#define XK_vertconnector 0x8a6 +#define XK_topleftsqbracket 0x8a7 +#define XK_botleftsqbracket 0x8a8 +#define XK_toprightsqbracket 0x8a9 +#define XK_botrightsqbracket 0x8aa +#define XK_topleftparens 0x8ab +#define XK_botleftparens 0x8ac +#define XK_toprightparens 0x8ad +#define XK_botrightparens 0x8ae +#define XK_leftmiddlecurlybrace 0x8af +#define XK_rightmiddlecurlybrace 0x8b0 +#define XK_topleftsummation 0x8b1 +#define XK_botleftsummation 0x8b2 +#define XK_topvertsummationconnector 0x8b3 +#define XK_botvertsummationconnector 0x8b4 +#define XK_toprightsummation 0x8b5 +#define XK_botrightsummation 0x8b6 +#define XK_rightmiddlesummation 0x8b7 +#define XK_lessthanequal 0x8bc +#define XK_notequal 0x8bd +#define XK_greaterthanequal 0x8be +#define XK_integral 0x8bf +#define XK_therefore 0x8c0 +#define XK_variation 0x8c1 +#define XK_infinity 0x8c2 +#define XK_nabla 0x8c5 +#define XK_approximate 0x8c8 +#define XK_similarequal 0x8c9 +#define XK_ifonlyif 0x8cd +#define XK_implies 0x8ce +#define XK_identical 0x8cf +#define XK_radical 0x8d6 +#define XK_includedin 0x8da +#define XK_includes 0x8db +#define XK_intersection 0x8dc +#define XK_union 0x8dd +#define XK_logicaland 0x8de +#define XK_logicalor 0x8df +#define XK_partialderivative 0x8ef +#define XK_function 0x8f6 +#define XK_leftarrow 0x8fb +#define XK_uparrow 0x8fc +#define XK_rightarrow 0x8fd +#define XK_downarrow 0x8fe +#endif /* XK_TECHNICAL */ + +/* + * Special + * Byte 3 = 9 + */ + +#ifdef XK_SPECIAL +#define XK_blank 0x9df +#define XK_soliddiamond 0x9e0 +#define XK_checkerboard 0x9e1 +#define XK_ht 0x9e2 +#define XK_ff 0x9e3 +#define XK_cr 0x9e4 +#define XK_lf 0x9e5 +#define XK_nl 0x9e8 +#define XK_vt 0x9e9 +#define XK_lowrightcorner 0x9ea +#define XK_uprightcorner 0x9eb +#define XK_upleftcorner 0x9ec +#define XK_lowleftcorner 0x9ed +#define XK_crossinglines 0x9ee +#define XK_horizlinescan1 0x9ef +#define XK_horizlinescan3 0x9f0 +#define XK_horizlinescan5 0x9f1 +#define XK_horizlinescan7 0x9f2 +#define XK_horizlinescan9 0x9f3 +#define XK_leftt 0x9f4 +#define XK_rightt 0x9f5 +#define XK_bott 0x9f6 +#define XK_topt 0x9f7 +#define XK_vertbar 0x9f8 +#endif /* XK_SPECIAL */ + +/* + * Publishing + * Byte 3 = a + */ + +#ifdef XK_PUBLISHING +#define XK_emspace 0xaa1 +#define XK_enspace 0xaa2 +#define XK_em3space 0xaa3 +#define XK_em4space 0xaa4 +#define XK_digitspace 0xaa5 +#define XK_punctspace 0xaa6 +#define XK_thinspace 0xaa7 +#define XK_hairspace 0xaa8 +#define XK_emdash 0xaa9 +#define XK_endash 0xaaa +#define XK_signifblank 0xaac +#define XK_ellipsis 0xaae +#define XK_doubbaselinedot 0xaaf +#define XK_onethird 0xab0 +#define XK_twothirds 0xab1 +#define XK_onefifth 0xab2 +#define XK_twofifths 0xab3 +#define XK_threefifths 0xab4 +#define XK_fourfifths 0xab5 +#define XK_onesixth 0xab6 +#define XK_fivesixths 0xab7 +#define XK_careof 0xab8 +#define XK_figdash 0xabb +#define XK_leftanglebracket 0xabc +#define XK_decimalpoint 0xabd +#define XK_rightanglebracket 0xabe +#define XK_marker 0xabf +#define XK_oneeighth 0xac3 +#define XK_threeeighths 0xac4 +#define XK_fiveeighths 0xac5 +#define XK_seveneighths 0xac6 +#define XK_trademark 0xac9 +#define XK_signaturemark 0xaca +#define XK_trademarkincircle 0xacb +#define XK_leftopentriangle 0xacc +#define XK_rightopentriangle 0xacd +#define XK_emopencircle 0xace +#define XK_emopenrectangle 0xacf +#define XK_leftsinglequotemark 0xad0 +#define XK_rightsinglequotemark 0xad1 +#define XK_leftdoublequotemark 0xad2 +#define XK_rightdoublequotemark 0xad3 +#define XK_prescription 0xad4 +#define XK_minutes 0xad6 +#define XK_seconds 0xad7 +#define XK_latincross 0xad9 +#define XK_hexagram 0xada +#define XK_filledrectbullet 0xadb +#define XK_filledlefttribullet 0xadc +#define XK_filledrighttribullet 0xadd +#define XK_emfilledcircle 0xade +#define XK_emfilledrect 0xadf +#define XK_enopencircbullet 0xae0 +#define XK_enopensquarebullet 0xae1 +#define XK_openrectbullet 0xae2 +#define XK_opentribulletup 0xae3 +#define XK_opentribulletdown 0xae4 +#define XK_openstar 0xae5 +#define XK_enfilledcircbullet 0xae6 +#define XK_enfilledsqbullet 0xae7 +#define XK_filledtribulletup 0xae8 +#define XK_filledtribulletdown 0xae9 +#define XK_leftpointer 0xaea +#define XK_rightpointer 0xaeb +#define XK_club 0xaec +#define XK_diamond 0xaed +#define XK_heart 0xaee +#define XK_maltesecross 0xaf0 +#define XK_dagger 0xaf1 +#define XK_doubledagger 0xaf2 +#define XK_checkmark 0xaf3 +#define XK_ballotcross 0xaf4 +#define XK_musicalsharp 0xaf5 +#define XK_musicalflat 0xaf6 +#define XK_malesymbol 0xaf7 +#define XK_femalesymbol 0xaf8 +#define XK_telephone 0xaf9 +#define XK_telephonerecorder 0xafa +#define XK_phonographcopyright 0xafb +#define XK_caret 0xafc +#define XK_singlelowquotemark 0xafd +#define XK_doublelowquotemark 0xafe +#define XK_cursor 0xaff +#endif /* XK_PUBLISHING */ + +/* + * APL + * Byte 3 = b + */ + +#ifdef XK_APL +#define XK_leftcaret 0xba3 +#define XK_rightcaret 0xba6 +#define XK_downcaret 0xba8 +#define XK_upcaret 0xba9 +#define XK_overbar 0xbc0 +#define XK_downtack 0xbc2 +#define XK_upshoe 0xbc3 +#define XK_downstile 0xbc4 +#define XK_underbar 0xbc6 +#define XK_jot 0xbca +#define XK_quad 0xbcc +#define XK_uptack 0xbce +#define XK_circle 0xbcf +#define XK_upstile 0xbd3 +#define XK_downshoe 0xbd6 +#define XK_rightshoe 0xbd8 +#define XK_leftshoe 0xbda +#define XK_lefttack 0xbdc +#define XK_righttack 0xbfc +#endif /* XK_APL */ + +/* + * Hebrew + * Byte 3 = c + */ + +#ifdef XK_HEBREW +#define XK_hebrew_doublelowline 0xcdf +#define XK_hebrew_aleph 0xce0 +#define XK_hebrew_bet 0xce1 +#define XK_hebrew_beth 0xce1 /* deprecated */ +#define XK_hebrew_gimel 0xce2 +#define XK_hebrew_gimmel 0xce2 /* deprecated */ +#define XK_hebrew_dalet 0xce3 +#define XK_hebrew_daleth 0xce3 /* deprecated */ +#define XK_hebrew_he 0xce4 +#define XK_hebrew_waw 0xce5 +#define XK_hebrew_zain 0xce6 +#define XK_hebrew_zayin 0xce6 /* deprecated */ +#define XK_hebrew_chet 0xce7 +#define XK_hebrew_het 0xce7 /* deprecated */ +#define XK_hebrew_tet 0xce8 +#define XK_hebrew_teth 0xce8 /* deprecated */ +#define XK_hebrew_yod 0xce9 +#define XK_hebrew_finalkaph 0xcea +#define XK_hebrew_kaph 0xceb +#define XK_hebrew_lamed 0xcec +#define XK_hebrew_finalmem 0xced +#define XK_hebrew_mem 0xcee +#define XK_hebrew_finalnun 0xcef +#define XK_hebrew_nun 0xcf0 +#define XK_hebrew_samech 0xcf1 +#define XK_hebrew_samekh 0xcf1 /* deprecated */ +#define XK_hebrew_ayin 0xcf2 +#define XK_hebrew_finalpe 0xcf3 +#define XK_hebrew_pe 0xcf4 +#define XK_hebrew_finalzade 0xcf5 +#define XK_hebrew_finalzadi 0xcf5 /* deprecated */ +#define XK_hebrew_zade 0xcf6 +#define XK_hebrew_zadi 0xcf6 /* deprecated */ +#define XK_hebrew_qoph 0xcf7 +#define XK_hebrew_kuf 0xcf7 /* deprecated */ +#define XK_hebrew_resh 0xcf8 +#define XK_hebrew_shin 0xcf9 +#define XK_hebrew_taw 0xcfa +#define XK_hebrew_taf 0xcfa /* deprecated */ +#define XK_Hebrew_switch 0xFF7E /* Alias for mode_switch */ +#endif /* XK_HEBREW */ + diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/tkIntXlibDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/tkIntXlibDecls.h new file mode 100644 index 00000000..6ac7ccbd --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/X11/tkIntXlibDecls.h @@ -0,0 +1,1279 @@ +/* + * tkIntXlibDecls.h -- + * + * This file contains the declarations for all platform dependent + * unsupported functions that are exported by the Tk 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 _TKINTXLIBDECLS +#define _TKINTXLIBDECLS + +/* + * 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/tkInt.decls script. + */ + +#ifndef _TCL +# include +#endif + +#include "X11/Xutil.h" + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +typedef int (*XAfterFunction) ( /* WARNING, this type not in Xlib spec */ + Display* /* display */ +); + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +/* 0 */ +EXTERN int XSetDashes(Display *display, GC gc, int dash_offset, + _Xconst char *dash_list, int n); +/* 1 */ +EXTERN XModifierKeymap * XGetModifierMapping(Display *d); +/* 2 */ +EXTERN XImage * XCreateImage(Display *d, Visual *v, unsigned int ui1, + int i1, int i2, char *cp, unsigned int ui2, + unsigned int ui3, int i3, int i4); +/* 3 */ +EXTERN XImage * XGetImage(Display *d, Drawable dr, int i1, int i2, + unsigned int ui1, unsigned int ui2, + unsigned long ul, int i3); +/* 4 */ +EXTERN char * XGetAtomName(Display *d, Atom a); +/* 5 */ +EXTERN char * XKeysymToString(KeySym k); +/* 6 */ +EXTERN Colormap XCreateColormap(Display *d, Window w, Visual *v, + int i); +/* 7 */ +EXTERN Cursor XCreatePixmapCursor(Display *d, Pixmap p1, Pixmap p2, + XColor *x1, XColor *x2, unsigned int ui1, + unsigned int ui2); +/* 8 */ +EXTERN Cursor XCreateGlyphCursor(Display *d, Font f1, Font f2, + unsigned int ui1, unsigned int ui2, + XColor _Xconst *x1, XColor _Xconst *x2); +/* 9 */ +EXTERN GContext XGContextFromGC(GC g); +/* 10 */ +EXTERN XHostAddress * XListHosts(Display *d, int *i, Bool *b); +/* 11 */ +EXTERN KeySym XKeycodeToKeysym(Display *d, unsigned int k, int i); +/* 12 */ +EXTERN KeySym XStringToKeysym(_Xconst char *c); +/* 13 */ +EXTERN Window XRootWindow(Display *d, int i); +/* 14 */ +EXTERN XErrorHandler XSetErrorHandler(XErrorHandler x); +/* 15 */ +EXTERN Status XIconifyWindow(Display *d, Window w, int i); +/* 16 */ +EXTERN Status XWithdrawWindow(Display *d, Window w, int i); +/* 17 */ +EXTERN Status XGetWMColormapWindows(Display *d, Window w, + Window **wpp, int *ip); +/* 18 */ +EXTERN Status XAllocColor(Display *d, Colormap c, XColor *xp); +/* 19 */ +EXTERN int XBell(Display *d, int i); +/* 20 */ +EXTERN int XChangeProperty(Display *d, Window w, Atom a1, + Atom a2, int i1, int i2, + _Xconst unsigned char *c, int i3); +/* 21 */ +EXTERN int XChangeWindowAttributes(Display *d, Window w, + unsigned long ul, XSetWindowAttributes *x); +/* 22 */ +EXTERN int XClearWindow(Display *d, Window w); +/* 23 */ +EXTERN int XConfigureWindow(Display *d, Window w, + unsigned int i, XWindowChanges *x); +/* 24 */ +EXTERN int XCopyArea(Display *d, Drawable dr1, Drawable dr2, + GC g, int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4); +/* 25 */ +EXTERN int XCopyPlane(Display *d, Drawable dr1, Drawable dr2, + GC g, int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4, + unsigned long ul); +/* 26 */ +EXTERN Pixmap XCreateBitmapFromData(Display *display, Drawable d, + _Xconst char *data, unsigned int width, + unsigned int height); +/* 27 */ +EXTERN int XDefineCursor(Display *d, Window w, Cursor c); +/* 28 */ +EXTERN int XDeleteProperty(Display *d, Window w, Atom a); +/* 29 */ +EXTERN int XDestroyWindow(Display *d, Window w); +/* 30 */ +EXTERN int XDrawArc(Display *d, Drawable dr, GC g, int i1, + int i2, unsigned int ui1, unsigned int ui2, + int i3, int i4); +/* 31 */ +EXTERN int XDrawLines(Display *d, Drawable dr, GC g, XPoint *x, + int i1, int i2); +/* 32 */ +EXTERN int XDrawRectangle(Display *d, Drawable dr, GC g, int i1, + int i2, unsigned int ui1, unsigned int ui2); +/* 33 */ +EXTERN int XFillArc(Display *d, Drawable dr, GC g, int i1, + int i2, unsigned int ui1, unsigned int ui2, + int i3, int i4); +/* 34 */ +EXTERN int XFillPolygon(Display *d, Drawable dr, GC g, + XPoint *x, int i1, int i2, int i3); +/* 35 */ +EXTERN int XFillRectangles(Display *d, Drawable dr, GC g, + XRectangle *x, int i); +/* 36 */ +EXTERN int XForceScreenSaver(Display *d, int i); +/* 37 */ +EXTERN int XFreeColormap(Display *d, Colormap c); +/* 38 */ +EXTERN int XFreeColors(Display *d, Colormap c, + unsigned long *ulp, int i, unsigned long ul); +/* 39 */ +EXTERN int XFreeCursor(Display *d, Cursor c); +/* 40 */ +EXTERN int XFreeModifiermap(XModifierKeymap *x); +/* 41 */ +EXTERN Status XGetGeometry(Display *d, Drawable dr, Window *w, + int *i1, int *i2, unsigned int *ui1, + unsigned int *ui2, unsigned int *ui3, + unsigned int *ui4); +/* 42 */ +EXTERN int XGetInputFocus(Display *d, Window *w, int *i); +/* 43 */ +EXTERN int XGetWindowProperty(Display *d, Window w, Atom a1, + long l1, long l2, Bool b, Atom a2, Atom *ap, + int *ip, unsigned long *ulp1, + unsigned long *ulp2, unsigned char **cpp); +/* 44 */ +EXTERN Status XGetWindowAttributes(Display *d, Window w, + XWindowAttributes *x); +/* 45 */ +EXTERN int XGrabKeyboard(Display *d, Window w, Bool b, int i1, + int i2, Time t); +/* 46 */ +EXTERN int XGrabPointer(Display *d, Window w1, Bool b, + unsigned int ui, int i1, int i2, Window w2, + Cursor c, Time t); +/* 47 */ +EXTERN KeyCode XKeysymToKeycode(Display *d, KeySym k); +/* 48 */ +EXTERN Status XLookupColor(Display *d, Colormap c1, + _Xconst char *c2, XColor *x1, XColor *x2); +/* 49 */ +EXTERN int XMapWindow(Display *d, Window w); +/* 50 */ +EXTERN int XMoveResizeWindow(Display *d, Window w, int i1, + int i2, unsigned int ui1, unsigned int ui2); +/* 51 */ +EXTERN int XMoveWindow(Display *d, Window w, int i1, int i2); +/* 52 */ +EXTERN int XNextEvent(Display *d, XEvent *x); +/* 53 */ +EXTERN int XPutBackEvent(Display *d, XEvent *x); +/* 54 */ +EXTERN int XQueryColors(Display *d, Colormap c, XColor *x, + int i); +/* 55 */ +EXTERN Bool XQueryPointer(Display *d, Window w1, Window *w2, + Window *w3, int *i1, int *i2, int *i3, + int *i4, unsigned int *ui); +/* 56 */ +EXTERN Status XQueryTree(Display *d, Window w1, Window *w2, + Window *w3, Window **w4, unsigned int *ui); +/* 57 */ +EXTERN int XRaiseWindow(Display *d, Window w); +/* 58 */ +EXTERN int XRefreshKeyboardMapping(XMappingEvent *x); +/* 59 */ +EXTERN int XResizeWindow(Display *d, Window w, unsigned int ui1, + unsigned int ui2); +/* 60 */ +EXTERN int XSelectInput(Display *d, Window w, long l); +/* 61 */ +EXTERN Status XSendEvent(Display *d, Window w, Bool b, long l, + XEvent *x); +/* 62 */ +EXTERN int XSetCommand(Display *d, Window w, char **c, int i); +/* 63 */ +EXTERN int XSetIconName(Display *d, Window w, _Xconst char *c); +/* 64 */ +EXTERN int XSetInputFocus(Display *d, Window w, int i, Time t); +/* 65 */ +EXTERN int XSetSelectionOwner(Display *d, Atom a, Window w, + Time t); +/* 66 */ +EXTERN int XSetWindowBackground(Display *d, Window w, + unsigned long ul); +/* 67 */ +EXTERN int XSetWindowBackgroundPixmap(Display *d, Window w, + Pixmap p); +/* 68 */ +EXTERN int XSetWindowBorder(Display *d, Window w, + unsigned long ul); +/* 69 */ +EXTERN int XSetWindowBorderPixmap(Display *d, Window w, + Pixmap p); +/* 70 */ +EXTERN int XSetWindowBorderWidth(Display *d, Window w, + unsigned int ui); +/* 71 */ +EXTERN int XSetWindowColormap(Display *d, Window w, Colormap c); +/* 72 */ +EXTERN Bool XTranslateCoordinates(Display *d, Window w1, + Window w2, int i1, int i2, int *i3, int *i4, + Window *w3); +/* 73 */ +EXTERN int XUngrabKeyboard(Display *d, Time t); +/* 74 */ +EXTERN int XUngrabPointer(Display *d, Time t); +/* 75 */ +EXTERN int XUnmapWindow(Display *d, Window w); +/* 76 */ +EXTERN int XWindowEvent(Display *d, Window w, long l, XEvent *x); +/* 77 */ +EXTERN void XDestroyIC(XIC x); +/* 78 */ +EXTERN Bool XFilterEvent(XEvent *x, Window w); +/* 79 */ +EXTERN int XmbLookupString(XIC xi, XKeyPressedEvent *xk, + char *c, int i, KeySym *k, Status *s); +/* 80 */ +EXTERN int TkPutImage(unsigned long *colors, int ncolors, + Display *display, Drawable d, GC gc, + XImage *image, int src_x, int src_y, + int dest_x, int dest_y, unsigned int width, + unsigned int height); +/* Slot 81 is reserved */ +/* 82 */ +EXTERN Status XParseColor(Display *display, Colormap map, + _Xconst char *spec, XColor *colorPtr); +/* 83 */ +EXTERN GC XCreateGC(Display *display, Drawable d, + unsigned long valuemask, XGCValues *values); +/* 84 */ +EXTERN int XFreeGC(Display *display, GC gc); +/* 85 */ +EXTERN Atom XInternAtom(Display *display, + _Xconst char *atom_name, Bool only_if_exists); +/* 86 */ +EXTERN int XSetBackground(Display *display, GC gc, + unsigned long foreground); +/* 87 */ +EXTERN int XSetForeground(Display *display, GC gc, + unsigned long foreground); +/* 88 */ +EXTERN int XSetClipMask(Display *display, GC gc, Pixmap pixmap); +/* 89 */ +EXTERN int XSetClipOrigin(Display *display, GC gc, + int clip_x_origin, int clip_y_origin); +/* 90 */ +EXTERN int XSetTSOrigin(Display *display, GC gc, + int ts_x_origin, int ts_y_origin); +/* 91 */ +EXTERN int XChangeGC(Display *d, GC gc, unsigned long mask, + XGCValues *values); +/* 92 */ +EXTERN int XSetFont(Display *display, GC gc, Font font); +/* 93 */ +EXTERN int XSetArcMode(Display *display, GC gc, int arc_mode); +/* 94 */ +EXTERN int XSetStipple(Display *display, GC gc, Pixmap stipple); +/* 95 */ +EXTERN int XSetFillRule(Display *display, GC gc, int fill_rule); +/* 96 */ +EXTERN int XSetFillStyle(Display *display, GC gc, + int fill_style); +/* 97 */ +EXTERN int XSetFunction(Display *display, GC gc, int function); +/* 98 */ +EXTERN int XSetLineAttributes(Display *display, GC gc, + unsigned int line_width, int line_style, + int cap_style, int join_style); +/* 99 */ +EXTERN int _XInitImageFuncPtrs(XImage *image); +/* 100 */ +EXTERN XIC XCreateIC(XIM xim, ...); +/* 101 */ +EXTERN XVisualInfo * XGetVisualInfo(Display *display, long vinfo_mask, + XVisualInfo *vinfo_template, + int *nitems_return); +/* 102 */ +EXTERN void XSetWMClientMachine(Display *display, Window w, + XTextProperty *text_prop); +/* 103 */ +EXTERN Status XStringListToTextProperty(char **list, int count, + XTextProperty *text_prop_return); +/* 104 */ +EXTERN int XDrawLine(Display *d, Drawable dr, GC g, int x1, + int y1, int x2, int y2); +/* 105 */ +EXTERN int XWarpPointer(Display *d, Window s, Window dw, int sx, + int sy, unsigned int sw, unsigned int sh, + int dx, int dy); +/* 106 */ +EXTERN int XFillRectangle(Display *display, Drawable d, GC gc, + int x, int y, unsigned int width, + unsigned int height); +/* 107 */ +EXTERN int XFlush(Display *display); +/* 108 */ +EXTERN int XGrabServer(Display *display); +/* 109 */ +EXTERN int XUngrabServer(Display *display); +/* 110 */ +EXTERN int XFree(void *data); +/* 111 */ +EXTERN int XNoOp(Display *display); +/* 112 */ +EXTERN XAfterFunction XSynchronize(Display *display, Bool onoff); +/* 113 */ +EXTERN int XSync(Display *display, Bool discard); +/* 114 */ +EXTERN VisualID XVisualIDFromVisual(Visual *visual); +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ +/* 0 */ +EXTERN int XSetDashes(Display *display, GC gc, int dash_offset, + _Xconst char *dash_list, int n); +/* 1 */ +EXTERN XModifierKeymap * XGetModifierMapping(Display *d); +/* 2 */ +EXTERN XImage * XCreateImage(Display *d, Visual *v, unsigned int ui1, + int i1, int i2, char *cp, unsigned int ui2, + unsigned int ui3, int i3, int i4); +/* 3 */ +EXTERN XImage * XGetImage(Display *d, Drawable dr, int i1, int i2, + unsigned int ui1, unsigned int ui2, + unsigned long ul, int i3); +/* 4 */ +EXTERN char * XGetAtomName(Display *d, Atom a); +/* 5 */ +EXTERN char * XKeysymToString(KeySym k); +/* 6 */ +EXTERN Colormap XCreateColormap(Display *d, Window w, Visual *v, + int i); +/* 7 */ +EXTERN GContext XGContextFromGC(GC g); +/* 8 */ +EXTERN KeySym XKeycodeToKeysym(Display *d, KeyCode k, int i); +/* 9 */ +EXTERN KeySym XStringToKeysym(_Xconst char *c); +/* 10 */ +EXTERN Window XRootWindow(Display *d, int i); +/* 11 */ +EXTERN XErrorHandler XSetErrorHandler(XErrorHandler x); +/* 12 */ +EXTERN Status XAllocColor(Display *d, Colormap c, XColor *xp); +/* 13 */ +EXTERN int XBell(Display *d, int i); +/* 14 */ +EXTERN void XChangeProperty(Display *d, Window w, Atom a1, + Atom a2, int i1, int i2, + _Xconst unsigned char *c, int i3); +/* 15 */ +EXTERN void XChangeWindowAttributes(Display *d, Window w, + unsigned long ul, XSetWindowAttributes *x); +/* 16 */ +EXTERN void XConfigureWindow(Display *d, Window w, + unsigned int i, XWindowChanges *x); +/* 17 */ +EXTERN void XCopyArea(Display *d, Drawable dr1, Drawable dr2, + GC g, int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4); +/* 18 */ +EXTERN void XCopyPlane(Display *d, Drawable dr1, Drawable dr2, + GC g, int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4, + unsigned long ul); +/* 19 */ +EXTERN Pixmap XCreateBitmapFromData(Display *display, Drawable d, + _Xconst char *data, unsigned int width, + unsigned int height); +/* 20 */ +EXTERN int XDefineCursor(Display *d, Window w, Cursor c); +/* 21 */ +EXTERN void XDestroyWindow(Display *d, Window w); +/* 22 */ +EXTERN void XDrawArc(Display *d, Drawable dr, GC g, int i1, + int i2, unsigned int ui1, unsigned int ui2, + int i3, int i4); +/* 23 */ +EXTERN int XDrawLines(Display *d, Drawable dr, GC g, XPoint *x, + int i1, int i2); +/* 24 */ +EXTERN void XDrawRectangle(Display *d, Drawable dr, GC g, int i1, + int i2, unsigned int ui1, unsigned int ui2); +/* 25 */ +EXTERN void XFillArc(Display *d, Drawable dr, GC g, int i1, + int i2, unsigned int ui1, unsigned int ui2, + int i3, int i4); +/* 26 */ +EXTERN void XFillPolygon(Display *d, Drawable dr, GC g, + XPoint *x, int i1, int i2, int i3); +/* 27 */ +EXTERN int XFillRectangles(Display *d, Drawable dr, GC g, + XRectangle *x, int i); +/* 28 */ +EXTERN int XFreeColormap(Display *d, Colormap c); +/* 29 */ +EXTERN int XFreeColors(Display *d, Colormap c, + unsigned long *ulp, int i, unsigned long ul); +/* 30 */ +EXTERN int XFreeModifiermap(XModifierKeymap *x); +/* 31 */ +EXTERN Status XGetGeometry(Display *d, Drawable dr, Window *w, + int *i1, int *i2, unsigned int *ui1, + unsigned int *ui2, unsigned int *ui3, + unsigned int *ui4); +/* 32 */ +EXTERN int XGetWindowProperty(Display *d, Window w, Atom a1, + long l1, long l2, Bool b, Atom a2, Atom *ap, + int *ip, unsigned long *ulp1, + unsigned long *ulp2, unsigned char **cpp); +/* 33 */ +EXTERN int XGrabKeyboard(Display *d, Window w, Bool b, int i1, + int i2, Time t); +/* 34 */ +EXTERN int XGrabPointer(Display *d, Window w1, Bool b, + unsigned int ui, int i1, int i2, Window w2, + Cursor c, Time t); +/* 35 */ +EXTERN KeyCode XKeysymToKeycode(Display *d, KeySym k); +/* 36 */ +EXTERN void XMapWindow(Display *d, Window w); +/* 37 */ +EXTERN void XMoveResizeWindow(Display *d, Window w, int i1, + int i2, unsigned int ui1, unsigned int ui2); +/* 38 */ +EXTERN void XMoveWindow(Display *d, Window w, int i1, int i2); +/* 39 */ +EXTERN Bool XQueryPointer(Display *d, Window w1, Window *w2, + Window *w3, int *i1, int *i2, int *i3, + int *i4, unsigned int *ui); +/* 40 */ +EXTERN void XRaiseWindow(Display *d, Window w); +/* 41 */ +EXTERN void XRefreshKeyboardMapping(XMappingEvent *x); +/* 42 */ +EXTERN void XResizeWindow(Display *d, Window w, unsigned int ui1, + unsigned int ui2); +/* 43 */ +EXTERN void XSelectInput(Display *d, Window w, long l); +/* 44 */ +EXTERN Status XSendEvent(Display *d, Window w, Bool b, long l, + XEvent *x); +/* 45 */ +EXTERN void XSetIconName(Display *d, Window w, _Xconst char *c); +/* 46 */ +EXTERN void XSetInputFocus(Display *d, Window w, int i, Time t); +/* 47 */ +EXTERN int XSetSelectionOwner(Display *d, Atom a, Window w, + Time t); +/* 48 */ +EXTERN void XSetWindowBackground(Display *d, Window w, + unsigned long ul); +/* 49 */ +EXTERN void XSetWindowBackgroundPixmap(Display *d, Window w, + Pixmap p); +/* 50 */ +EXTERN void XSetWindowBorder(Display *d, Window w, + unsigned long ul); +/* 51 */ +EXTERN void XSetWindowBorderPixmap(Display *d, Window w, + Pixmap p); +/* 52 */ +EXTERN void XSetWindowBorderWidth(Display *d, Window w, + unsigned int ui); +/* 53 */ +EXTERN void XSetWindowColormap(Display *d, Window w, Colormap c); +/* 54 */ +EXTERN void XUngrabKeyboard(Display *d, Time t); +/* 55 */ +EXTERN int XUngrabPointer(Display *d, Time t); +/* 56 */ +EXTERN void XUnmapWindow(Display *d, Window w); +/* 57 */ +EXTERN int TkPutImage(unsigned long *colors, int ncolors, + Display *display, Drawable d, GC gc, + XImage *image, int src_x, int src_y, + int dest_x, int dest_y, unsigned int width, + unsigned int height); +/* 58 */ +EXTERN Status XParseColor(Display *display, Colormap map, + _Xconst char *spec, XColor *colorPtr); +/* 59 */ +EXTERN GC XCreateGC(Display *display, Drawable d, + unsigned long valuemask, XGCValues *values); +/* 60 */ +EXTERN int XFreeGC(Display *display, GC gc); +/* 61 */ +EXTERN Atom XInternAtom(Display *display, + _Xconst char *atom_name, Bool only_if_exists); +/* 62 */ +EXTERN int XSetBackground(Display *display, GC gc, + unsigned long foreground); +/* 63 */ +EXTERN int XSetForeground(Display *display, GC gc, + unsigned long foreground); +/* 64 */ +EXTERN int XSetClipMask(Display *display, GC gc, Pixmap pixmap); +/* 65 */ +EXTERN int XSetClipOrigin(Display *display, GC gc, + int clip_x_origin, int clip_y_origin); +/* 66 */ +EXTERN int XSetTSOrigin(Display *display, GC gc, + int ts_x_origin, int ts_y_origin); +/* 67 */ +EXTERN int XChangeGC(Display *d, GC gc, unsigned long mask, + XGCValues *values); +/* 68 */ +EXTERN int XSetFont(Display *display, GC gc, Font font); +/* 69 */ +EXTERN int XSetArcMode(Display *display, GC gc, int arc_mode); +/* 70 */ +EXTERN int XSetStipple(Display *display, GC gc, Pixmap stipple); +/* 71 */ +EXTERN int XSetFillRule(Display *display, GC gc, int fill_rule); +/* 72 */ +EXTERN int XSetFillStyle(Display *display, GC gc, + int fill_style); +/* 73 */ +EXTERN int XSetFunction(Display *display, GC gc, int function); +/* 74 */ +EXTERN int XSetLineAttributes(Display *display, GC gc, + unsigned int line_width, int line_style, + int cap_style, int join_style); +/* 75 */ +EXTERN int _XInitImageFuncPtrs(XImage *image); +/* 76 */ +EXTERN XIC XCreateIC(void); +/* 77 */ +EXTERN XVisualInfo * XGetVisualInfo(Display *display, long vinfo_mask, + XVisualInfo *vinfo_template, + int *nitems_return); +/* 78 */ +EXTERN void XSetWMClientMachine(Display *display, Window w, + XTextProperty *text_prop); +/* 79 */ +EXTERN Status XStringListToTextProperty(char **list, int count, + XTextProperty *text_prop_return); +/* 80 */ +EXTERN void XDrawSegments(Display *display, Drawable d, GC gc, + XSegment *segments, int nsegments); +/* 81 */ +EXTERN void XForceScreenSaver(Display *display, int mode); +/* 82 */ +EXTERN int XDrawLine(Display *d, Drawable dr, GC g, int x1, + int y1, int x2, int y2); +/* 83 */ +EXTERN int XFillRectangle(Display *display, Drawable d, GC gc, + int x, int y, unsigned int width, + unsigned int height); +/* 84 */ +EXTERN void XClearWindow(Display *d, Window w); +/* 85 */ +EXTERN void XDrawPoint(Display *display, Drawable d, GC gc, + int x, int y); +/* 86 */ +EXTERN void XDrawPoints(Display *display, Drawable d, GC gc, + XPoint *points, int npoints, int mode); +/* 87 */ +EXTERN int XWarpPointer(Display *display, Window src_w, + Window dest_w, int src_x, int src_y, + unsigned int src_width, + unsigned int src_height, int dest_x, + int dest_y); +/* 88 */ +EXTERN void XQueryColor(Display *display, Colormap colormap, + XColor *def_in_out); +/* 89 */ +EXTERN void XQueryColors(Display *display, Colormap colormap, + XColor *defs_in_out, int ncolors); +/* 90 */ +EXTERN Status XQueryTree(Display *d, Window w1, Window *w2, + Window *w3, Window **w4, unsigned int *ui); +/* 91 */ +EXTERN int XSync(Display *display, Bool flag); +#endif /* AQUA */ + +typedef struct TkIntXlibStubs { + int magic; + void *hooks; + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ + int (*xSetDashes) (Display *display, GC gc, int dash_offset, _Xconst char *dash_list, int n); /* 0 */ + XModifierKeymap * (*xGetModifierMapping) (Display *d); /* 1 */ + XImage * (*xCreateImage) (Display *d, Visual *v, unsigned int ui1, int i1, int i2, char *cp, unsigned int ui2, unsigned int ui3, int i3, int i4); /* 2 */ + XImage * (*xGetImage) (Display *d, Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3); /* 3 */ + char * (*xGetAtomName) (Display *d, Atom a); /* 4 */ + char * (*xKeysymToString) (KeySym k); /* 5 */ + Colormap (*xCreateColormap) (Display *d, Window w, Visual *v, int i); /* 6 */ + Cursor (*xCreatePixmapCursor) (Display *d, Pixmap p1, Pixmap p2, XColor *x1, XColor *x2, unsigned int ui1, unsigned int ui2); /* 7 */ + Cursor (*xCreateGlyphCursor) (Display *d, Font f1, Font f2, unsigned int ui1, unsigned int ui2, XColor _Xconst *x1, XColor _Xconst *x2); /* 8 */ + GContext (*xGContextFromGC) (GC g); /* 9 */ + XHostAddress * (*xListHosts) (Display *d, int *i, Bool *b); /* 10 */ + KeySym (*xKeycodeToKeysym) (Display *d, unsigned int k, int i); /* 11 */ + KeySym (*xStringToKeysym) (_Xconst char *c); /* 12 */ + Window (*xRootWindow) (Display *d, int i); /* 13 */ + XErrorHandler (*xSetErrorHandler) (XErrorHandler x); /* 14 */ + Status (*xIconifyWindow) (Display *d, Window w, int i); /* 15 */ + Status (*xWithdrawWindow) (Display *d, Window w, int i); /* 16 */ + Status (*xGetWMColormapWindows) (Display *d, Window w, Window **wpp, int *ip); /* 17 */ + Status (*xAllocColor) (Display *d, Colormap c, XColor *xp); /* 18 */ + int (*xBell) (Display *d, int i); /* 19 */ + int (*xChangeProperty) (Display *d, Window w, Atom a1, Atom a2, int i1, int i2, _Xconst unsigned char *c, int i3); /* 20 */ + int (*xChangeWindowAttributes) (Display *d, Window w, unsigned long ul, XSetWindowAttributes *x); /* 21 */ + int (*xClearWindow) (Display *d, Window w); /* 22 */ + int (*xConfigureWindow) (Display *d, Window w, unsigned int i, XWindowChanges *x); /* 23 */ + int (*xCopyArea) (Display *d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); /* 24 */ + int (*xCopyPlane) (Display *d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4, unsigned long ul); /* 25 */ + Pixmap (*xCreateBitmapFromData) (Display *display, Drawable d, _Xconst char *data, unsigned int width, unsigned int height); /* 26 */ + int (*xDefineCursor) (Display *d, Window w, Cursor c); /* 27 */ + int (*xDeleteProperty) (Display *d, Window w, Atom a); /* 28 */ + int (*xDestroyWindow) (Display *d, Window w); /* 29 */ + int (*xDrawArc) (Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); /* 30 */ + int (*xDrawLines) (Display *d, Drawable dr, GC g, XPoint *x, int i1, int i2); /* 31 */ + int (*xDrawRectangle) (Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2); /* 32 */ + int (*xFillArc) (Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); /* 33 */ + int (*xFillPolygon) (Display *d, Drawable dr, GC g, XPoint *x, int i1, int i2, int i3); /* 34 */ + int (*xFillRectangles) (Display *d, Drawable dr, GC g, XRectangle *x, int i); /* 35 */ + int (*xForceScreenSaver) (Display *d, int i); /* 36 */ + int (*xFreeColormap) (Display *d, Colormap c); /* 37 */ + int (*xFreeColors) (Display *d, Colormap c, unsigned long *ulp, int i, unsigned long ul); /* 38 */ + int (*xFreeCursor) (Display *d, Cursor c); /* 39 */ + int (*xFreeModifiermap) (XModifierKeymap *x); /* 40 */ + Status (*xGetGeometry) (Display *d, Drawable dr, Window *w, int *i1, int *i2, unsigned int *ui1, unsigned int *ui2, unsigned int *ui3, unsigned int *ui4); /* 41 */ + int (*xGetInputFocus) (Display *d, Window *w, int *i); /* 42 */ + int (*xGetWindowProperty) (Display *d, Window w, Atom a1, long l1, long l2, Bool b, Atom a2, Atom *ap, int *ip, unsigned long *ulp1, unsigned long *ulp2, unsigned char **cpp); /* 43 */ + Status (*xGetWindowAttributes) (Display *d, Window w, XWindowAttributes *x); /* 44 */ + int (*xGrabKeyboard) (Display *d, Window w, Bool b, int i1, int i2, Time t); /* 45 */ + int (*xGrabPointer) (Display *d, Window w1, Bool b, unsigned int ui, int i1, int i2, Window w2, Cursor c, Time t); /* 46 */ + KeyCode (*xKeysymToKeycode) (Display *d, KeySym k); /* 47 */ + Status (*xLookupColor) (Display *d, Colormap c1, _Xconst char *c2, XColor *x1, XColor *x2); /* 48 */ + int (*xMapWindow) (Display *d, Window w); /* 49 */ + int (*xMoveResizeWindow) (Display *d, Window w, int i1, int i2, unsigned int ui1, unsigned int ui2); /* 50 */ + int (*xMoveWindow) (Display *d, Window w, int i1, int i2); /* 51 */ + int (*xNextEvent) (Display *d, XEvent *x); /* 52 */ + int (*xPutBackEvent) (Display *d, XEvent *x); /* 53 */ + int (*xQueryColors) (Display *d, Colormap c, XColor *x, int i); /* 54 */ + Bool (*xQueryPointer) (Display *d, Window w1, Window *w2, Window *w3, int *i1, int *i2, int *i3, int *i4, unsigned int *ui); /* 55 */ + Status (*xQueryTree) (Display *d, Window w1, Window *w2, Window *w3, Window **w4, unsigned int *ui); /* 56 */ + int (*xRaiseWindow) (Display *d, Window w); /* 57 */ + int (*xRefreshKeyboardMapping) (XMappingEvent *x); /* 58 */ + int (*xResizeWindow) (Display *d, Window w, unsigned int ui1, unsigned int ui2); /* 59 */ + int (*xSelectInput) (Display *d, Window w, long l); /* 60 */ + Status (*xSendEvent) (Display *d, Window w, Bool b, long l, XEvent *x); /* 61 */ + int (*xSetCommand) (Display *d, Window w, char **c, int i); /* 62 */ + int (*xSetIconName) (Display *d, Window w, _Xconst char *c); /* 63 */ + int (*xSetInputFocus) (Display *d, Window w, int i, Time t); /* 64 */ + int (*xSetSelectionOwner) (Display *d, Atom a, Window w, Time t); /* 65 */ + int (*xSetWindowBackground) (Display *d, Window w, unsigned long ul); /* 66 */ + int (*xSetWindowBackgroundPixmap) (Display *d, Window w, Pixmap p); /* 67 */ + int (*xSetWindowBorder) (Display *d, Window w, unsigned long ul); /* 68 */ + int (*xSetWindowBorderPixmap) (Display *d, Window w, Pixmap p); /* 69 */ + int (*xSetWindowBorderWidth) (Display *d, Window w, unsigned int ui); /* 70 */ + int (*xSetWindowColormap) (Display *d, Window w, Colormap c); /* 71 */ + Bool (*xTranslateCoordinates) (Display *d, Window w1, Window w2, int i1, int i2, int *i3, int *i4, Window *w3); /* 72 */ + int (*xUngrabKeyboard) (Display *d, Time t); /* 73 */ + int (*xUngrabPointer) (Display *d, Time t); /* 74 */ + int (*xUnmapWindow) (Display *d, Window w); /* 75 */ + int (*xWindowEvent) (Display *d, Window w, long l, XEvent *x); /* 76 */ + void (*xDestroyIC) (XIC x); /* 77 */ + Bool (*xFilterEvent) (XEvent *x, Window w); /* 78 */ + int (*xmbLookupString) (XIC xi, XKeyPressedEvent *xk, char *c, int i, KeySym *k, Status *s); /* 79 */ + int (*tkPutImage) (unsigned long *colors, int ncolors, Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height); /* 80 */ + void (*reserved81)(void); + Status (*xParseColor) (Display *display, Colormap map, _Xconst char *spec, XColor *colorPtr); /* 82 */ + GC (*xCreateGC) (Display *display, Drawable d, unsigned long valuemask, XGCValues *values); /* 83 */ + int (*xFreeGC) (Display *display, GC gc); /* 84 */ + Atom (*xInternAtom) (Display *display, _Xconst char *atom_name, Bool only_if_exists); /* 85 */ + int (*xSetBackground) (Display *display, GC gc, unsigned long foreground); /* 86 */ + int (*xSetForeground) (Display *display, GC gc, unsigned long foreground); /* 87 */ + int (*xSetClipMask) (Display *display, GC gc, Pixmap pixmap); /* 88 */ + int (*xSetClipOrigin) (Display *display, GC gc, int clip_x_origin, int clip_y_origin); /* 89 */ + int (*xSetTSOrigin) (Display *display, GC gc, int ts_x_origin, int ts_y_origin); /* 90 */ + int (*xChangeGC) (Display *d, GC gc, unsigned long mask, XGCValues *values); /* 91 */ + int (*xSetFont) (Display *display, GC gc, Font font); /* 92 */ + int (*xSetArcMode) (Display *display, GC gc, int arc_mode); /* 93 */ + int (*xSetStipple) (Display *display, GC gc, Pixmap stipple); /* 94 */ + int (*xSetFillRule) (Display *display, GC gc, int fill_rule); /* 95 */ + int (*xSetFillStyle) (Display *display, GC gc, int fill_style); /* 96 */ + int (*xSetFunction) (Display *display, GC gc, int function); /* 97 */ + int (*xSetLineAttributes) (Display *display, GC gc, unsigned int line_width, int line_style, int cap_style, int join_style); /* 98 */ + int (*_XInitImageFuncPtrs) (XImage *image); /* 99 */ + XIC (*xCreateIC) (XIM xim, ...); /* 100 */ + XVisualInfo * (*xGetVisualInfo) (Display *display, long vinfo_mask, XVisualInfo *vinfo_template, int *nitems_return); /* 101 */ + void (*xSetWMClientMachine) (Display *display, Window w, XTextProperty *text_prop); /* 102 */ + Status (*xStringListToTextProperty) (char **list, int count, XTextProperty *text_prop_return); /* 103 */ + int (*xDrawLine) (Display *d, Drawable dr, GC g, int x1, int y1, int x2, int y2); /* 104 */ + int (*xWarpPointer) (Display *d, Window s, Window dw, int sx, int sy, unsigned int sw, unsigned int sh, int dx, int dy); /* 105 */ + int (*xFillRectangle) (Display *display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height); /* 106 */ + int (*xFlush) (Display *display); /* 107 */ + int (*xGrabServer) (Display *display); /* 108 */ + int (*xUngrabServer) (Display *display); /* 109 */ + int (*xFree) (void *data); /* 110 */ + int (*xNoOp) (Display *display); /* 111 */ + XAfterFunction (*xSynchronize) (Display *display, Bool onoff); /* 112 */ + int (*xSync) (Display *display, Bool discard); /* 113 */ + VisualID (*xVisualIDFromVisual) (Visual *visual); /* 114 */ +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ + int (*xSetDashes) (Display *display, GC gc, int dash_offset, _Xconst char *dash_list, int n); /* 0 */ + XModifierKeymap * (*xGetModifierMapping) (Display *d); /* 1 */ + XImage * (*xCreateImage) (Display *d, Visual *v, unsigned int ui1, int i1, int i2, char *cp, unsigned int ui2, unsigned int ui3, int i3, int i4); /* 2 */ + XImage * (*xGetImage) (Display *d, Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3); /* 3 */ + char * (*xGetAtomName) (Display *d, Atom a); /* 4 */ + char * (*xKeysymToString) (KeySym k); /* 5 */ + Colormap (*xCreateColormap) (Display *d, Window w, Visual *v, int i); /* 6 */ + GContext (*xGContextFromGC) (GC g); /* 7 */ + KeySym (*xKeycodeToKeysym) (Display *d, KeyCode k, int i); /* 8 */ + KeySym (*xStringToKeysym) (_Xconst char *c); /* 9 */ + Window (*xRootWindow) (Display *d, int i); /* 10 */ + XErrorHandler (*xSetErrorHandler) (XErrorHandler x); /* 11 */ + Status (*xAllocColor) (Display *d, Colormap c, XColor *xp); /* 12 */ + int (*xBell) (Display *d, int i); /* 13 */ + void (*xChangeProperty) (Display *d, Window w, Atom a1, Atom a2, int i1, int i2, _Xconst unsigned char *c, int i3); /* 14 */ + void (*xChangeWindowAttributes) (Display *d, Window w, unsigned long ul, XSetWindowAttributes *x); /* 15 */ + void (*xConfigureWindow) (Display *d, Window w, unsigned int i, XWindowChanges *x); /* 16 */ + void (*xCopyArea) (Display *d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); /* 17 */ + void (*xCopyPlane) (Display *d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4, unsigned long ul); /* 18 */ + Pixmap (*xCreateBitmapFromData) (Display *display, Drawable d, _Xconst char *data, unsigned int width, unsigned int height); /* 19 */ + int (*xDefineCursor) (Display *d, Window w, Cursor c); /* 20 */ + void (*xDestroyWindow) (Display *d, Window w); /* 21 */ + void (*xDrawArc) (Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); /* 22 */ + int (*xDrawLines) (Display *d, Drawable dr, GC g, XPoint *x, int i1, int i2); /* 23 */ + void (*xDrawRectangle) (Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2); /* 24 */ + void (*xFillArc) (Display *d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4); /* 25 */ + void (*xFillPolygon) (Display *d, Drawable dr, GC g, XPoint *x, int i1, int i2, int i3); /* 26 */ + int (*xFillRectangles) (Display *d, Drawable dr, GC g, XRectangle *x, int i); /* 27 */ + int (*xFreeColormap) (Display *d, Colormap c); /* 28 */ + int (*xFreeColors) (Display *d, Colormap c, unsigned long *ulp, int i, unsigned long ul); /* 29 */ + int (*xFreeModifiermap) (XModifierKeymap *x); /* 30 */ + Status (*xGetGeometry) (Display *d, Drawable dr, Window *w, int *i1, int *i2, unsigned int *ui1, unsigned int *ui2, unsigned int *ui3, unsigned int *ui4); /* 31 */ + int (*xGetWindowProperty) (Display *d, Window w, Atom a1, long l1, long l2, Bool b, Atom a2, Atom *ap, int *ip, unsigned long *ulp1, unsigned long *ulp2, unsigned char **cpp); /* 32 */ + int (*xGrabKeyboard) (Display *d, Window w, Bool b, int i1, int i2, Time t); /* 33 */ + int (*xGrabPointer) (Display *d, Window w1, Bool b, unsigned int ui, int i1, int i2, Window w2, Cursor c, Time t); /* 34 */ + KeyCode (*xKeysymToKeycode) (Display *d, KeySym k); /* 35 */ + void (*xMapWindow) (Display *d, Window w); /* 36 */ + void (*xMoveResizeWindow) (Display *d, Window w, int i1, int i2, unsigned int ui1, unsigned int ui2); /* 37 */ + void (*xMoveWindow) (Display *d, Window w, int i1, int i2); /* 38 */ + Bool (*xQueryPointer) (Display *d, Window w1, Window *w2, Window *w3, int *i1, int *i2, int *i3, int *i4, unsigned int *ui); /* 39 */ + void (*xRaiseWindow) (Display *d, Window w); /* 40 */ + void (*xRefreshKeyboardMapping) (XMappingEvent *x); /* 41 */ + void (*xResizeWindow) (Display *d, Window w, unsigned int ui1, unsigned int ui2); /* 42 */ + void (*xSelectInput) (Display *d, Window w, long l); /* 43 */ + Status (*xSendEvent) (Display *d, Window w, Bool b, long l, XEvent *x); /* 44 */ + void (*xSetIconName) (Display *d, Window w, _Xconst char *c); /* 45 */ + void (*xSetInputFocus) (Display *d, Window w, int i, Time t); /* 46 */ + int (*xSetSelectionOwner) (Display *d, Atom a, Window w, Time t); /* 47 */ + void (*xSetWindowBackground) (Display *d, Window w, unsigned long ul); /* 48 */ + void (*xSetWindowBackgroundPixmap) (Display *d, Window w, Pixmap p); /* 49 */ + void (*xSetWindowBorder) (Display *d, Window w, unsigned long ul); /* 50 */ + void (*xSetWindowBorderPixmap) (Display *d, Window w, Pixmap p); /* 51 */ + void (*xSetWindowBorderWidth) (Display *d, Window w, unsigned int ui); /* 52 */ + void (*xSetWindowColormap) (Display *d, Window w, Colormap c); /* 53 */ + void (*xUngrabKeyboard) (Display *d, Time t); /* 54 */ + int (*xUngrabPointer) (Display *d, Time t); /* 55 */ + void (*xUnmapWindow) (Display *d, Window w); /* 56 */ + int (*tkPutImage) (unsigned long *colors, int ncolors, Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height); /* 57 */ + Status (*xParseColor) (Display *display, Colormap map, _Xconst char *spec, XColor *colorPtr); /* 58 */ + GC (*xCreateGC) (Display *display, Drawable d, unsigned long valuemask, XGCValues *values); /* 59 */ + int (*xFreeGC) (Display *display, GC gc); /* 60 */ + Atom (*xInternAtom) (Display *display, _Xconst char *atom_name, Bool only_if_exists); /* 61 */ + int (*xSetBackground) (Display *display, GC gc, unsigned long foreground); /* 62 */ + int (*xSetForeground) (Display *display, GC gc, unsigned long foreground); /* 63 */ + int (*xSetClipMask) (Display *display, GC gc, Pixmap pixmap); /* 64 */ + int (*xSetClipOrigin) (Display *display, GC gc, int clip_x_origin, int clip_y_origin); /* 65 */ + int (*xSetTSOrigin) (Display *display, GC gc, int ts_x_origin, int ts_y_origin); /* 66 */ + int (*xChangeGC) (Display *d, GC gc, unsigned long mask, XGCValues *values); /* 67 */ + int (*xSetFont) (Display *display, GC gc, Font font); /* 68 */ + int (*xSetArcMode) (Display *display, GC gc, int arc_mode); /* 69 */ + int (*xSetStipple) (Display *display, GC gc, Pixmap stipple); /* 70 */ + int (*xSetFillRule) (Display *display, GC gc, int fill_rule); /* 71 */ + int (*xSetFillStyle) (Display *display, GC gc, int fill_style); /* 72 */ + int (*xSetFunction) (Display *display, GC gc, int function); /* 73 */ + int (*xSetLineAttributes) (Display *display, GC gc, unsigned int line_width, int line_style, int cap_style, int join_style); /* 74 */ + int (*_XInitImageFuncPtrs) (XImage *image); /* 75 */ + XIC (*xCreateIC) (void); /* 76 */ + XVisualInfo * (*xGetVisualInfo) (Display *display, long vinfo_mask, XVisualInfo *vinfo_template, int *nitems_return); /* 77 */ + void (*xSetWMClientMachine) (Display *display, Window w, XTextProperty *text_prop); /* 78 */ + Status (*xStringListToTextProperty) (char **list, int count, XTextProperty *text_prop_return); /* 79 */ + void (*xDrawSegments) (Display *display, Drawable d, GC gc, XSegment *segments, int nsegments); /* 80 */ + void (*xForceScreenSaver) (Display *display, int mode); /* 81 */ + int (*xDrawLine) (Display *d, Drawable dr, GC g, int x1, int y1, int x2, int y2); /* 82 */ + int (*xFillRectangle) (Display *display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height); /* 83 */ + void (*xClearWindow) (Display *d, Window w); /* 84 */ + void (*xDrawPoint) (Display *display, Drawable d, GC gc, int x, int y); /* 85 */ + void (*xDrawPoints) (Display *display, Drawable d, GC gc, XPoint *points, int npoints, int mode); /* 86 */ + int (*xWarpPointer) (Display *display, Window src_w, Window dest_w, int src_x, int src_y, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y); /* 87 */ + void (*xQueryColor) (Display *display, Colormap colormap, XColor *def_in_out); /* 88 */ + void (*xQueryColors) (Display *display, Colormap colormap, XColor *defs_in_out, int ncolors); /* 89 */ + Status (*xQueryTree) (Display *d, Window w1, Window *w2, Window *w3, Window **w4, unsigned int *ui); /* 90 */ + int (*xSync) (Display *display, Bool flag); /* 91 */ +#endif /* AQUA */ +} TkIntXlibStubs; + +extern const TkIntXlibStubs *tkIntXlibStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) + +/* + * Inline function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +#define XSetDashes \ + (tkIntXlibStubsPtr->xSetDashes) /* 0 */ +#define XGetModifierMapping \ + (tkIntXlibStubsPtr->xGetModifierMapping) /* 1 */ +#define XCreateImage \ + (tkIntXlibStubsPtr->xCreateImage) /* 2 */ +#define XGetImage \ + (tkIntXlibStubsPtr->xGetImage) /* 3 */ +#define XGetAtomName \ + (tkIntXlibStubsPtr->xGetAtomName) /* 4 */ +#define XKeysymToString \ + (tkIntXlibStubsPtr->xKeysymToString) /* 5 */ +#define XCreateColormap \ + (tkIntXlibStubsPtr->xCreateColormap) /* 6 */ +#define XCreatePixmapCursor \ + (tkIntXlibStubsPtr->xCreatePixmapCursor) /* 7 */ +#define XCreateGlyphCursor \ + (tkIntXlibStubsPtr->xCreateGlyphCursor) /* 8 */ +#define XGContextFromGC \ + (tkIntXlibStubsPtr->xGContextFromGC) /* 9 */ +#define XListHosts \ + (tkIntXlibStubsPtr->xListHosts) /* 10 */ +#define XKeycodeToKeysym \ + (tkIntXlibStubsPtr->xKeycodeToKeysym) /* 11 */ +#define XStringToKeysym \ + (tkIntXlibStubsPtr->xStringToKeysym) /* 12 */ +#define XRootWindow \ + (tkIntXlibStubsPtr->xRootWindow) /* 13 */ +#define XSetErrorHandler \ + (tkIntXlibStubsPtr->xSetErrorHandler) /* 14 */ +#define XIconifyWindow \ + (tkIntXlibStubsPtr->xIconifyWindow) /* 15 */ +#define XWithdrawWindow \ + (tkIntXlibStubsPtr->xWithdrawWindow) /* 16 */ +#define XGetWMColormapWindows \ + (tkIntXlibStubsPtr->xGetWMColormapWindows) /* 17 */ +#define XAllocColor \ + (tkIntXlibStubsPtr->xAllocColor) /* 18 */ +#define XBell \ + (tkIntXlibStubsPtr->xBell) /* 19 */ +#define XChangeProperty \ + (tkIntXlibStubsPtr->xChangeProperty) /* 20 */ +#define XChangeWindowAttributes \ + (tkIntXlibStubsPtr->xChangeWindowAttributes) /* 21 */ +#define XClearWindow \ + (tkIntXlibStubsPtr->xClearWindow) /* 22 */ +#define XConfigureWindow \ + (tkIntXlibStubsPtr->xConfigureWindow) /* 23 */ +#define XCopyArea \ + (tkIntXlibStubsPtr->xCopyArea) /* 24 */ +#define XCopyPlane \ + (tkIntXlibStubsPtr->xCopyPlane) /* 25 */ +#define XCreateBitmapFromData \ + (tkIntXlibStubsPtr->xCreateBitmapFromData) /* 26 */ +#define XDefineCursor \ + (tkIntXlibStubsPtr->xDefineCursor) /* 27 */ +#define XDeleteProperty \ + (tkIntXlibStubsPtr->xDeleteProperty) /* 28 */ +#define XDestroyWindow \ + (tkIntXlibStubsPtr->xDestroyWindow) /* 29 */ +#define XDrawArc \ + (tkIntXlibStubsPtr->xDrawArc) /* 30 */ +#define XDrawLines \ + (tkIntXlibStubsPtr->xDrawLines) /* 31 */ +#define XDrawRectangle \ + (tkIntXlibStubsPtr->xDrawRectangle) /* 32 */ +#define XFillArc \ + (tkIntXlibStubsPtr->xFillArc) /* 33 */ +#define XFillPolygon \ + (tkIntXlibStubsPtr->xFillPolygon) /* 34 */ +#define XFillRectangles \ + (tkIntXlibStubsPtr->xFillRectangles) /* 35 */ +#define XForceScreenSaver \ + (tkIntXlibStubsPtr->xForceScreenSaver) /* 36 */ +#define XFreeColormap \ + (tkIntXlibStubsPtr->xFreeColormap) /* 37 */ +#define XFreeColors \ + (tkIntXlibStubsPtr->xFreeColors) /* 38 */ +#define XFreeCursor \ + (tkIntXlibStubsPtr->xFreeCursor) /* 39 */ +#define XFreeModifiermap \ + (tkIntXlibStubsPtr->xFreeModifiermap) /* 40 */ +#define XGetGeometry \ + (tkIntXlibStubsPtr->xGetGeometry) /* 41 */ +#define XGetInputFocus \ + (tkIntXlibStubsPtr->xGetInputFocus) /* 42 */ +#define XGetWindowProperty \ + (tkIntXlibStubsPtr->xGetWindowProperty) /* 43 */ +#define XGetWindowAttributes \ + (tkIntXlibStubsPtr->xGetWindowAttributes) /* 44 */ +#define XGrabKeyboard \ + (tkIntXlibStubsPtr->xGrabKeyboard) /* 45 */ +#define XGrabPointer \ + (tkIntXlibStubsPtr->xGrabPointer) /* 46 */ +#define XKeysymToKeycode \ + (tkIntXlibStubsPtr->xKeysymToKeycode) /* 47 */ +#define XLookupColor \ + (tkIntXlibStubsPtr->xLookupColor) /* 48 */ +#define XMapWindow \ + (tkIntXlibStubsPtr->xMapWindow) /* 49 */ +#define XMoveResizeWindow \ + (tkIntXlibStubsPtr->xMoveResizeWindow) /* 50 */ +#define XMoveWindow \ + (tkIntXlibStubsPtr->xMoveWindow) /* 51 */ +#define XNextEvent \ + (tkIntXlibStubsPtr->xNextEvent) /* 52 */ +#define XPutBackEvent \ + (tkIntXlibStubsPtr->xPutBackEvent) /* 53 */ +#define XQueryColors \ + (tkIntXlibStubsPtr->xQueryColors) /* 54 */ +#define XQueryPointer \ + (tkIntXlibStubsPtr->xQueryPointer) /* 55 */ +#define XQueryTree \ + (tkIntXlibStubsPtr->xQueryTree) /* 56 */ +#define XRaiseWindow \ + (tkIntXlibStubsPtr->xRaiseWindow) /* 57 */ +#define XRefreshKeyboardMapping \ + (tkIntXlibStubsPtr->xRefreshKeyboardMapping) /* 58 */ +#define XResizeWindow \ + (tkIntXlibStubsPtr->xResizeWindow) /* 59 */ +#define XSelectInput \ + (tkIntXlibStubsPtr->xSelectInput) /* 60 */ +#define XSendEvent \ + (tkIntXlibStubsPtr->xSendEvent) /* 61 */ +#define XSetCommand \ + (tkIntXlibStubsPtr->xSetCommand) /* 62 */ +#define XSetIconName \ + (tkIntXlibStubsPtr->xSetIconName) /* 63 */ +#define XSetInputFocus \ + (tkIntXlibStubsPtr->xSetInputFocus) /* 64 */ +#define XSetSelectionOwner \ + (tkIntXlibStubsPtr->xSetSelectionOwner) /* 65 */ +#define XSetWindowBackground \ + (tkIntXlibStubsPtr->xSetWindowBackground) /* 66 */ +#define XSetWindowBackgroundPixmap \ + (tkIntXlibStubsPtr->xSetWindowBackgroundPixmap) /* 67 */ +#define XSetWindowBorder \ + (tkIntXlibStubsPtr->xSetWindowBorder) /* 68 */ +#define XSetWindowBorderPixmap \ + (tkIntXlibStubsPtr->xSetWindowBorderPixmap) /* 69 */ +#define XSetWindowBorderWidth \ + (tkIntXlibStubsPtr->xSetWindowBorderWidth) /* 70 */ +#define XSetWindowColormap \ + (tkIntXlibStubsPtr->xSetWindowColormap) /* 71 */ +#define XTranslateCoordinates \ + (tkIntXlibStubsPtr->xTranslateCoordinates) /* 72 */ +#define XUngrabKeyboard \ + (tkIntXlibStubsPtr->xUngrabKeyboard) /* 73 */ +#define XUngrabPointer \ + (tkIntXlibStubsPtr->xUngrabPointer) /* 74 */ +#define XUnmapWindow \ + (tkIntXlibStubsPtr->xUnmapWindow) /* 75 */ +#define XWindowEvent \ + (tkIntXlibStubsPtr->xWindowEvent) /* 76 */ +#define XDestroyIC \ + (tkIntXlibStubsPtr->xDestroyIC) /* 77 */ +#define XFilterEvent \ + (tkIntXlibStubsPtr->xFilterEvent) /* 78 */ +#define XmbLookupString \ + (tkIntXlibStubsPtr->xmbLookupString) /* 79 */ +#define TkPutImage \ + (tkIntXlibStubsPtr->tkPutImage) /* 80 */ +/* Slot 81 is reserved */ +#define XParseColor \ + (tkIntXlibStubsPtr->xParseColor) /* 82 */ +#define XCreateGC \ + (tkIntXlibStubsPtr->xCreateGC) /* 83 */ +#define XFreeGC \ + (tkIntXlibStubsPtr->xFreeGC) /* 84 */ +#define XInternAtom \ + (tkIntXlibStubsPtr->xInternAtom) /* 85 */ +#define XSetBackground \ + (tkIntXlibStubsPtr->xSetBackground) /* 86 */ +#define XSetForeground \ + (tkIntXlibStubsPtr->xSetForeground) /* 87 */ +#define XSetClipMask \ + (tkIntXlibStubsPtr->xSetClipMask) /* 88 */ +#define XSetClipOrigin \ + (tkIntXlibStubsPtr->xSetClipOrigin) /* 89 */ +#define XSetTSOrigin \ + (tkIntXlibStubsPtr->xSetTSOrigin) /* 90 */ +#define XChangeGC \ + (tkIntXlibStubsPtr->xChangeGC) /* 91 */ +#define XSetFont \ + (tkIntXlibStubsPtr->xSetFont) /* 92 */ +#define XSetArcMode \ + (tkIntXlibStubsPtr->xSetArcMode) /* 93 */ +#define XSetStipple \ + (tkIntXlibStubsPtr->xSetStipple) /* 94 */ +#define XSetFillRule \ + (tkIntXlibStubsPtr->xSetFillRule) /* 95 */ +#define XSetFillStyle \ + (tkIntXlibStubsPtr->xSetFillStyle) /* 96 */ +#define XSetFunction \ + (tkIntXlibStubsPtr->xSetFunction) /* 97 */ +#define XSetLineAttributes \ + (tkIntXlibStubsPtr->xSetLineAttributes) /* 98 */ +#define _XInitImageFuncPtrs \ + (tkIntXlibStubsPtr->_XInitImageFuncPtrs) /* 99 */ +#define XCreateIC \ + (tkIntXlibStubsPtr->xCreateIC) /* 100 */ +#define XGetVisualInfo \ + (tkIntXlibStubsPtr->xGetVisualInfo) /* 101 */ +#define XSetWMClientMachine \ + (tkIntXlibStubsPtr->xSetWMClientMachine) /* 102 */ +#define XStringListToTextProperty \ + (tkIntXlibStubsPtr->xStringListToTextProperty) /* 103 */ +#define XDrawLine \ + (tkIntXlibStubsPtr->xDrawLine) /* 104 */ +#define XWarpPointer \ + (tkIntXlibStubsPtr->xWarpPointer) /* 105 */ +#define XFillRectangle \ + (tkIntXlibStubsPtr->xFillRectangle) /* 106 */ +#define XFlush \ + (tkIntXlibStubsPtr->xFlush) /* 107 */ +#define XGrabServer \ + (tkIntXlibStubsPtr->xGrabServer) /* 108 */ +#define XUngrabServer \ + (tkIntXlibStubsPtr->xUngrabServer) /* 109 */ +#define XFree \ + (tkIntXlibStubsPtr->xFree) /* 110 */ +#define XNoOp \ + (tkIntXlibStubsPtr->xNoOp) /* 111 */ +#define XSynchronize \ + (tkIntXlibStubsPtr->xSynchronize) /* 112 */ +#define XSync \ + (tkIntXlibStubsPtr->xSync) /* 113 */ +#define XVisualIDFromVisual \ + (tkIntXlibStubsPtr->xVisualIDFromVisual) /* 114 */ +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ +#define XSetDashes \ + (tkIntXlibStubsPtr->xSetDashes) /* 0 */ +#define XGetModifierMapping \ + (tkIntXlibStubsPtr->xGetModifierMapping) /* 1 */ +#define XCreateImage \ + (tkIntXlibStubsPtr->xCreateImage) /* 2 */ +#define XGetImage \ + (tkIntXlibStubsPtr->xGetImage) /* 3 */ +#define XGetAtomName \ + (tkIntXlibStubsPtr->xGetAtomName) /* 4 */ +#define XKeysymToString \ + (tkIntXlibStubsPtr->xKeysymToString) /* 5 */ +#define XCreateColormap \ + (tkIntXlibStubsPtr->xCreateColormap) /* 6 */ +#define XGContextFromGC \ + (tkIntXlibStubsPtr->xGContextFromGC) /* 7 */ +#define XKeycodeToKeysym \ + (tkIntXlibStubsPtr->xKeycodeToKeysym) /* 8 */ +#define XStringToKeysym \ + (tkIntXlibStubsPtr->xStringToKeysym) /* 9 */ +#define XRootWindow \ + (tkIntXlibStubsPtr->xRootWindow) /* 10 */ +#define XSetErrorHandler \ + (tkIntXlibStubsPtr->xSetErrorHandler) /* 11 */ +#define XAllocColor \ + (tkIntXlibStubsPtr->xAllocColor) /* 12 */ +#define XBell \ + (tkIntXlibStubsPtr->xBell) /* 13 */ +#define XChangeProperty \ + (tkIntXlibStubsPtr->xChangeProperty) /* 14 */ +#define XChangeWindowAttributes \ + (tkIntXlibStubsPtr->xChangeWindowAttributes) /* 15 */ +#define XConfigureWindow \ + (tkIntXlibStubsPtr->xConfigureWindow) /* 16 */ +#define XCopyArea \ + (tkIntXlibStubsPtr->xCopyArea) /* 17 */ +#define XCopyPlane \ + (tkIntXlibStubsPtr->xCopyPlane) /* 18 */ +#define XCreateBitmapFromData \ + (tkIntXlibStubsPtr->xCreateBitmapFromData) /* 19 */ +#define XDefineCursor \ + (tkIntXlibStubsPtr->xDefineCursor) /* 20 */ +#define XDestroyWindow \ + (tkIntXlibStubsPtr->xDestroyWindow) /* 21 */ +#define XDrawArc \ + (tkIntXlibStubsPtr->xDrawArc) /* 22 */ +#define XDrawLines \ + (tkIntXlibStubsPtr->xDrawLines) /* 23 */ +#define XDrawRectangle \ + (tkIntXlibStubsPtr->xDrawRectangle) /* 24 */ +#define XFillArc \ + (tkIntXlibStubsPtr->xFillArc) /* 25 */ +#define XFillPolygon \ + (tkIntXlibStubsPtr->xFillPolygon) /* 26 */ +#define XFillRectangles \ + (tkIntXlibStubsPtr->xFillRectangles) /* 27 */ +#define XFreeColormap \ + (tkIntXlibStubsPtr->xFreeColormap) /* 28 */ +#define XFreeColors \ + (tkIntXlibStubsPtr->xFreeColors) /* 29 */ +#define XFreeModifiermap \ + (tkIntXlibStubsPtr->xFreeModifiermap) /* 30 */ +#define XGetGeometry \ + (tkIntXlibStubsPtr->xGetGeometry) /* 31 */ +#define XGetWindowProperty \ + (tkIntXlibStubsPtr->xGetWindowProperty) /* 32 */ +#define XGrabKeyboard \ + (tkIntXlibStubsPtr->xGrabKeyboard) /* 33 */ +#define XGrabPointer \ + (tkIntXlibStubsPtr->xGrabPointer) /* 34 */ +#define XKeysymToKeycode \ + (tkIntXlibStubsPtr->xKeysymToKeycode) /* 35 */ +#define XMapWindow \ + (tkIntXlibStubsPtr->xMapWindow) /* 36 */ +#define XMoveResizeWindow \ + (tkIntXlibStubsPtr->xMoveResizeWindow) /* 37 */ +#define XMoveWindow \ + (tkIntXlibStubsPtr->xMoveWindow) /* 38 */ +#define XQueryPointer \ + (tkIntXlibStubsPtr->xQueryPointer) /* 39 */ +#define XRaiseWindow \ + (tkIntXlibStubsPtr->xRaiseWindow) /* 40 */ +#define XRefreshKeyboardMapping \ + (tkIntXlibStubsPtr->xRefreshKeyboardMapping) /* 41 */ +#define XResizeWindow \ + (tkIntXlibStubsPtr->xResizeWindow) /* 42 */ +#define XSelectInput \ + (tkIntXlibStubsPtr->xSelectInput) /* 43 */ +#define XSendEvent \ + (tkIntXlibStubsPtr->xSendEvent) /* 44 */ +#define XSetIconName \ + (tkIntXlibStubsPtr->xSetIconName) /* 45 */ +#define XSetInputFocus \ + (tkIntXlibStubsPtr->xSetInputFocus) /* 46 */ +#define XSetSelectionOwner \ + (tkIntXlibStubsPtr->xSetSelectionOwner) /* 47 */ +#define XSetWindowBackground \ + (tkIntXlibStubsPtr->xSetWindowBackground) /* 48 */ +#define XSetWindowBackgroundPixmap \ + (tkIntXlibStubsPtr->xSetWindowBackgroundPixmap) /* 49 */ +#define XSetWindowBorder \ + (tkIntXlibStubsPtr->xSetWindowBorder) /* 50 */ +#define XSetWindowBorderPixmap \ + (tkIntXlibStubsPtr->xSetWindowBorderPixmap) /* 51 */ +#define XSetWindowBorderWidth \ + (tkIntXlibStubsPtr->xSetWindowBorderWidth) /* 52 */ +#define XSetWindowColormap \ + (tkIntXlibStubsPtr->xSetWindowColormap) /* 53 */ +#define XUngrabKeyboard \ + (tkIntXlibStubsPtr->xUngrabKeyboard) /* 54 */ +#define XUngrabPointer \ + (tkIntXlibStubsPtr->xUngrabPointer) /* 55 */ +#define XUnmapWindow \ + (tkIntXlibStubsPtr->xUnmapWindow) /* 56 */ +#define TkPutImage \ + (tkIntXlibStubsPtr->tkPutImage) /* 57 */ +#define XParseColor \ + (tkIntXlibStubsPtr->xParseColor) /* 58 */ +#define XCreateGC \ + (tkIntXlibStubsPtr->xCreateGC) /* 59 */ +#define XFreeGC \ + (tkIntXlibStubsPtr->xFreeGC) /* 60 */ +#define XInternAtom \ + (tkIntXlibStubsPtr->xInternAtom) /* 61 */ +#define XSetBackground \ + (tkIntXlibStubsPtr->xSetBackground) /* 62 */ +#define XSetForeground \ + (tkIntXlibStubsPtr->xSetForeground) /* 63 */ +#define XSetClipMask \ + (tkIntXlibStubsPtr->xSetClipMask) /* 64 */ +#define XSetClipOrigin \ + (tkIntXlibStubsPtr->xSetClipOrigin) /* 65 */ +#define XSetTSOrigin \ + (tkIntXlibStubsPtr->xSetTSOrigin) /* 66 */ +#define XChangeGC \ + (tkIntXlibStubsPtr->xChangeGC) /* 67 */ +#define XSetFont \ + (tkIntXlibStubsPtr->xSetFont) /* 68 */ +#define XSetArcMode \ + (tkIntXlibStubsPtr->xSetArcMode) /* 69 */ +#define XSetStipple \ + (tkIntXlibStubsPtr->xSetStipple) /* 70 */ +#define XSetFillRule \ + (tkIntXlibStubsPtr->xSetFillRule) /* 71 */ +#define XSetFillStyle \ + (tkIntXlibStubsPtr->xSetFillStyle) /* 72 */ +#define XSetFunction \ + (tkIntXlibStubsPtr->xSetFunction) /* 73 */ +#define XSetLineAttributes \ + (tkIntXlibStubsPtr->xSetLineAttributes) /* 74 */ +#define _XInitImageFuncPtrs \ + (tkIntXlibStubsPtr->_XInitImageFuncPtrs) /* 75 */ +#define XCreateIC \ + (tkIntXlibStubsPtr->xCreateIC) /* 76 */ +#define XGetVisualInfo \ + (tkIntXlibStubsPtr->xGetVisualInfo) /* 77 */ +#define XSetWMClientMachine \ + (tkIntXlibStubsPtr->xSetWMClientMachine) /* 78 */ +#define XStringListToTextProperty \ + (tkIntXlibStubsPtr->xStringListToTextProperty) /* 79 */ +#define XDrawSegments \ + (tkIntXlibStubsPtr->xDrawSegments) /* 80 */ +#define XForceScreenSaver \ + (tkIntXlibStubsPtr->xForceScreenSaver) /* 81 */ +#define XDrawLine \ + (tkIntXlibStubsPtr->xDrawLine) /* 82 */ +#define XFillRectangle \ + (tkIntXlibStubsPtr->xFillRectangle) /* 83 */ +#define XClearWindow \ + (tkIntXlibStubsPtr->xClearWindow) /* 84 */ +#define XDrawPoint \ + (tkIntXlibStubsPtr->xDrawPoint) /* 85 */ +#define XDrawPoints \ + (tkIntXlibStubsPtr->xDrawPoints) /* 86 */ +#define XWarpPointer \ + (tkIntXlibStubsPtr->xWarpPointer) /* 87 */ +#define XQueryColor \ + (tkIntXlibStubsPtr->xQueryColor) /* 88 */ +#define XQueryColors \ + (tkIntXlibStubsPtr->xQueryColors) /* 89 */ +#define XQueryTree \ + (tkIntXlibStubsPtr->xQueryTree) /* 90 */ +#define XSync \ + (tkIntXlibStubsPtr->xSync) /* 91 */ +#endif /* AQUA */ + +#endif /* defined(USE_TK_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKINTXLIBDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tcl.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tcl.h new file mode 100644 index 00000000..297b42c1 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tcl.h @@ -0,0 +1,2652 @@ +/* + * 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 (1 LOC patch) + * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch) + * win/configure.in (as above) + * win/tcl.m4 (not patchlevel) + * win/makefile.bc (not patchlevel) 2 LOC + * README (sections 0 and 2, with and without separator) + * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC + * macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC + * macosx/Tcl.xcode/project.pbxproj (not patchlevel) 2 LOC + * macosx/Tcl.xcode/default.pbxuser (not patchlevel) 1 LOC + * macosx/Tcl-Common.xcconfig (not patchlevel) 1 LOC + * win/README (not patchlevel) (sections 0 and 2) + * unix/tcl.spec (1 LOC patch) + * tools/tcl.hpj.in (not patchlevel, for windows installer) + */ + +#define TCL_MAJOR_VERSION 8 +#define TCL_MINOR_VERSION 6 +#define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE +#define TCL_RELEASE_SERIAL 4 + +#define TCL_VERSION "8.6" +#define TCL_PATCH_LEVEL "8.6.4" + +/* + *---------------------------------------------------------------------------- + * The following definitions set up the proper options for Windows compilers. + * We use this method because there is no autoconf equivalent. + */ + +#ifdef _WIN32 +# ifndef __WIN32__ +# define __WIN32__ +# endif +# ifndef WIN32 +# define WIN32 +# endif +#endif + +/* + * 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 function + * 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 + +/* + * Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and + * SEEK_END, all #define'd by stdio.h . + * + * Also, many extensions need stdio.h, and they've grown accustomed to tcl.h + * providing it for them rather than #include-ing it themselves as they + * should, so also for their sake, we keep the #include to be consistent with + * prior Tcl releases. + */ + +#include + +/* + *---------------------------------------------------------------------------- + * Support for functions with a variable number of arguments. + * + * The following TCL_VARARGS* macros are to support old extensions + * written for older versions of Tcl where the macros permitted + * support for the varargs.h system as well as stdarg.h . + * + * New code should just directly be written to use stdarg.h conventions. + */ + +#include +#ifndef TCL_NO_DEPRECATED +# 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) +#endif +#if defined(__GNUC__) && (__GNUC__ > 2) +# define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +# define TCL_FORMAT_PRINTF(a,b) +#endif + +/* + * Allow a part of Tcl's API to be explicitly marked as deprecated. + * + * Used to make TIP 330/336 generate moans even if people use the + * compatibility macros. Change your code, guys! We won't support you forever. + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) +# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__ (msg))) +# else +# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__)) +# endif +#else +# define TCL_DEPRECATED_API(msg) /* nothing portable */ +#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. + * + * Note: when building static but linking dynamically to MSVCRT we must still + * correctly decorate the C library imported function. Use CRTIMPORT + * for this purpose. _DLL is defined by the compiler when linking to + * MSVCRT. + */ + +#if (defined(_WIN32) && (defined(_MSC_VER) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0550)) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec)))) +# define HAVE_DECLSPEC 1 +# ifdef STATIC_BUILD +# define DLLIMPORT +# define DLLEXPORT +# ifdef _DLL +# define CRTIMPORT __declspec(dllimport) +# else +# define CRTIMPORT +# endif +# else +# define DLLIMPORT __declspec(dllimport) +# define DLLEXPORT __declspec(dllexport) +# define CRTIMPORT __declspec(dllimport) +# endif +#else +# define DLLIMPORT +# if defined(__GNUC__) && __GNUC__ > 3 +# define DLLEXPORT __attribute__ ((visibility("default"))) +# else +# define DLLEXPORT +# endif +# define CRTIMPORT +#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 + +/* + * The following _ANSI_ARGS_ macro is to support old extensions + * written for older versions of Tcl where it permitted support + * for compilers written in the pre-prototype era of C. + * + * New code should use prototypes. + */ + +#ifndef TCL_NO_DEPRECATED +# undef _ANSI_ARGS_ +# define _ANSI_ARGS_(x) x +#endif + +/* + * Definitions that allow this header file to be used either with or without + * ANSI C features. + */ + +#ifndef INLINE +# define INLINE +#endif + +#ifdef NO_CONST +# ifndef const +# define const +# endif +#endif +#ifndef CONST +# define CONST const +#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 + +#ifndef CONST86 +# define CONST86 CONST84 +#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 +# define TCL_CFG_DO64BIT 1 +# else /* !__LP64__ */ +# define TCL_WIDE_INT_TYPE long long +# undef TCL_WIDE_INT_IS_LONG +# undef TCL_CFG_DO64BIT +# endif /* __LP64__ */ +# undef HAVE_STRUCT_STAT64 +#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 function + * sprintf(...,"%" TCL_LL_MODIFIER "d",...). + */ + +#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" +# else /* __BORLANDC__ */ +# define TCL_LL_MODIFIER "I64" +# endif /* __BORLANDC__ */ +# elif defined(__GNUC__) +# define TCL_WIDE_INT_TYPE long long +# define TCL_LL_MODIFIER "ll" +# else /* ! _WIN32 && ! __GNUC__ */ +/* + * Don't know what platform it is and configure hasn't discovered what is + * going on for us. Try to guess... + */ +# include +# if (INT_MAX < LONG_MAX) +# define TCL_WIDE_INT_IS_LONG 1 +# else +# define TCL_WIDE_INT_TYPE long long +# endif +# 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" +# 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" +# 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 { + 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) && !defined(__APPLE__) + typedef struct stat64 Tcl_StatBuf; +#else + typedef struct stat Tcl_StatBuf; +#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 function 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 functions 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 +#ifndef TCL_NO_DEPRECATED +{ + /* TIP #330: Strongly discourage extensions from using the string + * result. */ +#ifdef USE_INTERP_RESULT + char *result TCL_DEPRECATED_API("use Tcl_GetStringResult/Tcl_SetResult"); + /* If the last command returned a string + * result, this points to it. */ + void (*freeProc) (char *blockPtr) + TCL_DEPRECATED_API("use Tcl_GetStringResult/Tcl_SetResult"); + /* 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 function to invoke to free the result. + * Tcl_Eval must free it before executing next + * command. */ +#else + char *resultDontUse; /* Don't use in extensions! */ + void (*freeProcDontUse) (char *); /* Don't use in extensions! */ +#endif +#ifdef USE_INTERP_ERRORLINE + int errorLine TCL_DEPRECATED_API("use Tcl_GetErrorLine/Tcl_SetErrorLine"); + /* When TCL_ERROR is returned, this gives the + * line number within the command where the + * error occurred (1 if first line). */ +#else + int errorLineDontUse; /* Don't use in extensions! */ +#endif +} +#endif /* TCL_NO_DEPRECATED */ +Tcl_Interp; + +typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler; +typedef struct Tcl_Channel_ *Tcl_Channel; +typedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion; +typedef struct Tcl_Command_ *Tcl_Command; +typedef struct Tcl_Condition_ *Tcl_Condition; +typedef struct Tcl_Dict_ *Tcl_Dict; +typedef struct Tcl_EncodingState_ *Tcl_EncodingState; +typedef struct Tcl_Encoding_ *Tcl_Encoding; +typedef struct Tcl_Event Tcl_Event; +typedef struct Tcl_InterpState_ *Tcl_InterpState; +typedef struct Tcl_LoadHandle_ *Tcl_LoadHandle; +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_ZLibStream_ *Tcl_ZlibStream; + +/* + *---------------------------------------------------------------------------- + * Definition of the interface to functions implementing threads. A function + * 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) (ClientData clientData); +#else +typedef void (Tcl_ThreadCreateProc) (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. + */ + +#if defined _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_StringCaseMatch. + */ + +#define TCL_MATCH_NOCASE (1<<0) + +/* + * 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. */ + +/* + * 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 functions + * Tcl_GetObjResult() or Tcl_GetStringResult() to read the interpreter's + * result. See the SetResult man page for details. Besides this result, the + * command function 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 function return; + * the interpreter's result contains the function'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 function types declared below. + */ + +struct Tcl_Obj; + +/* + *---------------------------------------------------------------------------- + * Function types defined by Tcl: + */ + +typedef int (Tcl_AppInitProc) (Tcl_Interp *interp); +typedef int (Tcl_AsyncProc) (ClientData clientData, Tcl_Interp *interp, + int code); +typedef void (Tcl_ChannelProc) (ClientData clientData, int mask); +typedef void (Tcl_CloseProc) (ClientData data); +typedef void (Tcl_CmdDeleteProc) (ClientData clientData); +typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp *interp, + int argc, CONST84 char *argv[]); +typedef void (Tcl_CmdTraceProc) (ClientData clientData, Tcl_Interp *interp, + int level, char *command, Tcl_CmdProc *proc, + ClientData cmdClientData, int argc, CONST84 char *argv[]); +typedef int (Tcl_CmdObjTraceProc) (ClientData clientData, Tcl_Interp *interp, + int level, const char *command, Tcl_Command commandInfo, int objc, + struct Tcl_Obj *const *objv); +typedef void (Tcl_CmdObjTraceDeleteProc) (ClientData clientData); +typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, + struct Tcl_Obj *dupPtr); +typedef int (Tcl_EncodingConvertProc) (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) (ClientData clientData); +typedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags); +typedef void (Tcl_EventCheckProc) (ClientData clientData, int flags); +typedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, ClientData clientData); +typedef void (Tcl_EventSetupProc) (ClientData clientData, int flags); +typedef void (Tcl_ExitProc) (ClientData clientData); +typedef void (Tcl_FileProc) (ClientData clientData, int mask); +typedef void (Tcl_FileFreeProc) (ClientData clientData); +typedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr); +typedef void (Tcl_FreeProc) (char *blockPtr); +typedef void (Tcl_IdleProc) (ClientData clientData); +typedef void (Tcl_InterpDeleteProc) (ClientData clientData, + Tcl_Interp *interp); +typedef int (Tcl_MathProc) (ClientData clientData, Tcl_Interp *interp, + Tcl_Value *args, Tcl_Value *resultPtr); +typedef void (Tcl_NamespaceDeleteProc) (ClientData clientData); +typedef int (Tcl_ObjCmdProc) (ClientData clientData, Tcl_Interp *interp, + int objc, struct Tcl_Obj *const *objv); +typedef int (Tcl_PackageInitProc) (Tcl_Interp *interp); +typedef int (Tcl_PackageUnloadProc) (Tcl_Interp *interp, int flags); +typedef void (Tcl_PanicProc) (const char *format, ...); +typedef void (Tcl_TcpAcceptProc) (ClientData callbackData, Tcl_Channel chan, + char *address, int port); +typedef void (Tcl_TimerProc) (ClientData clientData); +typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr); +typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr); +typedef char * (Tcl_VarTraceProc) (ClientData clientData, Tcl_Interp *interp, + CONST84 char *part1, CONST84 char *part2, int flags); +typedef void (Tcl_CommandTraceProc) (ClientData clientData, Tcl_Interp *interp, + const char *oldName, const char *newName, int flags); +typedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc, + ClientData clientData); +typedef void (Tcl_DeleteFileHandlerProc) (int fd); +typedef void (Tcl_AlertNotifierProc) (ClientData clientData); +typedef void (Tcl_ServiceModeHookProc) (int mode); +typedef ClientData (Tcl_InitNotifierProc) (void); +typedef void (Tcl_FinalizeNotifierProc) (ClientData clientData); +typedef void (Tcl_MainLoopProc) (void); + +/* + *---------------------------------------------------------------------------- + * The following structure represents a type of object, which is a particular + * internal representation for an object plus a set of functions that provide + * standard operations on objects of that type. + */ + +typedef struct Tcl_ObjType { + const 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. */ + const 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; + struct { /* - internal rep as a pointer and a long, + * the main use of which is a bignum's + * tightly packed fields, where the alloc, + * used and signum flags are packed into a + * single word with everything else hung + * off the pointer. */ + void *ptr; + unsigned long value; + } ptrAndLongRep; + } 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(Tcl_Obj *objPtr); +void Tcl_DecrRefCount(Tcl_Obj *objPtr); +int Tcl_IsShared(Tcl_Obj *objPtr); + +/* + *---------------------------------------------------------------------------- + * 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; + /* Function 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 + * function while proc is a traditional Tcl argc/argv string-based function. + * 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 function was registered by + * Tcl_CreateObjCommand, and to 0 if a string-based function was registered by + * Tcl_CreateCommand. The other function is typically set to a compatibility + * wrapper that does string-to-object or object-to-string argument conversions + * then calls the other function. + */ + +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 function. */ + ClientData objClientData; /* ClientData for object proc. */ + Tcl_CmdProc *proc; /* Command's string-based function. */ + ClientData clientData; /* ClientData for string proc. */ + Tcl_CmdDeleteProc *deleteProc; + /* Function 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 + * TclRenameCommand or Tcl_Eval (of 'rename') + * to do that. */ +} Tcl_CmdInfo; + +/* + *---------------------------------------------------------------------------- + * The structure defined below is used to hold dynamic strings. The only + * fields that clients should use are string and length, accessible via the + * macros Tcl_DStringValue and Tcl_DStringLength. + */ + +#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 values passed to Tcl_ConvertElement. + * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to + * use backslash quoting instead. + * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It + * is safe to leave the hash unquoted when the element is not the first + * element of a list, and this flag can be used by the caller to indicate + * that condition. + */ + +#define TCL_DONT_USE_BRACES 1 +#define TCL_DONT_QUOTE_HASH 8 + +/* + * 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, Tcl_EvalObj, Tcl_EvalObjv. + * WARNING: these bit choices must not conflict with the bit choices for + * evalFlag bits in tclInt.h! + * + * Meanings: + * TCL_NO_EVAL: Just record this command + * TCL_EVAL_GLOBAL: Execute script in global namespace + * TCL_EVAL_DIRECT: Do not compile this script + * TCL_EVAL_INVOKE: Magical Tcl_EvalObjv mode for aliases/ensembles + * o Run in iPtr->lookupNsPtr or global namespace + * o Cut out of error traces + * o Don't reset the flags controlling ensemble + * error message rewriting. + * TCL_CANCEL_UNWIND: Magical Tcl_CancelEval mode that causes the + * stack for the script in progress to be + * completely unwound. + * TCL_EVAL_NOERR: Do no exception reporting at all, just return + * as the caller will report. + */ + +#define TCL_NO_EVAL 0x010000 +#define TCL_EVAL_GLOBAL 0x020000 +#define TCL_EVAL_DIRECT 0x040000 +#define TCL_EVAL_INVOKE 0x080000 +#define TCL_CANCEL_UNWIND 0x100000 +#define TCL_EVAL_NOERR 0x200000 + +/* + * 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 functions. + * WARNING: these bit choices must not conflict with the bit choice for + * TCL_CANCEL_UNWIND, above. + */ + +#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 for ensemble commands. + */ + +#define TCL_ENSEMBLE_PREFIX 0x02/* Flag value to say whether to allow + * unambiguous prefixes of commands or to + * require exact matches for command names. */ + +/* + * Flag values passed to command-related functions. + */ + +#define TCL_TRACE_RENAME 0x2000 +#define TCL_TRACE_DELETE 0x4000 + +#define TCL_ALLOW_INLINE_COMPILATION 0x20000 + +/* + * 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_CHAR 6 +#define TCL_LINK_UCHAR 7 +#define TCL_LINK_SHORT 8 +#define TCL_LINK_USHORT 9 +#define TCL_LINK_UINT 10 +#define TCL_LINK_LONG 11 +#define TCL_LINK_ULONG 12 +#define TCL_LINK_FLOAT 13 +#define TCL_LINK_WIDE_UINT 14 +#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 (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr); +typedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr); +typedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr, + void *keyPtr); +typedef void (Tcl_FreeHashEntryProc) (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 + void *hash; /* Hash value, stored as pointer to ensure + * that the offsets of the fields in this + * structure are not changed. */ +#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[1]; /* 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. + * TCL_HASH_KEY_SYSTEM_HASH - If this flag is set then all memory internally + * allocated for the hash table that is not for an + * entry will use the system heap. + */ + +#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1 +#define TCL_HASH_KEY_SYSTEM_HASH 0x2 + +/* + * 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. */ + Tcl_HashKeyProc *hashKeyProc; + /* Calculates a hash value for the key. If + * this is NULL then the pointer itself is + * used as a hash value. */ + Tcl_CompareHashKeysProc *compareKeysProc; + /* 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_AllocHashEntryProc *allocEntryProc; + /* 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_FreeHashEntryProc *freeEntryProc; + /* 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. */ +}; + +/* + * 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. */ + Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key); + Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key, + int *newPtr); + const 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 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) +#define TCL_CUSTOM_TYPE_KEYS (-2) +#define TCL_CUSTOM_PTR_KEYS (-1) + +/* + * Structure definition for information used to keep track of searches through + * dictionaries. These fields should not be accessed by code outside + * tclDictObj.c + */ + +typedef struct { + void *next; /* Search position for underlying hash + * table. */ + int epoch; /* Epoch marker for dictionary being searched, + * or -1 if search has terminated. */ + Tcl_Dict dictionaryPtr; /* Reference to dictionary being searched. */ +} Tcl_DictSearch; + +/* + *---------------------------------------------------------------------------- + * 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; /* Function 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) (CONST86 Tcl_Time *timePtr); +typedef int (Tcl_WaitForEventProc) (CONST86 Tcl_Time *timePtr); + +/* + * TIP #233 (Virtualized Time) + */ + +typedef void (Tcl_GetTimeProc) (Tcl_Time *timebuf, ClientData clientData); +typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, ClientData clientData); + +/* + *---------------------------------------------------------------------------- + * 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) +#define TCL_CHANNEL_VERSION_5 ((Tcl_ChannelTypeVersion) 0x5) + +/* + * 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) (ClientData instanceData, int mode); +typedef int (Tcl_DriverCloseProc) (ClientData instanceData, + Tcl_Interp *interp); +typedef int (Tcl_DriverClose2Proc) (ClientData instanceData, + Tcl_Interp *interp, int flags); +typedef int (Tcl_DriverInputProc) (ClientData instanceData, char *buf, + int toRead, int *errorCodePtr); +typedef int (Tcl_DriverOutputProc) (ClientData instanceData, + CONST84 char *buf, int toWrite, int *errorCodePtr); +typedef int (Tcl_DriverSeekProc) (ClientData instanceData, long offset, + int mode, int *errorCodePtr); +typedef int (Tcl_DriverSetOptionProc) (ClientData instanceData, + Tcl_Interp *interp, const char *optionName, + const char *value); +typedef int (Tcl_DriverGetOptionProc) (ClientData instanceData, + Tcl_Interp *interp, CONST84 char *optionName, + Tcl_DString *dsPtr); +typedef void (Tcl_DriverWatchProc) (ClientData instanceData, int mask); +typedef int (Tcl_DriverGetHandleProc) (ClientData instanceData, + int direction, ClientData *handlePtr); +typedef int (Tcl_DriverFlushProc) (ClientData instanceData); +typedef int (Tcl_DriverHandlerProc) (ClientData instanceData, + int interestMask); +typedef Tcl_WideInt (Tcl_DriverWideSeekProc) (ClientData instanceData, + Tcl_WideInt offset, int mode, int *errorCodePtr); +/* + * TIP #218, Channel Thread Actions + */ +typedef void (Tcl_DriverThreadActionProc) (ClientData instanceData, + int action); +/* + * TIP #208, File Truncation (etc.) + */ +typedef int (Tcl_DriverTruncateProc) (ClientData instanceData, + Tcl_WideInt length); + +/* + * 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 { + const 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; + /* Function to call to close the channel, or + * TCL_CLOSE2PROC if the close2Proc should be + * used instead. */ + Tcl_DriverInputProc *inputProc; + /* Function to call for input on channel. */ + Tcl_DriverOutputProc *outputProc; + /* Function to call for output on channel. */ + Tcl_DriverSeekProc *seekProc; + /* Function 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; + /* Function 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; + /* Function to call to flush a channel. May be + * NULL. */ + Tcl_DriverHandlerProc *handlerProc; + /* Function 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; + /* Function 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; + /* Function to call to notify the driver of + * thread specific activity for a channel. May + * be NULL. */ + /* + * Only valid in TCL_CHANNEL_VERSION_5 channels or later. + * TIP #208, File Truncation. + */ + Tcl_DriverTruncateProc *truncateProc; + /* Function to call to truncate the underlying + * file to a particular length. May be NULL if + * the channel does not support truncation. */ +} 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 function 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 { + int type; /* Corresponds to bcdpfls as in 'find -t'. */ + int perm; /* Corresponds to file permissions. */ + Tcl_Obj *macType; /* Acceptable Mac type. */ + Tcl_Obj *macCreator; /* Acceptable Mac creator. */ +} 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) + +/* + * Flags for the unload callback function. + */ + +#define TCL_UNLOAD_DETACH_FROM_INTERPRETER (1<<0) +#define TCL_UNLOAD_DETACH_FROM_PROCESS (1<<1) + +/* + * Typedefs for the various filesystem operations: + */ + +typedef int (Tcl_FSStatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +typedef int (Tcl_FSAccessProc) (Tcl_Obj *pathPtr, int mode); +typedef Tcl_Channel (Tcl_FSOpenFileChannelProc) (Tcl_Interp *interp, + Tcl_Obj *pathPtr, int mode, int permissions); +typedef int (Tcl_FSMatchInDirectoryProc) (Tcl_Interp *interp, Tcl_Obj *result, + Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); +typedef Tcl_Obj * (Tcl_FSGetCwdProc) (Tcl_Interp *interp); +typedef int (Tcl_FSChdirProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSLstatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +typedef int (Tcl_FSCreateDirectoryProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSDeleteFileProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSCopyDirectoryProc) (Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); +typedef int (Tcl_FSCopyFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); +typedef int (Tcl_FSRemoveDirectoryProc) (Tcl_Obj *pathPtr, int recursive, + Tcl_Obj **errorPtr); +typedef int (Tcl_FSRenameFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); +typedef void (Tcl_FSUnloadFileProc) (Tcl_LoadHandle loadHandle); +typedef Tcl_Obj * (Tcl_FSListVolumesProc) (void); +/* We have to declare the utime structure here. */ +struct utimbuf; +typedef int (Tcl_FSUtimeProc) (Tcl_Obj *pathPtr, struct utimbuf *tval); +typedef int (Tcl_FSNormalizePathProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + int nextCheckpoint); +typedef int (Tcl_FSFileAttrsGetProc) (Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); +typedef const char *CONST86 * (Tcl_FSFileAttrStringsProc) (Tcl_Obj *pathPtr, + Tcl_Obj **objPtrRef); +typedef int (Tcl_FSFileAttrsSetProc) (Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj *objPtr); +typedef Tcl_Obj * (Tcl_FSLinkProc) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, + int linkType); +typedef int (Tcl_FSLoadFileProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); +typedef int (Tcl_FSPathInFilesystemProc) (Tcl_Obj *pathPtr, + ClientData *clientDataPtr); +typedef Tcl_Obj * (Tcl_FSFilesystemPathTypeProc) (Tcl_Obj *pathPtr); +typedef Tcl_Obj * (Tcl_FSFilesystemSeparatorProc) (Tcl_Obj *pathPtr); +typedef void (Tcl_FSFreeInternalRepProc) (ClientData clientData); +typedef ClientData (Tcl_FSDupInternalRepProc) (ClientData clientData); +typedef Tcl_Obj * (Tcl_FSInternalToNormalizedProc) (ClientData clientData); +typedef ClientData (Tcl_FSCreateInternalRepProc) (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 function. */ + 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 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 an + * 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. + * TCL_TOKEN_EXPAND_WORD - This token is just like TCL_TOKEN_WORD except + * that it marks a word that began with the + * literal character prefix "{*}". This word is + * marked to be expanded - that is, broken into + * words after substitution is complete. + */ + +#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 +#define TCL_TOKEN_EXPAND_WORD 256 + +/* + * 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 functions 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 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; + /* Function to convert from external encoding + * into UTF-8. */ + Tcl_EncodingConvertProc *fromUtfProc; + /* Function to convert from UTF-8 into + * external encoding. */ + Tcl_EncodingFreeProc *freeProc; + /* If non-NULL, function to call when this + * encoding is deleted. */ + ClientData clientData; /* Arbitrary value associated with encoding + * type. Passed to conversion functions. */ + 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 function 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 + * convert the source. + * TCL_ENCODING_NO_TERMINATE - If set, Tcl_ExternalToUtf will not append a + * terminating NUL byte. Knowing that it will + * not need space to do so, it will fill all + * dstLen bytes with encoded UTF-8 content, as + * other circumstances permit. If clear, the + * default behavior is to reserve a byte in + * the dst space for NUL termination, and to + * append the NUL byte. + * TCL_ENCODING_CHAR_LIMIT - If set and dstCharsPtr is not NULL, then + * Tcl_ExternalToUtf takes the initial value + * of *dstCharsPtr is taken as a limit of the + * maximum number of chars to produce in the + * encoded UTF-8 content. Otherwise, the + * number of chars produced is controlled only + * by other limiting factors. + */ + +#define TCL_ENCODING_START 0x01 +#define TCL_ENCODING_END 0x02 +#define TCL_ENCODING_STOPONERROR 0x04 +#define TCL_ENCODING_NO_TERMINATE 0x08 +#define TCL_ENCODING_CHAR_LIMIT 0x10 + +/* + * 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, 4 or 6 + * (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or + * 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the 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 + +/* + *---------------------------------------------------------------------------- + * TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to + * provide the system with the embedded configuration data. + */ + +typedef struct Tcl_Config { + const char *key; /* Configuration key to register. ASCII + * encoded, thus UTF-8. */ + const char *value; /* The value associated with the key. System + * encoding. */ +} Tcl_Config; + +/* + *---------------------------------------------------------------------------- + * Flags for TIP#143 limits, detailing which limits are active in an + * interpreter. Used for Tcl_{Add,Remove}LimitHandler type argument. + */ + +#define TCL_LIMIT_COMMANDS 0x01 +#define TCL_LIMIT_TIME 0x02 + +/* + * Structure containing information about a limit handler to be called when a + * command- or time-limit is exceeded by an interpreter. + */ + +typedef void (Tcl_LimitHandlerProc) (ClientData clientData, Tcl_Interp *interp); +typedef void (Tcl_LimitHandlerDeleteProc) (ClientData clientData); + +/* + *---------------------------------------------------------------------------- + * Override definitions for libtommath. + */ + +typedef struct mp_int mp_int; +#define MP_INT_DECLARED +typedef unsigned int mp_digit; +#define MP_DIGIT_DECLARED + +/* + *---------------------------------------------------------------------------- + * Definitions needed for Tcl_ParseArgvObj routines. + * Based on tkArgv.c. + * Modifications from the original are copyright (c) Sam Bromley 2006 + */ + +typedef struct { + int type; /* Indicates the option type; see below. */ + const char *keyStr; /* The key string that flags the option in the + * argv array. */ + void *srcPtr; /* Value to be used in setting dst; usage + * depends on type.*/ + void *dstPtr; /* Address of value to be modified; usage + * depends on type.*/ + const char *helpStr; /* Documentation message describing this + * option. */ + ClientData clientData; /* Word to pass to function callbacks. */ +} Tcl_ArgvInfo; + +/* + * Legal values for the type field of a Tcl_ArgInfo: see the user + * documentation for details. + */ + +#define TCL_ARGV_CONSTANT 15 +#define TCL_ARGV_INT 16 +#define TCL_ARGV_STRING 17 +#define TCL_ARGV_REST 18 +#define TCL_ARGV_FLOAT 19 +#define TCL_ARGV_FUNC 20 +#define TCL_ARGV_GENFUNC 21 +#define TCL_ARGV_HELP 22 +#define TCL_ARGV_END 23 + +/* + * Types of callback functions for the TCL_ARGV_FUNC and TCL_ARGV_GENFUNC + * argument types: + */ + +typedef int (Tcl_ArgvFuncProc)(ClientData clientData, Tcl_Obj *objPtr, + void *dstPtr); +typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv, void *dstPtr); + +/* + * Shorthand for commonly used argTable entries. + */ + +#define TCL_ARGV_AUTO_HELP \ + {TCL_ARGV_HELP, "-help", NULL, NULL, \ + "Print summary of command-line options and abort", NULL} +#define TCL_ARGV_AUTO_REST \ + {TCL_ARGV_REST, "--", NULL, NULL, \ + "Marks the end of the options", NULL} +#define TCL_ARGV_TABLE_END \ + {TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL} + +/* + *---------------------------------------------------------------------------- + * Definitions needed for Tcl_Zlib routines. [TIP #234] + * + * Constants for the format flags describing what sort of data format is + * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and + * Tcl_ZlibStreamInit functions. + */ + +#define TCL_ZLIB_FORMAT_RAW 1 +#define TCL_ZLIB_FORMAT_ZLIB 2 +#define TCL_ZLIB_FORMAT_GZIP 4 +#define TCL_ZLIB_FORMAT_AUTO 8 + +/* + * Constants that describe whether the stream is to operate in compressing or + * decompressing mode. + */ + +#define TCL_ZLIB_STREAM_DEFLATE 16 +#define TCL_ZLIB_STREAM_INFLATE 32 + +/* + * Constants giving compression levels. Use of TCL_ZLIB_COMPRESS_DEFAULT is + * recommended. + */ + +#define TCL_ZLIB_COMPRESS_NONE 0 +#define TCL_ZLIB_COMPRESS_FAST 1 +#define TCL_ZLIB_COMPRESS_BEST 9 +#define TCL_ZLIB_COMPRESS_DEFAULT (-1) + +/* + * Constants for types of flushing, used with Tcl_ZlibFlush. + */ + +#define TCL_ZLIB_NO_FLUSH 0 +#define TCL_ZLIB_FLUSH 2 +#define TCL_ZLIB_FULLFLUSH 3 +#define TCL_ZLIB_FINALIZE 4 + +/* + *---------------------------------------------------------------------------- + * Definitions needed for the Tcl_LoadFile function. [TIP #416] + */ + +#define TCL_LOAD_GLOBAL 1 +#define TCL_LOAD_LAZY 2 + +/* + *---------------------------------------------------------------------------- + * Single public declaration for NRE. + */ + +typedef int (Tcl_NRPostProc) (ClientData data[], Tcl_Interp *interp, + int result); + +/* + *---------------------------------------------------------------------------- + * 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. + */ + +const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version, + int exact); +const char * TclTomMathInitializeStubs(Tcl_Interp *interp, + const char *version, int epoch, int revision); + +/* + * When not using stubs, make it a macro. + */ + +#ifndef USE_TCL_STUBS +#define Tcl_InitStubs(interp, version, exact) \ + Tcl_PkgInitStubsCheck(interp, version, exact) +#endif + +/* + * TODO - tommath stubs export goes here! + */ + +/* + * Public functions that are not accessible via the stubs table. + * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171] + */ + +#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ + ((Tcl_CreateInterp)())) +EXTERN void Tcl_MainEx(int argc, char **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, + const char *version, int exact); +EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); + +/* + *---------------------------------------------------------------------------- + * 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. Make all TclOO symbols MODULE_SCOPE (which only + * has effect on building it as a shared library). See ticket [3010352]. + */ + +#if defined(BUILD_tcl) +# undef TCLAPI +# define TCLAPI MODULE_SCOPE +#endif + +#include "tclPlatDecls.h" + +/* + *---------------------------------------------------------------------------- + * The following declarations either map ckalloc and ckfree to malloc and + * free, or they map them to functions with all sorts of debugging hooks + * defined in tclCkalloc.c. + */ + +#ifdef TCL_MEM_DEBUG + +# define ckalloc(x) \ + ((void *) Tcl_DbCkalloc((unsigned)(x), __FILE__, __LINE__)) +# define ckfree(x) \ + Tcl_DbCkfree((char *)(x), __FILE__, __LINE__) +# define ckrealloc(x,y) \ + ((void *) Tcl_DbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__)) +# define attemptckalloc(x) \ + ((void *) Tcl_AttemptDbCkalloc((unsigned)(x), __FILE__, __LINE__)) +# define attemptckrealloc(x,y) \ + ((void *) Tcl_AttemptDbCkrealloc((char *)(x), (unsigned)(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) \ + ((void *) Tcl_Alloc((unsigned)(x))) +# define ckfree(x) \ + Tcl_Free((char *)(x)) +# define ckrealloc(x,y) \ + ((void *) Tcl_Realloc((char *)(x), (unsigned)(y))) +# define attemptckalloc(x) \ + ((void *) Tcl_AttemptAlloc((unsigned)(x))) +# define attemptckrealloc(x,y) \ + ((void *) Tcl_AttemptRealloc((char *)(x), (unsigned)(y))) +# undef Tcl_InitMemory +# define Tcl_InitMemory(x) +# undef Tcl_DumpActiveMemory +# define Tcl_DumpActiveMemory(x) +# undef Tcl_ValidateAllMemory +# define Tcl_ValidateAllMemory(x,y) + +#endif /* !TCL_MEM_DEBUG */ + +#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 functions. + */ + +#ifdef TCL_MEM_DEBUG +# undef Tcl_NewBignumObj +# define Tcl_NewBignumObj(val) \ + Tcl_DbNewBignumObj(val, __FILE__, __LINE__) +# undef Tcl_NewBooleanObj +# define Tcl_NewBooleanObj(val) \ + Tcl_DbNewBooleanObj(val, __FILE__, __LINE__) +# undef Tcl_NewByteArrayObj +# define Tcl_NewByteArrayObj(bytes, len) \ + Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__) +# undef Tcl_NewDoubleObj +# define Tcl_NewDoubleObj(val) \ + Tcl_DbNewDoubleObj(val, __FILE__, __LINE__) +# undef Tcl_NewIntObj +# define Tcl_NewIntObj(val) \ + Tcl_DbNewLongObj(val, __FILE__, __LINE__) +# undef Tcl_NewListObj +# define Tcl_NewListObj(objc, objv) \ + Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__) +# undef Tcl_NewLongObj +# define Tcl_NewLongObj(val) \ + Tcl_DbNewLongObj(val, __FILE__, __LINE__) +# undef Tcl_NewObj +# define Tcl_NewObj() \ + Tcl_DbNewObj(__FILE__, __LINE__) +# undef Tcl_NewStringObj +# define Tcl_NewStringObj(bytes, len) \ + Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__) +# undef Tcl_NewWideIntObj +# define Tcl_NewWideIntObj(val) \ + Tcl_DbNewWideIntObj(val, __FILE__, __LINE__) +#endif /* TCL_MEM_DEBUG */ + +/* + *---------------------------------------------------------------------------- + * 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)) +#define Tcl_GetHashKey(tablePtr, h) \ + ((void *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \ + (tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \ + ? (h)->key.oneWordValue \ + : (h)->key.string)) + +/* + * Macros to use for clients to use to invoke find and create functions for + * hash tables: + */ + +#undef Tcl_FindHashEntry +#define Tcl_FindHashEntry(tablePtr, key) \ + (*((tablePtr)->findProc))(tablePtr, (const char *)(key)) +#undef Tcl_CreateHashEntry +#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ + (*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr) + +/* + *---------------------------------------------------------------------------- + * Macros that eliminate the overhead of the thread synchronization functions + * when compiling without thread support. + */ + +#ifndef TCL_THREADS +#undef Tcl_MutexLock +#define Tcl_MutexLock(mutexPtr) +#undef Tcl_MutexUnlock +#define Tcl_MutexUnlock(mutexPtr) +#undef Tcl_MutexFinalize +#define Tcl_MutexFinalize(mutexPtr) +#undef Tcl_ConditionNotify +#define Tcl_ConditionNotify(condPtr) +#undef Tcl_ConditionWait +#define Tcl_ConditionWait(condPtr, mutexPtr, timePtr) +#undef Tcl_ConditionFinalize +#define Tcl_ConditionFinalize(condPtr) +#endif /* TCL_THREADS */ + +/* + *---------------------------------------------------------------------------- + * Deprecated Tcl functions: + */ + +#ifndef TCL_NO_DEPRECATED +/* + * 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 +#endif /* !TCL_NO_DEPRECATED */ + +/* + *---------------------------------------------------------------------------- + * 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. + */ + +extern Tcl_AppInitProc Tcl_AppInit; + +#endif /* RC_INVOKED */ + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TCL */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tclDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tclDecls.h new file mode 100644 index 00000000..91c0add2 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tclDecls.h @@ -0,0 +1,3917 @@ +/* + * 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 + +#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 + +/* + * 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. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +/* 0 */ +EXTERN int Tcl_PkgProvideEx(Tcl_Interp *interp, + const char *name, const char *version, + const void *clientData); +/* 1 */ +EXTERN CONST84_RETURN char * Tcl_PkgRequireEx(Tcl_Interp *interp, + const char *name, const char *version, + int exact, void *clientDataPtr); +/* 2 */ +EXTERN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); +/* 3 */ +EXTERN char * Tcl_Alloc(unsigned int size); +/* 4 */ +EXTERN void Tcl_Free(char *ptr); +/* 5 */ +EXTERN char * Tcl_Realloc(char *ptr, unsigned int size); +/* 6 */ +EXTERN char * Tcl_DbCkalloc(unsigned int size, const char *file, + int line); +/* 7 */ +EXTERN void Tcl_DbCkfree(char *ptr, const char *file, int line); +/* 8 */ +EXTERN char * Tcl_DbCkrealloc(char *ptr, unsigned int size, + const char *file, int line); +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +/* 9 */ +EXTERN void Tcl_CreateFileHandler(int fd, int mask, + Tcl_FileProc *proc, ClientData clientData); +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 9 */ +EXTERN void Tcl_CreateFileHandler(int fd, int mask, + Tcl_FileProc *proc, ClientData clientData); +#endif /* MACOSX */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +/* 10 */ +EXTERN void Tcl_DeleteFileHandler(int fd); +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 10 */ +EXTERN void Tcl_DeleteFileHandler(int fd); +#endif /* MACOSX */ +/* 11 */ +EXTERN void Tcl_SetTimer(const Tcl_Time *timePtr); +/* 12 */ +EXTERN void Tcl_Sleep(int ms); +/* 13 */ +EXTERN int Tcl_WaitForEvent(const Tcl_Time *timePtr); +/* 14 */ +EXTERN int Tcl_AppendAllObjTypes(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 15 */ +EXTERN void Tcl_AppendStringsToObj(Tcl_Obj *objPtr, ...); +/* 16 */ +EXTERN void Tcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes, + int length); +/* 17 */ +EXTERN Tcl_Obj * Tcl_ConcatObj(int objc, Tcl_Obj *const objv[]); +/* 18 */ +EXTERN int Tcl_ConvertToType(Tcl_Interp *interp, + Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); +/* 19 */ +EXTERN void Tcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file, + int line); +/* 20 */ +EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file, + int line); +/* 21 */ +EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, + int line); +/* 22 */ +EXTERN Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file, + int line); +/* 23 */ +EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes, + int length, const char *file, int line); +/* 24 */ +EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue, + const char *file, int line); +/* 25 */ +EXTERN Tcl_Obj * Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv, + const char *file, int line); +/* 26 */ +EXTERN Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file, + int line); +/* 27 */ +EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line); +/* 28 */ +EXTERN Tcl_Obj * Tcl_DbNewStringObj(const char *bytes, int length, + const char *file, int line); +/* 29 */ +EXTERN Tcl_Obj * Tcl_DuplicateObj(Tcl_Obj *objPtr); +/* 30 */ +EXTERN void TclFreeObj(Tcl_Obj *objPtr); +/* 31 */ +EXTERN int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, + int *boolPtr); +/* 32 */ +EXTERN int Tcl_GetBooleanFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *boolPtr); +/* 33 */ +EXTERN unsigned char * Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, + int *lengthPtr); +/* 34 */ +EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src, + double *doublePtr); +/* 35 */ +EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, double *doublePtr); +/* 36 */ +EXTERN int Tcl_GetIndexFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, + CONST84 char *const *tablePtr, + const char *msg, int flags, int *indexPtr); +/* 37 */ +EXTERN int Tcl_GetInt(Tcl_Interp *interp, const char *src, + int *intPtr); +/* 38 */ +EXTERN int Tcl_GetIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *intPtr); +/* 39 */ +EXTERN int Tcl_GetLongFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, long *longPtr); +/* 40 */ +EXTERN CONST86 Tcl_ObjType * Tcl_GetObjType(const char *typeName); +/* 41 */ +EXTERN char * Tcl_GetStringFromObj(Tcl_Obj *objPtr, int *lengthPtr); +/* 42 */ +EXTERN void Tcl_InvalidateStringRep(Tcl_Obj *objPtr); +/* 43 */ +EXTERN int Tcl_ListObjAppendList(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); +/* 44 */ +EXTERN int Tcl_ListObjAppendElement(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Obj *objPtr); +/* 45 */ +EXTERN int Tcl_ListObjGetElements(Tcl_Interp *interp, + Tcl_Obj *listPtr, int *objcPtr, + Tcl_Obj ***objvPtr); +/* 46 */ +EXTERN int Tcl_ListObjIndex(Tcl_Interp *interp, + Tcl_Obj *listPtr, int index, + Tcl_Obj **objPtrPtr); +/* 47 */ +EXTERN int Tcl_ListObjLength(Tcl_Interp *interp, + Tcl_Obj *listPtr, int *lengthPtr); +/* 48 */ +EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp, + Tcl_Obj *listPtr, int first, int count, + int objc, Tcl_Obj *const objv[]); +/* 49 */ +EXTERN Tcl_Obj * Tcl_NewBooleanObj(int boolValue); +/* 50 */ +EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes, + int length); +/* 51 */ +EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue); +/* 52 */ +EXTERN Tcl_Obj * Tcl_NewIntObj(int intValue); +/* 53 */ +EXTERN Tcl_Obj * Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); +/* 54 */ +EXTERN Tcl_Obj * Tcl_NewLongObj(long longValue); +/* 55 */ +EXTERN Tcl_Obj * Tcl_NewObj(void); +/* 56 */ +EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, int length); +/* 57 */ +EXTERN void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue); +/* 58 */ +EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, int length); +/* 59 */ +EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr, + const unsigned char *bytes, int length); +/* 60 */ +EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue); +/* 61 */ +EXTERN void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue); +/* 62 */ +EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, int objc, + Tcl_Obj *const objv[]); +/* 63 */ +EXTERN void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue); +/* 64 */ +EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, int length); +/* 65 */ +EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, + int length); +/* 66 */ +EXTERN void Tcl_AddErrorInfo(Tcl_Interp *interp, + const char *message); +/* 67 */ +EXTERN void Tcl_AddObjErrorInfo(Tcl_Interp *interp, + const char *message, int length); +/* 68 */ +EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp); +/* 69 */ +EXTERN void Tcl_AppendElement(Tcl_Interp *interp, + const char *element); +/* 70 */ +EXTERN void Tcl_AppendResult(Tcl_Interp *interp, ...); +/* 71 */ +EXTERN Tcl_AsyncHandler Tcl_AsyncCreate(Tcl_AsyncProc *proc, + ClientData clientData); +/* 72 */ +EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async); +/* 73 */ +EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code); +/* 74 */ +EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async); +/* 75 */ +EXTERN int Tcl_AsyncReady(void); +/* 76 */ +EXTERN void Tcl_BackgroundError(Tcl_Interp *interp); +/* 77 */ +EXTERN char Tcl_Backslash(const char *src, int *readPtr); +/* 78 */ +EXTERN int Tcl_BadChannelOption(Tcl_Interp *interp, + const char *optionName, + const char *optionList); +/* 79 */ +EXTERN void Tcl_CallWhenDeleted(Tcl_Interp *interp, + Tcl_InterpDeleteProc *proc, + ClientData clientData); +/* 80 */ +EXTERN void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, + ClientData clientData); +/* 81 */ +EXTERN int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan); +/* 82 */ +EXTERN int Tcl_CommandComplete(const char *cmd); +/* 83 */ +EXTERN char * Tcl_Concat(int argc, CONST84 char *const *argv); +/* 84 */ +EXTERN int Tcl_ConvertElement(const char *src, char *dst, + int flags); +/* 85 */ +EXTERN int Tcl_ConvertCountedElement(const char *src, + int length, char *dst, int flags); +/* 86 */ +EXTERN int Tcl_CreateAlias(Tcl_Interp *slave, + const char *slaveCmd, Tcl_Interp *target, + const char *targetCmd, int argc, + CONST84 char *const *argv); +/* 87 */ +EXTERN int Tcl_CreateAliasObj(Tcl_Interp *slave, + const char *slaveCmd, Tcl_Interp *target, + const char *targetCmd, int objc, + Tcl_Obj *const objv[]); +/* 88 */ +EXTERN Tcl_Channel Tcl_CreateChannel(const Tcl_ChannelType *typePtr, + const char *chanName, + ClientData instanceData, int mask); +/* 89 */ +EXTERN void Tcl_CreateChannelHandler(Tcl_Channel chan, int mask, + Tcl_ChannelProc *proc, ClientData clientData); +/* 90 */ +EXTERN void Tcl_CreateCloseHandler(Tcl_Channel chan, + Tcl_CloseProc *proc, ClientData clientData); +/* 91 */ +EXTERN Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdProc *proc, + ClientData clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 92 */ +EXTERN void Tcl_CreateEventSource(Tcl_EventSetupProc *setupProc, + Tcl_EventCheckProc *checkProc, + ClientData clientData); +/* 93 */ +EXTERN void Tcl_CreateExitHandler(Tcl_ExitProc *proc, + ClientData clientData); +/* 94 */ +EXTERN Tcl_Interp * Tcl_CreateInterp(void); +/* 95 */ +EXTERN void Tcl_CreateMathFunc(Tcl_Interp *interp, + const char *name, int numArgs, + Tcl_ValueType *argTypes, Tcl_MathProc *proc, + ClientData clientData); +/* 96 */ +EXTERN Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc *proc, + ClientData clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 97 */ +EXTERN Tcl_Interp * Tcl_CreateSlave(Tcl_Interp *interp, + const char *slaveName, int isSafe); +/* 98 */ +EXTERN Tcl_TimerToken Tcl_CreateTimerHandler(int milliseconds, + Tcl_TimerProc *proc, ClientData clientData); +/* 99 */ +EXTERN Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, int level, + Tcl_CmdTraceProc *proc, + ClientData clientData); +/* 100 */ +EXTERN void Tcl_DeleteAssocData(Tcl_Interp *interp, + const char *name); +/* 101 */ +EXTERN void Tcl_DeleteChannelHandler(Tcl_Channel chan, + Tcl_ChannelProc *proc, ClientData clientData); +/* 102 */ +EXTERN void Tcl_DeleteCloseHandler(Tcl_Channel chan, + Tcl_CloseProc *proc, ClientData clientData); +/* 103 */ +EXTERN int Tcl_DeleteCommand(Tcl_Interp *interp, + const char *cmdName); +/* 104 */ +EXTERN int Tcl_DeleteCommandFromToken(Tcl_Interp *interp, + Tcl_Command command); +/* 105 */ +EXTERN void Tcl_DeleteEvents(Tcl_EventDeleteProc *proc, + ClientData clientData); +/* 106 */ +EXTERN void Tcl_DeleteEventSource(Tcl_EventSetupProc *setupProc, + Tcl_EventCheckProc *checkProc, + ClientData clientData); +/* 107 */ +EXTERN void Tcl_DeleteExitHandler(Tcl_ExitProc *proc, + ClientData clientData); +/* 108 */ +EXTERN void Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr); +/* 109 */ +EXTERN void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr); +/* 110 */ +EXTERN void Tcl_DeleteInterp(Tcl_Interp *interp); +/* 111 */ +EXTERN void Tcl_DetachPids(int numPids, Tcl_Pid *pidPtr); +/* 112 */ +EXTERN void Tcl_DeleteTimerHandler(Tcl_TimerToken token); +/* 113 */ +EXTERN void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace); +/* 114 */ +EXTERN void Tcl_DontCallWhenDeleted(Tcl_Interp *interp, + Tcl_InterpDeleteProc *proc, + ClientData clientData); +/* 115 */ +EXTERN int Tcl_DoOneEvent(int flags); +/* 116 */ +EXTERN void Tcl_DoWhenIdle(Tcl_IdleProc *proc, + ClientData clientData); +/* 117 */ +EXTERN char * Tcl_DStringAppend(Tcl_DString *dsPtr, + const char *bytes, int length); +/* 118 */ +EXTERN char * Tcl_DStringAppendElement(Tcl_DString *dsPtr, + const char *element); +/* 119 */ +EXTERN void Tcl_DStringEndSublist(Tcl_DString *dsPtr); +/* 120 */ +EXTERN void Tcl_DStringFree(Tcl_DString *dsPtr); +/* 121 */ +EXTERN void Tcl_DStringGetResult(Tcl_Interp *interp, + Tcl_DString *dsPtr); +/* 122 */ +EXTERN void Tcl_DStringInit(Tcl_DString *dsPtr); +/* 123 */ +EXTERN void Tcl_DStringResult(Tcl_Interp *interp, + Tcl_DString *dsPtr); +/* 124 */ +EXTERN void Tcl_DStringSetLength(Tcl_DString *dsPtr, int length); +/* 125 */ +EXTERN void Tcl_DStringStartSublist(Tcl_DString *dsPtr); +/* 126 */ +EXTERN int Tcl_Eof(Tcl_Channel chan); +/* 127 */ +EXTERN CONST84_RETURN char * Tcl_ErrnoId(void); +/* 128 */ +EXTERN CONST84_RETURN char * Tcl_ErrnoMsg(int err); +/* 129 */ +EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *script); +/* 130 */ +EXTERN int Tcl_EvalFile(Tcl_Interp *interp, + const char *fileName); +/* 131 */ +EXTERN int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr); +/* 132 */ +EXTERN void Tcl_EventuallyFree(ClientData clientData, + Tcl_FreeProc *freeProc); +/* 133 */ +EXTERN void Tcl_Exit(int status); +/* 134 */ +EXTERN int Tcl_ExposeCommand(Tcl_Interp *interp, + const char *hiddenCmdToken, + const char *cmdName); +/* 135 */ +EXTERN int Tcl_ExprBoolean(Tcl_Interp *interp, const char *expr, + int *ptr); +/* 136 */ +EXTERN int Tcl_ExprBooleanObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *ptr); +/* 137 */ +EXTERN int Tcl_ExprDouble(Tcl_Interp *interp, const char *expr, + double *ptr); +/* 138 */ +EXTERN int Tcl_ExprDoubleObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, double *ptr); +/* 139 */ +EXTERN int Tcl_ExprLong(Tcl_Interp *interp, const char *expr, + long *ptr); +/* 140 */ +EXTERN int Tcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + long *ptr); +/* 141 */ +EXTERN int Tcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + Tcl_Obj **resultPtrPtr); +/* 142 */ +EXTERN int Tcl_ExprString(Tcl_Interp *interp, const char *expr); +/* 143 */ +EXTERN void Tcl_Finalize(void); +/* 144 */ +EXTERN void Tcl_FindExecutable(const char *argv0); +/* 145 */ +EXTERN Tcl_HashEntry * Tcl_FirstHashEntry(Tcl_HashTable *tablePtr, + Tcl_HashSearch *searchPtr); +/* 146 */ +EXTERN int Tcl_Flush(Tcl_Channel chan); +/* 147 */ +EXTERN void Tcl_FreeResult(Tcl_Interp *interp); +/* 148 */ +EXTERN int Tcl_GetAlias(Tcl_Interp *interp, + const char *slaveCmd, + Tcl_Interp **targetInterpPtr, + CONST84 char **targetCmdPtr, int *argcPtr, + CONST84 char ***argvPtr); +/* 149 */ +EXTERN int Tcl_GetAliasObj(Tcl_Interp *interp, + const char *slaveCmd, + Tcl_Interp **targetInterpPtr, + CONST84 char **targetCmdPtr, int *objcPtr, + Tcl_Obj ***objv); +/* 150 */ +EXTERN ClientData Tcl_GetAssocData(Tcl_Interp *interp, + const char *name, + Tcl_InterpDeleteProc **procPtr); +/* 151 */ +EXTERN Tcl_Channel Tcl_GetChannel(Tcl_Interp *interp, + const char *chanName, int *modePtr); +/* 152 */ +EXTERN int Tcl_GetChannelBufferSize(Tcl_Channel chan); +/* 153 */ +EXTERN int Tcl_GetChannelHandle(Tcl_Channel chan, int direction, + ClientData *handlePtr); +/* 154 */ +EXTERN ClientData Tcl_GetChannelInstanceData(Tcl_Channel chan); +/* 155 */ +EXTERN int Tcl_GetChannelMode(Tcl_Channel chan); +/* 156 */ +EXTERN CONST84_RETURN char * Tcl_GetChannelName(Tcl_Channel chan); +/* 157 */ +EXTERN int Tcl_GetChannelOption(Tcl_Interp *interp, + Tcl_Channel chan, const char *optionName, + Tcl_DString *dsPtr); +/* 158 */ +EXTERN CONST86 Tcl_ChannelType * Tcl_GetChannelType(Tcl_Channel chan); +/* 159 */ +EXTERN int Tcl_GetCommandInfo(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdInfo *infoPtr); +/* 160 */ +EXTERN CONST84_RETURN char * Tcl_GetCommandName(Tcl_Interp *interp, + Tcl_Command command); +/* 161 */ +EXTERN int Tcl_GetErrno(void); +/* 162 */ +EXTERN CONST84_RETURN char * Tcl_GetHostName(void); +/* 163 */ +EXTERN int Tcl_GetInterpPath(Tcl_Interp *askInterp, + Tcl_Interp *slaveInterp); +/* 164 */ +EXTERN Tcl_Interp * Tcl_GetMaster(Tcl_Interp *interp); +/* 165 */ +EXTERN const char * Tcl_GetNameOfExecutable(void); +/* 166 */ +EXTERN Tcl_Obj * Tcl_GetObjResult(Tcl_Interp *interp); +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +/* 167 */ +EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, + const char *chanID, int forWriting, + int checkUsage, ClientData *filePtr); +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 167 */ +EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, + const char *chanID, int forWriting, + int checkUsage, ClientData *filePtr); +#endif /* MACOSX */ +/* 168 */ +EXTERN Tcl_PathType Tcl_GetPathType(const char *path); +/* 169 */ +EXTERN int Tcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr); +/* 170 */ +EXTERN int Tcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr); +/* 171 */ +EXTERN int Tcl_GetServiceMode(void); +/* 172 */ +EXTERN Tcl_Interp * Tcl_GetSlave(Tcl_Interp *interp, + const char *slaveName); +/* 173 */ +EXTERN Tcl_Channel Tcl_GetStdChannel(int type); +/* 174 */ +EXTERN CONST84_RETURN char * Tcl_GetStringResult(Tcl_Interp *interp); +/* 175 */ +EXTERN CONST84_RETURN char * Tcl_GetVar(Tcl_Interp *interp, + const char *varName, int flags); +/* 176 */ +EXTERN CONST84_RETURN char * Tcl_GetVar2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags); +/* 177 */ +EXTERN int Tcl_GlobalEval(Tcl_Interp *interp, + const char *command); +/* 178 */ +EXTERN int Tcl_GlobalEvalObj(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 179 */ +EXTERN int Tcl_HideCommand(Tcl_Interp *interp, + const char *cmdName, + const char *hiddenCmdToken); +/* 180 */ +EXTERN int Tcl_Init(Tcl_Interp *interp); +/* 181 */ +EXTERN void Tcl_InitHashTable(Tcl_HashTable *tablePtr, + int keyType); +/* 182 */ +EXTERN int Tcl_InputBlocked(Tcl_Channel chan); +/* 183 */ +EXTERN int Tcl_InputBuffered(Tcl_Channel chan); +/* 184 */ +EXTERN int Tcl_InterpDeleted(Tcl_Interp *interp); +/* 185 */ +EXTERN int Tcl_IsSafe(Tcl_Interp *interp); +/* 186 */ +EXTERN char * Tcl_JoinPath(int argc, CONST84 char *const *argv, + Tcl_DString *resultPtr); +/* 187 */ +EXTERN int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, + char *addr, int type); +/* Slot 188 is reserved */ +/* 189 */ +EXTERN Tcl_Channel Tcl_MakeFileChannel(ClientData handle, int mode); +/* 190 */ +EXTERN int Tcl_MakeSafe(Tcl_Interp *interp); +/* 191 */ +EXTERN Tcl_Channel Tcl_MakeTcpClientChannel(ClientData tcpSocket); +/* 192 */ +EXTERN char * Tcl_Merge(int argc, CONST84 char *const *argv); +/* 193 */ +EXTERN Tcl_HashEntry * Tcl_NextHashEntry(Tcl_HashSearch *searchPtr); +/* 194 */ +EXTERN void Tcl_NotifyChannel(Tcl_Channel channel, int mask); +/* 195 */ +EXTERN Tcl_Obj * Tcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, + Tcl_Obj *part2Ptr, int flags); +/* 196 */ +EXTERN Tcl_Obj * Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, + Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, + int flags); +/* 197 */ +EXTERN Tcl_Channel Tcl_OpenCommandChannel(Tcl_Interp *interp, int argc, + CONST84 char **argv, int flags); +/* 198 */ +EXTERN Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp, + const char *fileName, const char *modeString, + int permissions); +/* 199 */ +EXTERN Tcl_Channel Tcl_OpenTcpClient(Tcl_Interp *interp, int port, + const char *address, const char *myaddr, + int myport, int async); +/* 200 */ +EXTERN Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port, + const char *host, + Tcl_TcpAcceptProc *acceptProc, + ClientData callbackData); +/* 201 */ +EXTERN void Tcl_Preserve(ClientData data); +/* 202 */ +EXTERN void Tcl_PrintDouble(Tcl_Interp *interp, double value, + char *dst); +/* 203 */ +EXTERN int Tcl_PutEnv(const char *assignment); +/* 204 */ +EXTERN CONST84_RETURN char * Tcl_PosixError(Tcl_Interp *interp); +/* 205 */ +EXTERN void Tcl_QueueEvent(Tcl_Event *evPtr, + Tcl_QueuePosition position); +/* 206 */ +EXTERN int Tcl_Read(Tcl_Channel chan, char *bufPtr, int toRead); +/* 207 */ +EXTERN void Tcl_ReapDetachedProcs(void); +/* 208 */ +EXTERN int Tcl_RecordAndEval(Tcl_Interp *interp, + const char *cmd, int flags); +/* 209 */ +EXTERN int Tcl_RecordAndEvalObj(Tcl_Interp *interp, + Tcl_Obj *cmdPtr, int flags); +/* 210 */ +EXTERN void Tcl_RegisterChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 211 */ +EXTERN void Tcl_RegisterObjType(const Tcl_ObjType *typePtr); +/* 212 */ +EXTERN Tcl_RegExp Tcl_RegExpCompile(Tcl_Interp *interp, + const char *pattern); +/* 213 */ +EXTERN int Tcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp, + const char *text, const char *start); +/* 214 */ +EXTERN int Tcl_RegExpMatch(Tcl_Interp *interp, const char *text, + const char *pattern); +/* 215 */ +EXTERN void Tcl_RegExpRange(Tcl_RegExp regexp, int index, + CONST84 char **startPtr, + CONST84 char **endPtr); +/* 216 */ +EXTERN void Tcl_Release(ClientData clientData); +/* 217 */ +EXTERN void Tcl_ResetResult(Tcl_Interp *interp); +/* 218 */ +EXTERN int Tcl_ScanElement(const char *src, int *flagPtr); +/* 219 */ +EXTERN int Tcl_ScanCountedElement(const char *src, int length, + int *flagPtr); +/* 220 */ +EXTERN int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode); +/* 221 */ +EXTERN int Tcl_ServiceAll(void); +/* 222 */ +EXTERN int Tcl_ServiceEvent(int flags); +/* 223 */ +EXTERN void Tcl_SetAssocData(Tcl_Interp *interp, + const char *name, Tcl_InterpDeleteProc *proc, + ClientData clientData); +/* 224 */ +EXTERN void Tcl_SetChannelBufferSize(Tcl_Channel chan, int sz); +/* 225 */ +EXTERN int Tcl_SetChannelOption(Tcl_Interp *interp, + Tcl_Channel chan, const char *optionName, + const char *newValue); +/* 226 */ +EXTERN int Tcl_SetCommandInfo(Tcl_Interp *interp, + const char *cmdName, + const Tcl_CmdInfo *infoPtr); +/* 227 */ +EXTERN void Tcl_SetErrno(int err); +/* 228 */ +EXTERN void Tcl_SetErrorCode(Tcl_Interp *interp, ...); +/* 229 */ +EXTERN void Tcl_SetMaxBlockTime(const Tcl_Time *timePtr); +/* 230 */ +EXTERN void Tcl_SetPanicProc(Tcl_PanicProc *panicProc); +/* 231 */ +EXTERN int Tcl_SetRecursionLimit(Tcl_Interp *interp, int depth); +/* 232 */ +EXTERN void Tcl_SetResult(Tcl_Interp *interp, char *result, + Tcl_FreeProc *freeProc); +/* 233 */ +EXTERN int Tcl_SetServiceMode(int mode); +/* 234 */ +EXTERN void Tcl_SetObjErrorCode(Tcl_Interp *interp, + Tcl_Obj *errorObjPtr); +/* 235 */ +EXTERN void Tcl_SetObjResult(Tcl_Interp *interp, + Tcl_Obj *resultObjPtr); +/* 236 */ +EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type); +/* 237 */ +EXTERN CONST84_RETURN char * Tcl_SetVar(Tcl_Interp *interp, + const char *varName, const char *newValue, + int flags); +/* 238 */ +EXTERN CONST84_RETURN char * Tcl_SetVar2(Tcl_Interp *interp, + const char *part1, const char *part2, + const char *newValue, int flags); +/* 239 */ +EXTERN CONST84_RETURN char * Tcl_SignalId(int sig); +/* 240 */ +EXTERN CONST84_RETURN char * Tcl_SignalMsg(int sig); +/* 241 */ +EXTERN void Tcl_SourceRCFile(Tcl_Interp *interp); +/* 242 */ +EXTERN int Tcl_SplitList(Tcl_Interp *interp, + const char *listStr, int *argcPtr, + CONST84 char ***argvPtr); +/* 243 */ +EXTERN void Tcl_SplitPath(const char *path, int *argcPtr, + CONST84 char ***argvPtr); +/* 244 */ +EXTERN void Tcl_StaticPackage(Tcl_Interp *interp, + const char *pkgName, + Tcl_PackageInitProc *initProc, + Tcl_PackageInitProc *safeInitProc); +/* 245 */ +EXTERN int Tcl_StringMatch(const char *str, const char *pattern); +/* 246 */ +EXTERN int Tcl_TellOld(Tcl_Channel chan); +/* 247 */ +EXTERN int Tcl_TraceVar(Tcl_Interp *interp, const char *varName, + int flags, Tcl_VarTraceProc *proc, + ClientData clientData); +/* 248 */ +EXTERN int Tcl_TraceVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags, + Tcl_VarTraceProc *proc, + ClientData clientData); +/* 249 */ +EXTERN char * Tcl_TranslateFileName(Tcl_Interp *interp, + const char *name, Tcl_DString *bufferPtr); +/* 250 */ +EXTERN int Tcl_Ungets(Tcl_Channel chan, const char *str, + int len, int atHead); +/* 251 */ +EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp, + const char *varName); +/* 252 */ +EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 253 */ +EXTERN int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName, + int flags); +/* 254 */ +EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* 255 */ +EXTERN void Tcl_UntraceVar(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_VarTraceProc *proc, + ClientData clientData); +/* 256 */ +EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags, Tcl_VarTraceProc *proc, + ClientData clientData); +/* 257 */ +EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp, + const char *varName); +/* 258 */ +EXTERN int Tcl_UpVar(Tcl_Interp *interp, const char *frameName, + const char *varName, const char *localName, + int flags); +/* 259 */ +EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName, + const char *part1, const char *part2, + const char *localName, int flags); +/* 260 */ +EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...); +/* 261 */ +EXTERN ClientData Tcl_VarTraceInfo(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_VarTraceProc *procPtr, + ClientData prevClientData); +/* 262 */ +EXTERN ClientData Tcl_VarTraceInfo2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags, Tcl_VarTraceProc *procPtr, + ClientData prevClientData); +/* 263 */ +EXTERN int Tcl_Write(Tcl_Channel chan, const char *s, int slen); +/* 264 */ +EXTERN void Tcl_WrongNumArgs(Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[], const char *message); +/* 265 */ +EXTERN int Tcl_DumpActiveMemory(const char *fileName); +/* 266 */ +EXTERN void Tcl_ValidateAllMemory(const char *file, int line); +/* 267 */ +EXTERN void Tcl_AppendResultVA(Tcl_Interp *interp, + va_list argList); +/* 268 */ +EXTERN void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, + va_list argList); +/* 269 */ +EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr); +/* 270 */ +EXTERN CONST84_RETURN char * Tcl_ParseVar(Tcl_Interp *interp, + const char *start, CONST84 char **termPtr); +/* 271 */ +EXTERN CONST84_RETURN char * Tcl_PkgPresent(Tcl_Interp *interp, + const char *name, const char *version, + int exact); +/* 272 */ +EXTERN CONST84_RETURN char * Tcl_PkgPresentEx(Tcl_Interp *interp, + const char *name, const char *version, + int exact, void *clientDataPtr); +/* 273 */ +EXTERN int Tcl_PkgProvide(Tcl_Interp *interp, const char *name, + const char *version); +/* 274 */ +EXTERN CONST84_RETURN char * Tcl_PkgRequire(Tcl_Interp *interp, + const char *name, const char *version, + int exact); +/* 275 */ +EXTERN void Tcl_SetErrorCodeVA(Tcl_Interp *interp, + va_list argList); +/* 276 */ +EXTERN int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList); +/* 277 */ +EXTERN Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options); +/* 278 */ +EXTERN void Tcl_PanicVA(const char *format, va_list argList); +/* 279 */ +EXTERN void Tcl_GetVersion(int *major, int *minor, + int *patchLevel, int *type); +/* 280 */ +EXTERN void Tcl_InitMemory(Tcl_Interp *interp); +/* 281 */ +EXTERN Tcl_Channel Tcl_StackChannel(Tcl_Interp *interp, + const Tcl_ChannelType *typePtr, + ClientData instanceData, int mask, + Tcl_Channel prevChan); +/* 282 */ +EXTERN int Tcl_UnstackChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 283 */ +EXTERN Tcl_Channel Tcl_GetStackedChannel(Tcl_Channel chan); +/* 284 */ +EXTERN void Tcl_SetMainLoop(Tcl_MainLoopProc *proc); +/* Slot 285 is reserved */ +/* 286 */ +EXTERN void Tcl_AppendObjToObj(Tcl_Obj *objPtr, + Tcl_Obj *appendObjPtr); +/* 287 */ +EXTERN Tcl_Encoding Tcl_CreateEncoding(const Tcl_EncodingType *typePtr); +/* 288 */ +EXTERN void Tcl_CreateThreadExitHandler(Tcl_ExitProc *proc, + ClientData clientData); +/* 289 */ +EXTERN void Tcl_DeleteThreadExitHandler(Tcl_ExitProc *proc, + ClientData clientData); +/* 290 */ +EXTERN void Tcl_DiscardResult(Tcl_SavedResult *statePtr); +/* 291 */ +EXTERN int Tcl_EvalEx(Tcl_Interp *interp, const char *script, + int numBytes, int flags); +/* 292 */ +EXTERN int Tcl_EvalObjv(Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[], int flags); +/* 293 */ +EXTERN int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 294 */ +EXTERN void Tcl_ExitThread(int status); +/* 295 */ +EXTERN 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); +/* 296 */ +EXTERN char * Tcl_ExternalToUtfDString(Tcl_Encoding encoding, + const char *src, int srcLen, + Tcl_DString *dsPtr); +/* 297 */ +EXTERN void Tcl_FinalizeThread(void); +/* 298 */ +EXTERN void Tcl_FinalizeNotifier(ClientData clientData); +/* 299 */ +EXTERN void Tcl_FreeEncoding(Tcl_Encoding encoding); +/* 300 */ +EXTERN Tcl_ThreadId Tcl_GetCurrentThread(void); +/* 301 */ +EXTERN Tcl_Encoding Tcl_GetEncoding(Tcl_Interp *interp, const char *name); +/* 302 */ +EXTERN CONST84_RETURN char * Tcl_GetEncodingName(Tcl_Encoding encoding); +/* 303 */ +EXTERN void Tcl_GetEncodingNames(Tcl_Interp *interp); +/* 304 */ +EXTERN int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp, + Tcl_Obj *objPtr, const void *tablePtr, + int offset, const char *msg, int flags, + int *indexPtr); +/* 305 */ +EXTERN void * Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, + int size); +/* 306 */ +EXTERN Tcl_Obj * Tcl_GetVar2Ex(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* 307 */ +EXTERN ClientData Tcl_InitNotifier(void); +/* 308 */ +EXTERN void Tcl_MutexLock(Tcl_Mutex *mutexPtr); +/* 309 */ +EXTERN void Tcl_MutexUnlock(Tcl_Mutex *mutexPtr); +/* 310 */ +EXTERN void Tcl_ConditionNotify(Tcl_Condition *condPtr); +/* 311 */ +EXTERN void Tcl_ConditionWait(Tcl_Condition *condPtr, + Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); +/* 312 */ +EXTERN int Tcl_NumUtfChars(const char *src, int length); +/* 313 */ +EXTERN int Tcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr, + int charsToRead, int appendFlag); +/* 314 */ +EXTERN void Tcl_RestoreResult(Tcl_Interp *interp, + Tcl_SavedResult *statePtr); +/* 315 */ +EXTERN void Tcl_SaveResult(Tcl_Interp *interp, + Tcl_SavedResult *statePtr); +/* 316 */ +EXTERN int Tcl_SetSystemEncoding(Tcl_Interp *interp, + const char *name); +/* 317 */ +EXTERN Tcl_Obj * Tcl_SetVar2Ex(Tcl_Interp *interp, const char *part1, + const char *part2, Tcl_Obj *newValuePtr, + int flags); +/* 318 */ +EXTERN void Tcl_ThreadAlert(Tcl_ThreadId threadId); +/* 319 */ +EXTERN void Tcl_ThreadQueueEvent(Tcl_ThreadId threadId, + Tcl_Event *evPtr, Tcl_QueuePosition position); +/* 320 */ +EXTERN Tcl_UniChar Tcl_UniCharAtIndex(const char *src, int index); +/* 321 */ +EXTERN Tcl_UniChar Tcl_UniCharToLower(int ch); +/* 322 */ +EXTERN Tcl_UniChar Tcl_UniCharToTitle(int ch); +/* 323 */ +EXTERN Tcl_UniChar Tcl_UniCharToUpper(int ch); +/* 324 */ +EXTERN int Tcl_UniCharToUtf(int ch, char *buf); +/* 325 */ +EXTERN CONST84_RETURN char * Tcl_UtfAtIndex(const char *src, int index); +/* 326 */ +EXTERN int Tcl_UtfCharComplete(const char *src, int length); +/* 327 */ +EXTERN int Tcl_UtfBackslash(const char *src, int *readPtr, + char *dst); +/* 328 */ +EXTERN CONST84_RETURN char * Tcl_UtfFindFirst(const char *src, int ch); +/* 329 */ +EXTERN CONST84_RETURN char * Tcl_UtfFindLast(const char *src, int ch); +/* 330 */ +EXTERN CONST84_RETURN char * Tcl_UtfNext(const char *src); +/* 331 */ +EXTERN CONST84_RETURN char * Tcl_UtfPrev(const char *src, const char *start); +/* 332 */ +EXTERN 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); +/* 333 */ +EXTERN char * Tcl_UtfToExternalDString(Tcl_Encoding encoding, + const char *src, int srcLen, + Tcl_DString *dsPtr); +/* 334 */ +EXTERN int Tcl_UtfToLower(char *src); +/* 335 */ +EXTERN int Tcl_UtfToTitle(char *src); +/* 336 */ +EXTERN int Tcl_UtfToUniChar(const char *src, Tcl_UniChar *chPtr); +/* 337 */ +EXTERN int Tcl_UtfToUpper(char *src); +/* 338 */ +EXTERN int Tcl_WriteChars(Tcl_Channel chan, const char *src, + int srcLen); +/* 339 */ +EXTERN int Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr); +/* 340 */ +EXTERN char * Tcl_GetString(Tcl_Obj *objPtr); +/* 341 */ +EXTERN CONST84_RETURN char * Tcl_GetDefaultEncodingDir(void); +/* 342 */ +EXTERN void Tcl_SetDefaultEncodingDir(const char *path); +/* 343 */ +EXTERN void Tcl_AlertNotifier(ClientData clientData); +/* 344 */ +EXTERN void Tcl_ServiceModeHook(int mode); +/* 345 */ +EXTERN int Tcl_UniCharIsAlnum(int ch); +/* 346 */ +EXTERN int Tcl_UniCharIsAlpha(int ch); +/* 347 */ +EXTERN int Tcl_UniCharIsDigit(int ch); +/* 348 */ +EXTERN int Tcl_UniCharIsLower(int ch); +/* 349 */ +EXTERN int Tcl_UniCharIsSpace(int ch); +/* 350 */ +EXTERN int Tcl_UniCharIsUpper(int ch); +/* 351 */ +EXTERN int Tcl_UniCharIsWordChar(int ch); +/* 352 */ +EXTERN int Tcl_UniCharLen(const Tcl_UniChar *uniStr); +/* 353 */ +EXTERN int Tcl_UniCharNcmp(const Tcl_UniChar *ucs, + const Tcl_UniChar *uct, + unsigned long numChars); +/* 354 */ +EXTERN char * Tcl_UniCharToUtfDString(const Tcl_UniChar *uniStr, + int uniLength, Tcl_DString *dsPtr); +/* 355 */ +EXTERN Tcl_UniChar * Tcl_UtfToUniCharDString(const char *src, int length, + Tcl_DString *dsPtr); +/* 356 */ +EXTERN Tcl_RegExp Tcl_GetRegExpFromObj(Tcl_Interp *interp, + Tcl_Obj *patObj, int flags); +/* 357 */ +EXTERN Tcl_Obj * Tcl_EvalTokens(Tcl_Interp *interp, + Tcl_Token *tokenPtr, int count); +/* 358 */ +EXTERN void Tcl_FreeParse(Tcl_Parse *parsePtr); +/* 359 */ +EXTERN void Tcl_LogCommandInfo(Tcl_Interp *interp, + const char *script, const char *command, + int length); +/* 360 */ +EXTERN int Tcl_ParseBraces(Tcl_Interp *interp, + const char *start, int numBytes, + Tcl_Parse *parsePtr, int append, + CONST84 char **termPtr); +/* 361 */ +EXTERN int Tcl_ParseCommand(Tcl_Interp *interp, + const char *start, int numBytes, int nested, + Tcl_Parse *parsePtr); +/* 362 */ +EXTERN int Tcl_ParseExpr(Tcl_Interp *interp, const char *start, + int numBytes, Tcl_Parse *parsePtr); +/* 363 */ +EXTERN int Tcl_ParseQuotedString(Tcl_Interp *interp, + const char *start, int numBytes, + Tcl_Parse *parsePtr, int append, + CONST84 char **termPtr); +/* 364 */ +EXTERN int Tcl_ParseVarName(Tcl_Interp *interp, + const char *start, int numBytes, + Tcl_Parse *parsePtr, int append); +/* 365 */ +EXTERN char * Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr); +/* 366 */ +EXTERN int Tcl_Chdir(const char *dirName); +/* 367 */ +EXTERN int Tcl_Access(const char *path, int mode); +/* 368 */ +EXTERN int Tcl_Stat(const char *path, struct stat *bufPtr); +/* 369 */ +EXTERN int Tcl_UtfNcmp(const char *s1, const char *s2, + unsigned long n); +/* 370 */ +EXTERN int Tcl_UtfNcasecmp(const char *s1, const char *s2, + unsigned long n); +/* 371 */ +EXTERN int Tcl_StringCaseMatch(const char *str, + const char *pattern, int nocase); +/* 372 */ +EXTERN int Tcl_UniCharIsControl(int ch); +/* 373 */ +EXTERN int Tcl_UniCharIsGraph(int ch); +/* 374 */ +EXTERN int Tcl_UniCharIsPrint(int ch); +/* 375 */ +EXTERN int Tcl_UniCharIsPunct(int ch); +/* 376 */ +EXTERN int Tcl_RegExpExecObj(Tcl_Interp *interp, + Tcl_RegExp regexp, Tcl_Obj *textObj, + int offset, int nmatches, int flags); +/* 377 */ +EXTERN void Tcl_RegExpGetInfo(Tcl_RegExp regexp, + Tcl_RegExpInfo *infoPtr); +/* 378 */ +EXTERN Tcl_Obj * Tcl_NewUnicodeObj(const Tcl_UniChar *unicode, + int numChars); +/* 379 */ +EXTERN void Tcl_SetUnicodeObj(Tcl_Obj *objPtr, + const Tcl_UniChar *unicode, int numChars); +/* 380 */ +EXTERN int Tcl_GetCharLength(Tcl_Obj *objPtr); +/* 381 */ +EXTERN Tcl_UniChar Tcl_GetUniChar(Tcl_Obj *objPtr, int index); +/* 382 */ +EXTERN Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr); +/* 383 */ +EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, int first, int last); +/* 384 */ +EXTERN void Tcl_AppendUnicodeToObj(Tcl_Obj *objPtr, + const Tcl_UniChar *unicode, int length); +/* 385 */ +EXTERN int Tcl_RegExpMatchObj(Tcl_Interp *interp, + Tcl_Obj *textObj, Tcl_Obj *patternObj); +/* 386 */ +EXTERN void Tcl_SetNotifier(Tcl_NotifierProcs *notifierProcPtr); +/* 387 */ +EXTERN Tcl_Mutex * Tcl_GetAllocMutex(void); +/* 388 */ +EXTERN int Tcl_GetChannelNames(Tcl_Interp *interp); +/* 389 */ +EXTERN int Tcl_GetChannelNamesEx(Tcl_Interp *interp, + const char *pattern); +/* 390 */ +EXTERN int Tcl_ProcObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); +/* 391 */ +EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr); +/* 392 */ +EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex); +/* 393 */ +EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr, + Tcl_ThreadCreateProc *proc, + ClientData clientData, int stackSize, + int flags); +/* 394 */ +EXTERN int Tcl_ReadRaw(Tcl_Channel chan, char *dst, + int bytesToRead); +/* 395 */ +EXTERN int Tcl_WriteRaw(Tcl_Channel chan, const char *src, + int srcLen); +/* 396 */ +EXTERN Tcl_Channel Tcl_GetTopChannel(Tcl_Channel chan); +/* 397 */ +EXTERN int Tcl_ChannelBuffered(Tcl_Channel chan); +/* 398 */ +EXTERN CONST84_RETURN char * Tcl_ChannelName( + const Tcl_ChannelType *chanTypePtr); +/* 399 */ +EXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion( + const Tcl_ChannelType *chanTypePtr); +/* 400 */ +EXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc( + const Tcl_ChannelType *chanTypePtr); +/* 401 */ +EXTERN Tcl_DriverCloseProc * Tcl_ChannelCloseProc( + const Tcl_ChannelType *chanTypePtr); +/* 402 */ +EXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc( + const Tcl_ChannelType *chanTypePtr); +/* 403 */ +EXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc( + const Tcl_ChannelType *chanTypePtr); +/* 404 */ +EXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc( + const Tcl_ChannelType *chanTypePtr); +/* 405 */ +EXTERN Tcl_DriverSeekProc * Tcl_ChannelSeekProc( + const Tcl_ChannelType *chanTypePtr); +/* 406 */ +EXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc( + const Tcl_ChannelType *chanTypePtr); +/* 407 */ +EXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc( + const Tcl_ChannelType *chanTypePtr); +/* 408 */ +EXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc( + const Tcl_ChannelType *chanTypePtr); +/* 409 */ +EXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc( + const Tcl_ChannelType *chanTypePtr); +/* 410 */ +EXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc( + const Tcl_ChannelType *chanTypePtr); +/* 411 */ +EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc( + const Tcl_ChannelType *chanTypePtr); +/* 412 */ +EXTERN int Tcl_JoinThread(Tcl_ThreadId threadId, int *result); +/* 413 */ +EXTERN int Tcl_IsChannelShared(Tcl_Channel channel); +/* 414 */ +EXTERN int Tcl_IsChannelRegistered(Tcl_Interp *interp, + Tcl_Channel channel); +/* 415 */ +EXTERN void Tcl_CutChannel(Tcl_Channel channel); +/* 416 */ +EXTERN void Tcl_SpliceChannel(Tcl_Channel channel); +/* 417 */ +EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel); +/* 418 */ +EXTERN int Tcl_IsChannelExisting(const char *channelName); +/* 419 */ +EXTERN int Tcl_UniCharNcasecmp(const Tcl_UniChar *ucs, + const Tcl_UniChar *uct, + unsigned long numChars); +/* 420 */ +EXTERN int Tcl_UniCharCaseMatch(const Tcl_UniChar *uniStr, + const Tcl_UniChar *uniPattern, int nocase); +/* 421 */ +EXTERN Tcl_HashEntry * Tcl_FindHashEntry(Tcl_HashTable *tablePtr, + const void *key); +/* 422 */ +EXTERN Tcl_HashEntry * Tcl_CreateHashEntry(Tcl_HashTable *tablePtr, + const void *key, int *newPtr); +/* 423 */ +EXTERN void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, + int keyType, const Tcl_HashKeyType *typePtr); +/* 424 */ +EXTERN void Tcl_InitObjHashTable(Tcl_HashTable *tablePtr); +/* 425 */ +EXTERN ClientData Tcl_CommandTraceInfo(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *procPtr, + ClientData prevClientData); +/* 426 */ +EXTERN int Tcl_TraceCommand(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *proc, + ClientData clientData); +/* 427 */ +EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *proc, + ClientData clientData); +/* 428 */ +EXTERN char * Tcl_AttemptAlloc(unsigned int size); +/* 429 */ +EXTERN char * Tcl_AttemptDbCkalloc(unsigned int size, + const char *file, int line); +/* 430 */ +EXTERN char * Tcl_AttemptRealloc(char *ptr, unsigned int size); +/* 431 */ +EXTERN char * Tcl_AttemptDbCkrealloc(char *ptr, unsigned int size, + const char *file, int line); +/* 432 */ +EXTERN int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, int length); +/* 433 */ +EXTERN Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel); +/* 434 */ +EXTERN Tcl_UniChar * Tcl_GetUnicodeFromObj(Tcl_Obj *objPtr, + int *lengthPtr); +/* 435 */ +EXTERN int Tcl_GetMathFuncInfo(Tcl_Interp *interp, + const char *name, int *numArgsPtr, + Tcl_ValueType **argTypesPtr, + Tcl_MathProc **procPtr, + ClientData *clientDataPtr); +/* 436 */ +EXTERN Tcl_Obj * Tcl_ListMathFuncs(Tcl_Interp *interp, + const char *pattern); +/* 437 */ +EXTERN Tcl_Obj * Tcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 438 */ +EXTERN int Tcl_DetachChannel(Tcl_Interp *interp, + Tcl_Channel channel); +/* 439 */ +EXTERN int Tcl_IsStandardChannel(Tcl_Channel channel); +/* 440 */ +EXTERN int Tcl_FSCopyFile(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr); +/* 441 */ +EXTERN int Tcl_FSCopyDirectory(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); +/* 442 */ +EXTERN int Tcl_FSCreateDirectory(Tcl_Obj *pathPtr); +/* 443 */ +EXTERN int Tcl_FSDeleteFile(Tcl_Obj *pathPtr); +/* 444 */ +EXTERN 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); +/* 445 */ +EXTERN int Tcl_FSMatchInDirectory(Tcl_Interp *interp, + Tcl_Obj *result, Tcl_Obj *pathPtr, + const char *pattern, Tcl_GlobTypeData *types); +/* 446 */ +EXTERN Tcl_Obj * Tcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr, + int linkAction); +/* 447 */ +EXTERN int Tcl_FSRemoveDirectory(Tcl_Obj *pathPtr, + int recursive, Tcl_Obj **errorPtr); +/* 448 */ +EXTERN int Tcl_FSRenameFile(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr); +/* 449 */ +EXTERN int Tcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +/* 450 */ +EXTERN int Tcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval); +/* 451 */ +EXTERN int Tcl_FSFileAttrsGet(Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); +/* 452 */ +EXTERN int Tcl_FSFileAttrsSet(Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj *objPtr); +/* 453 */ +EXTERN const char *CONST86 * Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr, + Tcl_Obj **objPtrRef); +/* 454 */ +EXTERN int Tcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +/* 455 */ +EXTERN int Tcl_FSAccess(Tcl_Obj *pathPtr, int mode); +/* 456 */ +EXTERN Tcl_Channel Tcl_FSOpenFileChannel(Tcl_Interp *interp, + Tcl_Obj *pathPtr, const char *modeString, + int permissions); +/* 457 */ +EXTERN Tcl_Obj * Tcl_FSGetCwd(Tcl_Interp *interp); +/* 458 */ +EXTERN int Tcl_FSChdir(Tcl_Obj *pathPtr); +/* 459 */ +EXTERN int Tcl_FSConvertToPathType(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 460 */ +EXTERN Tcl_Obj * Tcl_FSJoinPath(Tcl_Obj *listObj, int elements); +/* 461 */ +EXTERN Tcl_Obj * Tcl_FSSplitPath(Tcl_Obj *pathPtr, int *lenPtr); +/* 462 */ +EXTERN int Tcl_FSEqualPaths(Tcl_Obj *firstPtr, + Tcl_Obj *secondPtr); +/* 463 */ +EXTERN Tcl_Obj * Tcl_FSGetNormalizedPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 464 */ +EXTERN Tcl_Obj * Tcl_FSJoinToPath(Tcl_Obj *pathPtr, int objc, + Tcl_Obj *const objv[]); +/* 465 */ +EXTERN ClientData Tcl_FSGetInternalRep(Tcl_Obj *pathPtr, + const Tcl_Filesystem *fsPtr); +/* 466 */ +EXTERN Tcl_Obj * Tcl_FSGetTranslatedPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 467 */ +EXTERN int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName); +/* 468 */ +EXTERN Tcl_Obj * Tcl_FSNewNativePath( + const Tcl_Filesystem *fromFilesystem, + ClientData clientData); +/* 469 */ +EXTERN const void * Tcl_FSGetNativePath(Tcl_Obj *pathPtr); +/* 470 */ +EXTERN Tcl_Obj * Tcl_FSFileSystemInfo(Tcl_Obj *pathPtr); +/* 471 */ +EXTERN Tcl_Obj * Tcl_FSPathSeparator(Tcl_Obj *pathPtr); +/* 472 */ +EXTERN Tcl_Obj * Tcl_FSListVolumes(void); +/* 473 */ +EXTERN int Tcl_FSRegister(ClientData clientData, + const Tcl_Filesystem *fsPtr); +/* 474 */ +EXTERN int Tcl_FSUnregister(const Tcl_Filesystem *fsPtr); +/* 475 */ +EXTERN ClientData Tcl_FSData(const Tcl_Filesystem *fsPtr); +/* 476 */ +EXTERN const char * Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 477 */ +EXTERN CONST86 Tcl_Filesystem * Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr); +/* 478 */ +EXTERN Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr); +/* 479 */ +EXTERN int Tcl_OutputBuffered(Tcl_Channel chan); +/* 480 */ +EXTERN void Tcl_FSMountsChanged(const Tcl_Filesystem *fsPtr); +/* 481 */ +EXTERN int Tcl_EvalTokensStandard(Tcl_Interp *interp, + Tcl_Token *tokenPtr, int count); +/* 482 */ +EXTERN void Tcl_GetTime(Tcl_Time *timeBuf); +/* 483 */ +EXTERN Tcl_Trace Tcl_CreateObjTrace(Tcl_Interp *interp, int level, + int flags, Tcl_CmdObjTraceProc *objProc, + ClientData clientData, + Tcl_CmdObjTraceDeleteProc *delProc); +/* 484 */ +EXTERN int Tcl_GetCommandInfoFromToken(Tcl_Command token, + Tcl_CmdInfo *infoPtr); +/* 485 */ +EXTERN int Tcl_SetCommandInfoFromToken(Tcl_Command token, + const Tcl_CmdInfo *infoPtr); +/* 486 */ +EXTERN Tcl_Obj * Tcl_DbNewWideIntObj(Tcl_WideInt wideValue, + const char *file, int line); +/* 487 */ +EXTERN int Tcl_GetWideIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_WideInt *widePtr); +/* 488 */ +EXTERN Tcl_Obj * Tcl_NewWideIntObj(Tcl_WideInt wideValue); +/* 489 */ +EXTERN void Tcl_SetWideIntObj(Tcl_Obj *objPtr, + Tcl_WideInt wideValue); +/* 490 */ +EXTERN Tcl_StatBuf * Tcl_AllocStatBuf(void); +/* 491 */ +EXTERN Tcl_WideInt Tcl_Seek(Tcl_Channel chan, Tcl_WideInt offset, + int mode); +/* 492 */ +EXTERN Tcl_WideInt Tcl_Tell(Tcl_Channel chan); +/* 493 */ +EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc( + const Tcl_ChannelType *chanTypePtr); +/* 494 */ +EXTERN int Tcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); +/* 495 */ +EXTERN int Tcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); +/* 496 */ +EXTERN int Tcl_DictObjRemove(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); +/* 497 */ +EXTERN int Tcl_DictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr, + int *sizePtr); +/* 498 */ +EXTERN int Tcl_DictObjFirst(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, + Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, + int *donePtr); +/* 499 */ +EXTERN void Tcl_DictObjNext(Tcl_DictSearch *searchPtr, + Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, + int *donePtr); +/* 500 */ +EXTERN void Tcl_DictObjDone(Tcl_DictSearch *searchPtr); +/* 501 */ +EXTERN int Tcl_DictObjPutKeyList(Tcl_Interp *interp, + Tcl_Obj *dictPtr, int keyc, + Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); +/* 502 */ +EXTERN int Tcl_DictObjRemoveKeyList(Tcl_Interp *interp, + Tcl_Obj *dictPtr, int keyc, + Tcl_Obj *const *keyv); +/* 503 */ +EXTERN Tcl_Obj * Tcl_NewDictObj(void); +/* 504 */ +EXTERN Tcl_Obj * Tcl_DbNewDictObj(const char *file, int line); +/* 505 */ +EXTERN void Tcl_RegisterConfig(Tcl_Interp *interp, + const char *pkgName, + const Tcl_Config *configuration, + const char *valEncoding); +/* 506 */ +EXTERN Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp, + const char *name, ClientData clientData, + Tcl_NamespaceDeleteProc *deleteProc); +/* 507 */ +EXTERN void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr); +/* 508 */ +EXTERN int Tcl_AppendExportList(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); +/* 509 */ +EXTERN int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr, + const char *pattern, int resetListFirst); +/* 510 */ +EXTERN int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr, + const char *pattern, int allowOverwrite); +/* 511 */ +EXTERN int Tcl_ForgetImport(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, const char *pattern); +/* 512 */ +EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp); +/* 513 */ +EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp); +/* 514 */ +EXTERN Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp, + const char *name, + Tcl_Namespace *contextNsPtr, int flags); +/* 515 */ +EXTERN Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, const char *name, + Tcl_Namespace *contextNsPtr, int flags); +/* 516 */ +EXTERN Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 517 */ +EXTERN void Tcl_GetCommandFullName(Tcl_Interp *interp, + Tcl_Command command, Tcl_Obj *objPtr); +/* 518 */ +EXTERN int Tcl_FSEvalFileEx(Tcl_Interp *interp, + Tcl_Obj *fileName, const char *encodingName); +/* 519 */ +EXTERN Tcl_ExitProc * Tcl_SetExitProc(Tcl_ExitProc *proc); +/* 520 */ +EXTERN void Tcl_LimitAddHandler(Tcl_Interp *interp, int type, + Tcl_LimitHandlerProc *handlerProc, + ClientData clientData, + Tcl_LimitHandlerDeleteProc *deleteProc); +/* 521 */ +EXTERN void Tcl_LimitRemoveHandler(Tcl_Interp *interp, int type, + Tcl_LimitHandlerProc *handlerProc, + ClientData clientData); +/* 522 */ +EXTERN int Tcl_LimitReady(Tcl_Interp *interp); +/* 523 */ +EXTERN int Tcl_LimitCheck(Tcl_Interp *interp); +/* 524 */ +EXTERN int Tcl_LimitExceeded(Tcl_Interp *interp); +/* 525 */ +EXTERN void Tcl_LimitSetCommands(Tcl_Interp *interp, + int commandLimit); +/* 526 */ +EXTERN void Tcl_LimitSetTime(Tcl_Interp *interp, + Tcl_Time *timeLimitPtr); +/* 527 */ +EXTERN void Tcl_LimitSetGranularity(Tcl_Interp *interp, int type, + int granularity); +/* 528 */ +EXTERN int Tcl_LimitTypeEnabled(Tcl_Interp *interp, int type); +/* 529 */ +EXTERN int Tcl_LimitTypeExceeded(Tcl_Interp *interp, int type); +/* 530 */ +EXTERN void Tcl_LimitTypeSet(Tcl_Interp *interp, int type); +/* 531 */ +EXTERN void Tcl_LimitTypeReset(Tcl_Interp *interp, int type); +/* 532 */ +EXTERN int Tcl_LimitGetCommands(Tcl_Interp *interp); +/* 533 */ +EXTERN void Tcl_LimitGetTime(Tcl_Interp *interp, + Tcl_Time *timeLimitPtr); +/* 534 */ +EXTERN int Tcl_LimitGetGranularity(Tcl_Interp *interp, int type); +/* 535 */ +EXTERN Tcl_InterpState Tcl_SaveInterpState(Tcl_Interp *interp, int status); +/* 536 */ +EXTERN int Tcl_RestoreInterpState(Tcl_Interp *interp, + Tcl_InterpState state); +/* 537 */ +EXTERN void Tcl_DiscardInterpState(Tcl_InterpState state); +/* 538 */ +EXTERN int Tcl_SetReturnOptions(Tcl_Interp *interp, + Tcl_Obj *options); +/* 539 */ +EXTERN Tcl_Obj * Tcl_GetReturnOptions(Tcl_Interp *interp, int result); +/* 540 */ +EXTERN int Tcl_IsEnsemble(Tcl_Command token); +/* 541 */ +EXTERN Tcl_Command Tcl_CreateEnsemble(Tcl_Interp *interp, + const char *name, + Tcl_Namespace *namespacePtr, int flags); +/* 542 */ +EXTERN Tcl_Command Tcl_FindEnsemble(Tcl_Interp *interp, + Tcl_Obj *cmdNameObj, int flags); +/* 543 */ +EXTERN int Tcl_SetEnsembleSubcommandList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *subcmdList); +/* 544 */ +EXTERN int Tcl_SetEnsembleMappingDict(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *mapDict); +/* 545 */ +EXTERN int Tcl_SetEnsembleUnknownHandler(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *unknownList); +/* 546 */ +EXTERN int Tcl_SetEnsembleFlags(Tcl_Interp *interp, + Tcl_Command token, int flags); +/* 547 */ +EXTERN int Tcl_GetEnsembleSubcommandList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **subcmdListPtr); +/* 548 */ +EXTERN int Tcl_GetEnsembleMappingDict(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **mapDictPtr); +/* 549 */ +EXTERN int Tcl_GetEnsembleUnknownHandler(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **unknownListPtr); +/* 550 */ +EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp, + Tcl_Command token, int *flagsPtr); +/* 551 */ +EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, + Tcl_Command token, + Tcl_Namespace **namespacePtrPtr); +/* 552 */ +EXTERN void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc, + Tcl_ScaleTimeProc *scaleProc, + ClientData clientData); +/* 553 */ +EXTERN void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc, + Tcl_ScaleTimeProc **scaleProc, + ClientData *clientData); +/* 554 */ +EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc( + const Tcl_ChannelType *chanTypePtr); +/* 555 */ +EXTERN Tcl_Obj * Tcl_NewBignumObj(mp_int *value); +/* 556 */ +EXTERN Tcl_Obj * Tcl_DbNewBignumObj(mp_int *value, const char *file, + int line); +/* 557 */ +EXTERN void Tcl_SetBignumObj(Tcl_Obj *obj, mp_int *value); +/* 558 */ +EXTERN int Tcl_GetBignumFromObj(Tcl_Interp *interp, + Tcl_Obj *obj, mp_int *value); +/* 559 */ +EXTERN int Tcl_TakeBignumFromObj(Tcl_Interp *interp, + Tcl_Obj *obj, mp_int *value); +/* 560 */ +EXTERN int Tcl_TruncateChannel(Tcl_Channel chan, + Tcl_WideInt length); +/* 561 */ +EXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc( + const Tcl_ChannelType *chanTypePtr); +/* 562 */ +EXTERN void Tcl_SetChannelErrorInterp(Tcl_Interp *interp, + Tcl_Obj *msg); +/* 563 */ +EXTERN void Tcl_GetChannelErrorInterp(Tcl_Interp *interp, + Tcl_Obj **msg); +/* 564 */ +EXTERN void Tcl_SetChannelError(Tcl_Channel chan, Tcl_Obj *msg); +/* 565 */ +EXTERN void Tcl_GetChannelError(Tcl_Channel chan, Tcl_Obj **msg); +/* 566 */ +EXTERN int Tcl_InitBignumFromDouble(Tcl_Interp *interp, + double initval, mp_int *toInit); +/* 567 */ +EXTERN Tcl_Obj * Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp, + Tcl_Namespace *nsPtr); +/* 568 */ +EXTERN int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); +/* 569 */ +EXTERN int Tcl_GetEncodingFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); +/* 570 */ +EXTERN Tcl_Obj * Tcl_GetEncodingSearchPath(void); +/* 571 */ +EXTERN int Tcl_SetEncodingSearchPath(Tcl_Obj *searchPath); +/* 572 */ +EXTERN const char * Tcl_GetEncodingNameFromEnvironment( + Tcl_DString *bufPtr); +/* 573 */ +EXTERN int Tcl_PkgRequireProc(Tcl_Interp *interp, + const char *name, int objc, + Tcl_Obj *const objv[], void *clientDataPtr); +/* 574 */ +EXTERN void Tcl_AppendObjToErrorInfo(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 575 */ +EXTERN void Tcl_AppendLimitedToObj(Tcl_Obj *objPtr, + const char *bytes, int length, int limit, + const char *ellipsis); +/* 576 */ +EXTERN Tcl_Obj * Tcl_Format(Tcl_Interp *interp, const char *format, + int objc, Tcl_Obj *const objv[]); +/* 577 */ +EXTERN int Tcl_AppendFormatToObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, const char *format, + int objc, Tcl_Obj *const objv[]); +/* 578 */ +EXTERN Tcl_Obj * Tcl_ObjPrintf(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); +/* 579 */ +EXTERN void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr, + const char *format, ...) TCL_FORMAT_PRINTF(2, 3); +/* 580 */ +EXTERN int Tcl_CancelEval(Tcl_Interp *interp, + Tcl_Obj *resultObjPtr, ClientData clientData, + int flags); +/* 581 */ +EXTERN int Tcl_Canceled(Tcl_Interp *interp, int flags); +/* 582 */ +EXTERN int Tcl_CreatePipe(Tcl_Interp *interp, + Tcl_Channel *rchan, Tcl_Channel *wchan, + int flags); +/* 583 */ +EXTERN Tcl_Command Tcl_NRCreateCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc *proc, + Tcl_ObjCmdProc *nreProc, + ClientData clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 584 */ +EXTERN int Tcl_NREvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 585 */ +EXTERN int Tcl_NREvalObjv(Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[], int flags); +/* 586 */ +EXTERN int Tcl_NRCmdSwap(Tcl_Interp *interp, Tcl_Command cmd, + int objc, Tcl_Obj *const objv[], int flags); +/* 587 */ +EXTERN void Tcl_NRAddCallback(Tcl_Interp *interp, + Tcl_NRPostProc *postProcPtr, + ClientData data0, ClientData data1, + ClientData data2, ClientData data3); +/* 588 */ +EXTERN int Tcl_NRCallObjProc(Tcl_Interp *interp, + Tcl_ObjCmdProc *objProc, + ClientData clientData, int objc, + Tcl_Obj *const objv[]); +/* 589 */ +EXTERN unsigned Tcl_GetFSDeviceFromStat(const Tcl_StatBuf *statPtr); +/* 590 */ +EXTERN unsigned Tcl_GetFSInodeFromStat(const Tcl_StatBuf *statPtr); +/* 591 */ +EXTERN unsigned Tcl_GetModeFromStat(const Tcl_StatBuf *statPtr); +/* 592 */ +EXTERN int Tcl_GetLinkCountFromStat(const Tcl_StatBuf *statPtr); +/* 593 */ +EXTERN int Tcl_GetUserIdFromStat(const Tcl_StatBuf *statPtr); +/* 594 */ +EXTERN int Tcl_GetGroupIdFromStat(const Tcl_StatBuf *statPtr); +/* 595 */ +EXTERN int Tcl_GetDeviceTypeFromStat(const Tcl_StatBuf *statPtr); +/* 596 */ +EXTERN Tcl_WideInt Tcl_GetAccessTimeFromStat(const Tcl_StatBuf *statPtr); +/* 597 */ +EXTERN Tcl_WideInt Tcl_GetModificationTimeFromStat( + const Tcl_StatBuf *statPtr); +/* 598 */ +EXTERN Tcl_WideInt Tcl_GetChangeTimeFromStat(const Tcl_StatBuf *statPtr); +/* 599 */ +EXTERN Tcl_WideUInt Tcl_GetSizeFromStat(const Tcl_StatBuf *statPtr); +/* 600 */ +EXTERN Tcl_WideUInt Tcl_GetBlocksFromStat(const Tcl_StatBuf *statPtr); +/* 601 */ +EXTERN unsigned Tcl_GetBlockSizeFromStat(const Tcl_StatBuf *statPtr); +/* 602 */ +EXTERN int Tcl_SetEnsembleParameterList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *paramList); +/* 603 */ +EXTERN int Tcl_GetEnsembleParameterList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **paramListPtr); +/* 604 */ +EXTERN int Tcl_ParseArgsObjv(Tcl_Interp *interp, + const Tcl_ArgvInfo *argTable, int *objcPtr, + Tcl_Obj *const *objv, Tcl_Obj ***remObjv); +/* 605 */ +EXTERN int Tcl_GetErrorLine(Tcl_Interp *interp); +/* 606 */ +EXTERN void Tcl_SetErrorLine(Tcl_Interp *interp, int lineNum); +/* 607 */ +EXTERN void Tcl_TransferResult(Tcl_Interp *sourceInterp, + int result, Tcl_Interp *targetInterp); +/* 608 */ +EXTERN int Tcl_InterpActive(Tcl_Interp *interp); +/* 609 */ +EXTERN void Tcl_BackgroundException(Tcl_Interp *interp, int code); +/* 610 */ +EXTERN int Tcl_ZlibDeflate(Tcl_Interp *interp, int format, + Tcl_Obj *data, int level, + Tcl_Obj *gzipHeaderDictObj); +/* 611 */ +EXTERN int Tcl_ZlibInflate(Tcl_Interp *interp, int format, + Tcl_Obj *data, int buffersize, + Tcl_Obj *gzipHeaderDictObj); +/* 612 */ +EXTERN unsigned int Tcl_ZlibCRC32(unsigned int crc, + const unsigned char *buf, int len); +/* 613 */ +EXTERN unsigned int Tcl_ZlibAdler32(unsigned int adler, + const unsigned char *buf, int len); +/* 614 */ +EXTERN int Tcl_ZlibStreamInit(Tcl_Interp *interp, int mode, + int format, int level, Tcl_Obj *dictObj, + Tcl_ZlibStream *zshandle); +/* 615 */ +EXTERN Tcl_Obj * Tcl_ZlibStreamGetCommandName(Tcl_ZlibStream zshandle); +/* 616 */ +EXTERN int Tcl_ZlibStreamEof(Tcl_ZlibStream zshandle); +/* 617 */ +EXTERN int Tcl_ZlibStreamChecksum(Tcl_ZlibStream zshandle); +/* 618 */ +EXTERN int Tcl_ZlibStreamPut(Tcl_ZlibStream zshandle, + Tcl_Obj *data, int flush); +/* 619 */ +EXTERN int Tcl_ZlibStreamGet(Tcl_ZlibStream zshandle, + Tcl_Obj *data, int count); +/* 620 */ +EXTERN int Tcl_ZlibStreamClose(Tcl_ZlibStream zshandle); +/* 621 */ +EXTERN int Tcl_ZlibStreamReset(Tcl_ZlibStream zshandle); +/* 622 */ +EXTERN void Tcl_SetStartupScript(Tcl_Obj *path, + const char *encoding); +/* 623 */ +EXTERN Tcl_Obj * Tcl_GetStartupScript(const char **encodingPtr); +/* 624 */ +EXTERN int Tcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan, + int flags); +/* 625 */ +EXTERN int Tcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + Tcl_Obj *resultPtr); +/* 626 */ +EXTERN int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 627 */ +EXTERN int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, + const char *const symv[], int flags, + void *procPtrs, Tcl_LoadHandle *handlePtr); +/* 628 */ +EXTERN void * Tcl_FindSymbol(Tcl_Interp *interp, + Tcl_LoadHandle handle, const char *symbol); +/* 629 */ +EXTERN int Tcl_FSUnloadFile(Tcl_Interp *interp, + Tcl_LoadHandle handlePtr); +/* 630 */ +EXTERN void Tcl_ZlibStreamSetCompressionDictionary( + Tcl_ZlibStream zhandle, + Tcl_Obj *compressionDictionaryObj); + +typedef struct { + const struct TclPlatStubs *tclPlatStubs; + const struct TclIntStubs *tclIntStubs; + const struct TclIntPlatStubs *tclIntPlatStubs; +} TclStubHooks; + +typedef struct TclStubs { + int magic; + const TclStubHooks *hooks; + + int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */ + CONST84_RETURN char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */ + void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */ + char * (*tcl_Alloc) (unsigned int size); /* 3 */ + void (*tcl_Free) (char *ptr); /* 4 */ + char * (*tcl_Realloc) (char *ptr, unsigned int size); /* 5 */ + char * (*tcl_DbCkalloc) (unsigned int size, const char *file, int line); /* 6 */ + void (*tcl_DbCkfree) (char *ptr, const char *file, int line); /* 7 */ + char * (*tcl_DbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 8 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ + void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */ +#endif /* UNIX */ +#if defined(_WIN32) /* WIN */ + void (*reserved9)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */ +#endif /* MACOSX */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ + void (*tcl_DeleteFileHandler) (int fd); /* 10 */ +#endif /* UNIX */ +#if defined(_WIN32) /* WIN */ + void (*reserved10)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + void (*tcl_DeleteFileHandler) (int fd); /* 10 */ +#endif /* MACOSX */ + void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */ + void (*tcl_Sleep) (int ms); /* 12 */ + int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */ + int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */ + void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */ + void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 16 */ + Tcl_Obj * (*tcl_ConcatObj) (int objc, Tcl_Obj *const objv[]); /* 17 */ + int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */ + void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */ + void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */ + int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */ + Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */ + Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, int length, const char *file, int line); /* 23 */ + Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */ + Tcl_Obj * (*tcl_DbNewListObj) (int objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */ + Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */ + Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */ + Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, int length, const char *file, int line); /* 28 */ + Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */ + void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */ + int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *boolPtr); /* 31 */ + int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr); /* 32 */ + unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 33 */ + int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */ + int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */ + int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */ + int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */ + int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */ + int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */ + CONST86 Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */ + char * (*tcl_GetStringFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 41 */ + void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */ + int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */ + int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */ + int (*tcl_ListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr); /* 45 */ + int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 46 */ + int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */ + int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 48 */ + Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */ + Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, int length); /* 50 */ + Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */ + Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */ + Tcl_Obj * (*tcl_NewListObj) (int objc, Tcl_Obj *const objv[]); /* 53 */ + Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */ + Tcl_Obj * (*tcl_NewObj) (void); /* 55 */ + Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, int length); /* 56 */ + void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */ + unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, int length); /* 58 */ + void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 59 */ + void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */ + void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */ + void (*tcl_SetListObj) (Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 62 */ + void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */ + void (*tcl_SetObjLength) (Tcl_Obj *objPtr, int length); /* 64 */ + void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 65 */ + void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */ + void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */ + void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */ + void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */ + void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */ + Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, ClientData clientData); /* 71 */ + void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */ + int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */ + void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */ + int (*tcl_AsyncReady) (void); /* 75 */ + void (*tcl_BackgroundError) (Tcl_Interp *interp); /* 76 */ + char (*tcl_Backslash) (const char *src, int *readPtr); /* 77 */ + int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */ + void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 79 */ + void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, ClientData clientData); /* 80 */ + int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */ + int (*tcl_CommandComplete) (const char *cmd); /* 82 */ + char * (*tcl_Concat) (int argc, CONST84 char *const *argv); /* 83 */ + int (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */ + int (*tcl_ConvertCountedElement) (const char *src, int length, char *dst, int flags); /* 85 */ + int (*tcl_CreateAlias) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, CONST84 char *const *argv); /* 86 */ + int (*tcl_CreateAliasObj) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]); /* 87 */ + Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask); /* 88 */ + void (*tcl_CreateChannelHandler) (Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData); /* 89 */ + void (*tcl_CreateCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 90 */ + Tcl_Command (*tcl_CreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 91 */ + void (*tcl_CreateEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 92 */ + void (*tcl_CreateExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 93 */ + Tcl_Interp * (*tcl_CreateInterp) (void); /* 94 */ + void (*tcl_CreateMathFunc) (Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData); /* 95 */ + Tcl_Command (*tcl_CreateObjCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 96 */ + Tcl_Interp * (*tcl_CreateSlave) (Tcl_Interp *interp, const char *slaveName, int isSafe); /* 97 */ + Tcl_TimerToken (*tcl_CreateTimerHandler) (int milliseconds, Tcl_TimerProc *proc, ClientData clientData); /* 98 */ + Tcl_Trace (*tcl_CreateTrace) (Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData); /* 99 */ + void (*tcl_DeleteAssocData) (Tcl_Interp *interp, const char *name); /* 100 */ + void (*tcl_DeleteChannelHandler) (Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData); /* 101 */ + void (*tcl_DeleteCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 102 */ + int (*tcl_DeleteCommand) (Tcl_Interp *interp, const char *cmdName); /* 103 */ + int (*tcl_DeleteCommandFromToken) (Tcl_Interp *interp, Tcl_Command command); /* 104 */ + void (*tcl_DeleteEvents) (Tcl_EventDeleteProc *proc, ClientData clientData); /* 105 */ + void (*tcl_DeleteEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 106 */ + void (*tcl_DeleteExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 107 */ + void (*tcl_DeleteHashEntry) (Tcl_HashEntry *entryPtr); /* 108 */ + void (*tcl_DeleteHashTable) (Tcl_HashTable *tablePtr); /* 109 */ + void (*tcl_DeleteInterp) (Tcl_Interp *interp); /* 110 */ + void (*tcl_DetachPids) (int numPids, Tcl_Pid *pidPtr); /* 111 */ + void (*tcl_DeleteTimerHandler) (Tcl_TimerToken token); /* 112 */ + void (*tcl_DeleteTrace) (Tcl_Interp *interp, Tcl_Trace trace); /* 113 */ + void (*tcl_DontCallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 114 */ + int (*tcl_DoOneEvent) (int flags); /* 115 */ + void (*tcl_DoWhenIdle) (Tcl_IdleProc *proc, ClientData clientData); /* 116 */ + char * (*tcl_DStringAppend) (Tcl_DString *dsPtr, const char *bytes, int length); /* 117 */ + char * (*tcl_DStringAppendElement) (Tcl_DString *dsPtr, const char *element); /* 118 */ + void (*tcl_DStringEndSublist) (Tcl_DString *dsPtr); /* 119 */ + void (*tcl_DStringFree) (Tcl_DString *dsPtr); /* 120 */ + void (*tcl_DStringGetResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 121 */ + void (*tcl_DStringInit) (Tcl_DString *dsPtr); /* 122 */ + void (*tcl_DStringResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 123 */ + void (*tcl_DStringSetLength) (Tcl_DString *dsPtr, int length); /* 124 */ + void (*tcl_DStringStartSublist) (Tcl_DString *dsPtr); /* 125 */ + int (*tcl_Eof) (Tcl_Channel chan); /* 126 */ + CONST84_RETURN char * (*tcl_ErrnoId) (void); /* 127 */ + CONST84_RETURN char * (*tcl_ErrnoMsg) (int err); /* 128 */ + int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */ + int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */ + int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */ + void (*tcl_EventuallyFree) (ClientData clientData, Tcl_FreeProc *freeProc); /* 132 */ + void (*tcl_Exit) (int status); /* 133 */ + int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */ + int (*tcl_ExprBoolean) (Tcl_Interp *interp, const char *expr, int *ptr); /* 135 */ + int (*tcl_ExprBooleanObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 136 */ + int (*tcl_ExprDouble) (Tcl_Interp *interp, const char *expr, double *ptr); /* 137 */ + int (*tcl_ExprDoubleObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 138 */ + int (*tcl_ExprLong) (Tcl_Interp *interp, const char *expr, long *ptr); /* 139 */ + int (*tcl_ExprLongObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 140 */ + int (*tcl_ExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 141 */ + int (*tcl_ExprString) (Tcl_Interp *interp, const char *expr); /* 142 */ + void (*tcl_Finalize) (void); /* 143 */ + void (*tcl_FindExecutable) (const char *argv0); /* 144 */ + Tcl_HashEntry * (*tcl_FirstHashEntry) (Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 145 */ + int (*tcl_Flush) (Tcl_Channel chan); /* 146 */ + void (*tcl_FreeResult) (Tcl_Interp *interp); /* 147 */ + int (*tcl_GetAlias) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr); /* 148 */ + int (*tcl_GetAliasObj) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 149 */ + ClientData (*tcl_GetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 150 */ + Tcl_Channel (*tcl_GetChannel) (Tcl_Interp *interp, const char *chanName, int *modePtr); /* 151 */ + int (*tcl_GetChannelBufferSize) (Tcl_Channel chan); /* 152 */ + int (*tcl_GetChannelHandle) (Tcl_Channel chan, int direction, ClientData *handlePtr); /* 153 */ + ClientData (*tcl_GetChannelInstanceData) (Tcl_Channel chan); /* 154 */ + int (*tcl_GetChannelMode) (Tcl_Channel chan); /* 155 */ + CONST84_RETURN char * (*tcl_GetChannelName) (Tcl_Channel chan); /* 156 */ + int (*tcl_GetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 157 */ + CONST86 Tcl_ChannelType * (*tcl_GetChannelType) (Tcl_Channel chan); /* 158 */ + int (*tcl_GetCommandInfo) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 159 */ + CONST84_RETURN char * (*tcl_GetCommandName) (Tcl_Interp *interp, Tcl_Command command); /* 160 */ + int (*tcl_GetErrno) (void); /* 161 */ + CONST84_RETURN char * (*tcl_GetHostName) (void); /* 162 */ + int (*tcl_GetInterpPath) (Tcl_Interp *askInterp, Tcl_Interp *slaveInterp); /* 163 */ + Tcl_Interp * (*tcl_GetMaster) (Tcl_Interp *interp); /* 164 */ + const char * (*tcl_GetNameOfExecutable) (void); /* 165 */ + Tcl_Obj * (*tcl_GetObjResult) (Tcl_Interp *interp); /* 166 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ + int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */ +#endif /* UNIX */ +#if defined(_WIN32) /* WIN */ + void (*reserved167)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */ +#endif /* MACOSX */ + Tcl_PathType (*tcl_GetPathType) (const char *path); /* 168 */ + int (*tcl_Gets) (Tcl_Channel chan, Tcl_DString *dsPtr); /* 169 */ + int (*tcl_GetsObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 170 */ + int (*tcl_GetServiceMode) (void); /* 171 */ + Tcl_Interp * (*tcl_GetSlave) (Tcl_Interp *interp, const char *slaveName); /* 172 */ + Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */ + CONST84_RETURN char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */ + CONST84_RETURN char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */ + CONST84_RETURN char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */ + int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */ + int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */ + int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */ + int (*tcl_Init) (Tcl_Interp *interp); /* 180 */ + void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */ + int (*tcl_InputBlocked) (Tcl_Channel chan); /* 182 */ + int (*tcl_InputBuffered) (Tcl_Channel chan); /* 183 */ + int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */ + int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */ + char * (*tcl_JoinPath) (int argc, CONST84 char *const *argv, Tcl_DString *resultPtr); /* 186 */ + int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, char *addr, int type); /* 187 */ + void (*reserved188)(void); + Tcl_Channel (*tcl_MakeFileChannel) (ClientData handle, int mode); /* 189 */ + int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */ + Tcl_Channel (*tcl_MakeTcpClientChannel) (ClientData tcpSocket); /* 191 */ + char * (*tcl_Merge) (int argc, CONST84 char *const *argv); /* 192 */ + Tcl_HashEntry * (*tcl_NextHashEntry) (Tcl_HashSearch *searchPtr); /* 193 */ + void (*tcl_NotifyChannel) (Tcl_Channel channel, int mask); /* 194 */ + Tcl_Obj * (*tcl_ObjGetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 195 */ + Tcl_Obj * (*tcl_ObjSetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 196 */ + Tcl_Channel (*tcl_OpenCommandChannel) (Tcl_Interp *interp, int argc, CONST84 char **argv, int flags); /* 197 */ + Tcl_Channel (*tcl_OpenFileChannel) (Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 198 */ + Tcl_Channel (*tcl_OpenTcpClient) (Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int async); /* 199 */ + Tcl_Channel (*tcl_OpenTcpServer) (Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 200 */ + void (*tcl_Preserve) (ClientData data); /* 201 */ + void (*tcl_PrintDouble) (Tcl_Interp *interp, double value, char *dst); /* 202 */ + int (*tcl_PutEnv) (const char *assignment); /* 203 */ + CONST84_RETURN char * (*tcl_PosixError) (Tcl_Interp *interp); /* 204 */ + void (*tcl_QueueEvent) (Tcl_Event *evPtr, Tcl_QueuePosition position); /* 205 */ + int (*tcl_Read) (Tcl_Channel chan, char *bufPtr, int toRead); /* 206 */ + void (*tcl_ReapDetachedProcs) (void); /* 207 */ + int (*tcl_RecordAndEval) (Tcl_Interp *interp, const char *cmd, int flags); /* 208 */ + int (*tcl_RecordAndEvalObj) (Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 209 */ + void (*tcl_RegisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 210 */ + void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */ + Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */ + int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */ + int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */ + void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 215 */ + void (*tcl_Release) (ClientData clientData); /* 216 */ + void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */ + int (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */ + int (*tcl_ScanCountedElement) (const char *src, int length, int *flagPtr); /* 219 */ + int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */ + int (*tcl_ServiceAll) (void); /* 221 */ + int (*tcl_ServiceEvent) (int flags); /* 222 */ + void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 223 */ + void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, int sz); /* 224 */ + int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */ + int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */ + void (*tcl_SetErrno) (int err); /* 227 */ + void (*tcl_SetErrorCode) (Tcl_Interp *interp, ...); /* 228 */ + void (*tcl_SetMaxBlockTime) (const Tcl_Time *timePtr); /* 229 */ + void (*tcl_SetPanicProc) (Tcl_PanicProc *panicProc); /* 230 */ + int (*tcl_SetRecursionLimit) (Tcl_Interp *interp, int depth); /* 231 */ + void (*tcl_SetResult) (Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); /* 232 */ + int (*tcl_SetServiceMode) (int mode); /* 233 */ + void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */ + void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */ + void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */ + CONST84_RETURN char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */ + CONST84_RETURN char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */ + CONST84_RETURN char * (*tcl_SignalId) (int sig); /* 239 */ + CONST84_RETURN char * (*tcl_SignalMsg) (int sig); /* 240 */ + void (*tcl_SourceRCFile) (Tcl_Interp *interp); /* 241 */ + int (*tcl_SplitList) (Tcl_Interp *interp, const char *listStr, int *argcPtr, CONST84 char ***argvPtr); /* 242 */ + void (*tcl_SplitPath) (const char *path, int *argcPtr, CONST84 char ***argvPtr); /* 243 */ + void (*tcl_StaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 244 */ + int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */ + int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */ + int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */ + int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */ + char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */ + int (*tcl_Ungets) (Tcl_Channel chan, const char *str, int len, int atHead); /* 250 */ + void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */ + int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */ + int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */ + int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */ + void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */ + void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */ + void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */ + int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */ + int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */ + int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */ + ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */ + ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */ + int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */ + void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */ + int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */ + void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */ + void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */ + void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */ + char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */ + CONST84_RETURN char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, CONST84 char **termPtr); /* 270 */ + CONST84_RETURN char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */ + CONST84_RETURN char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */ + int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */ + CONST84_RETURN char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */ + void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */ + int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */ + Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */ + void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */ + void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */ + void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */ + Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan); /* 281 */ + int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */ + Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */ + void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */ + void (*reserved285)(void); + void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */ + Tcl_Encoding (*tcl_CreateEncoding) (const Tcl_EncodingType *typePtr); /* 287 */ + void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 288 */ + void (*tcl_DeleteThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 289 */ + void (*tcl_DiscardResult) (Tcl_SavedResult *statePtr); /* 290 */ + int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, int numBytes, int flags); /* 291 */ + int (*tcl_EvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 292 */ + int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */ + void (*tcl_ExitThread) (int status); /* 294 */ + 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); /* 295 */ + char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 296 */ + void (*tcl_FinalizeThread) (void); /* 297 */ + void (*tcl_FinalizeNotifier) (ClientData clientData); /* 298 */ + void (*tcl_FreeEncoding) (Tcl_Encoding encoding); /* 299 */ + Tcl_ThreadId (*tcl_GetCurrentThread) (void); /* 300 */ + Tcl_Encoding (*tcl_GetEncoding) (Tcl_Interp *interp, const char *name); /* 301 */ + CONST84_RETURN char * (*tcl_GetEncodingName) (Tcl_Encoding encoding); /* 302 */ + void (*tcl_GetEncodingNames) (Tcl_Interp *interp); /* 303 */ + int (*tcl_GetIndexFromObjStruct) (Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, int offset, const char *msg, int flags, int *indexPtr); /* 304 */ + void * (*tcl_GetThreadData) (Tcl_ThreadDataKey *keyPtr, int size); /* 305 */ + Tcl_Obj * (*tcl_GetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 306 */ + ClientData (*tcl_InitNotifier) (void); /* 307 */ + void (*tcl_MutexLock) (Tcl_Mutex *mutexPtr); /* 308 */ + void (*tcl_MutexUnlock) (Tcl_Mutex *mutexPtr); /* 309 */ + void (*tcl_ConditionNotify) (Tcl_Condition *condPtr); /* 310 */ + void (*tcl_ConditionWait) (Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 311 */ + int (*tcl_NumUtfChars) (const char *src, int length); /* 312 */ + int (*tcl_ReadChars) (Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag); /* 313 */ + void (*tcl_RestoreResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 314 */ + void (*tcl_SaveResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 315 */ + int (*tcl_SetSystemEncoding) (Tcl_Interp *interp, const char *name); /* 316 */ + Tcl_Obj * (*tcl_SetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 317 */ + void (*tcl_ThreadAlert) (Tcl_ThreadId threadId); /* 318 */ + void (*tcl_ThreadQueueEvent) (Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position); /* 319 */ + Tcl_UniChar (*tcl_UniCharAtIndex) (const char *src, int index); /* 320 */ + Tcl_UniChar (*tcl_UniCharToLower) (int ch); /* 321 */ + Tcl_UniChar (*tcl_UniCharToTitle) (int ch); /* 322 */ + Tcl_UniChar (*tcl_UniCharToUpper) (int ch); /* 323 */ + int (*tcl_UniCharToUtf) (int ch, char *buf); /* 324 */ + CONST84_RETURN char * (*tcl_UtfAtIndex) (const char *src, int index); /* 325 */ + int (*tcl_UtfCharComplete) (const char *src, int length); /* 326 */ + int (*tcl_UtfBackslash) (const char *src, int *readPtr, char *dst); /* 327 */ + CONST84_RETURN char * (*tcl_UtfFindFirst) (const char *src, int ch); /* 328 */ + CONST84_RETURN char * (*tcl_UtfFindLast) (const char *src, int ch); /* 329 */ + CONST84_RETURN char * (*tcl_UtfNext) (const char *src); /* 330 */ + CONST84_RETURN char * (*tcl_UtfPrev) (const char *src, const char *start); /* 331 */ + 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); /* 332 */ + char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 333 */ + int (*tcl_UtfToLower) (char *src); /* 334 */ + int (*tcl_UtfToTitle) (char *src); /* 335 */ + int (*tcl_UtfToUniChar) (const char *src, Tcl_UniChar *chPtr); /* 336 */ + int (*tcl_UtfToUpper) (char *src); /* 337 */ + int (*tcl_WriteChars) (Tcl_Channel chan, const char *src, int srcLen); /* 338 */ + int (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */ + char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */ + CONST84_RETURN char * (*tcl_GetDefaultEncodingDir) (void); /* 341 */ + void (*tcl_SetDefaultEncodingDir) (const char *path); /* 342 */ + void (*tcl_AlertNotifier) (ClientData clientData); /* 343 */ + void (*tcl_ServiceModeHook) (int mode); /* 344 */ + int (*tcl_UniCharIsAlnum) (int ch); /* 345 */ + int (*tcl_UniCharIsAlpha) (int ch); /* 346 */ + int (*tcl_UniCharIsDigit) (int ch); /* 347 */ + int (*tcl_UniCharIsLower) (int ch); /* 348 */ + int (*tcl_UniCharIsSpace) (int ch); /* 349 */ + int (*tcl_UniCharIsUpper) (int ch); /* 350 */ + int (*tcl_UniCharIsWordChar) (int ch); /* 351 */ + int (*tcl_UniCharLen) (const Tcl_UniChar *uniStr); /* 352 */ + int (*tcl_UniCharNcmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 353 */ + char * (*tcl_UniCharToUtfDString) (const Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr); /* 354 */ + Tcl_UniChar * (*tcl_UtfToUniCharDString) (const char *src, int length, Tcl_DString *dsPtr); /* 355 */ + Tcl_RegExp (*tcl_GetRegExpFromObj) (Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 356 */ + Tcl_Obj * (*tcl_EvalTokens) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 357 */ + void (*tcl_FreeParse) (Tcl_Parse *parsePtr); /* 358 */ + void (*tcl_LogCommandInfo) (Tcl_Interp *interp, const char *script, const char *command, int length); /* 359 */ + int (*tcl_ParseBraces) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 360 */ + int (*tcl_ParseCommand) (Tcl_Interp *interp, const char *start, int numBytes, int nested, Tcl_Parse *parsePtr); /* 361 */ + int (*tcl_ParseExpr) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr); /* 362 */ + int (*tcl_ParseQuotedString) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 363 */ + int (*tcl_ParseVarName) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append); /* 364 */ + char * (*tcl_GetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 365 */ + int (*tcl_Chdir) (const char *dirName); /* 366 */ + int (*tcl_Access) (const char *path, int mode); /* 367 */ + int (*tcl_Stat) (const char *path, struct stat *bufPtr); /* 368 */ + int (*tcl_UtfNcmp) (const char *s1, const char *s2, unsigned long n); /* 369 */ + int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, unsigned long n); /* 370 */ + int (*tcl_StringCaseMatch) (const char *str, const char *pattern, int nocase); /* 371 */ + int (*tcl_UniCharIsControl) (int ch); /* 372 */ + int (*tcl_UniCharIsGraph) (int ch); /* 373 */ + int (*tcl_UniCharIsPrint) (int ch); /* 374 */ + int (*tcl_UniCharIsPunct) (int ch); /* 375 */ + int (*tcl_RegExpExecObj) (Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags); /* 376 */ + void (*tcl_RegExpGetInfo) (Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 377 */ + Tcl_Obj * (*tcl_NewUnicodeObj) (const Tcl_UniChar *unicode, int numChars); /* 378 */ + void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 379 */ + int (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */ + Tcl_UniChar (*tcl_GetUniChar) (Tcl_Obj *objPtr, int index); /* 381 */ + Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */ + Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, int first, int last); /* 383 */ + void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 384 */ + int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */ + void (*tcl_SetNotifier) (Tcl_NotifierProcs *notifierProcPtr); /* 386 */ + Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */ + int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */ + int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */ + int (*tcl_ProcObjCmd) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 390 */ + void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */ + void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */ + int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, ClientData clientData, int stackSize, int flags); /* 393 */ + int (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, int bytesToRead); /* 394 */ + int (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, int srcLen); /* 395 */ + Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */ + int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */ + CONST84_RETURN char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */ + Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */ + Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */ + Tcl_DriverCloseProc * (*tcl_ChannelCloseProc) (const Tcl_ChannelType *chanTypePtr); /* 401 */ + Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) (const Tcl_ChannelType *chanTypePtr); /* 402 */ + Tcl_DriverInputProc * (*tcl_ChannelInputProc) (const Tcl_ChannelType *chanTypePtr); /* 403 */ + Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) (const Tcl_ChannelType *chanTypePtr); /* 404 */ + Tcl_DriverSeekProc * (*tcl_ChannelSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 405 */ + Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 406 */ + Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 407 */ + Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) (const Tcl_ChannelType *chanTypePtr); /* 408 */ + Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) (const Tcl_ChannelType *chanTypePtr); /* 409 */ + Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) (const Tcl_ChannelType *chanTypePtr); /* 410 */ + Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) (const Tcl_ChannelType *chanTypePtr); /* 411 */ + int (*tcl_JoinThread) (Tcl_ThreadId threadId, int *result); /* 412 */ + int (*tcl_IsChannelShared) (Tcl_Channel channel); /* 413 */ + int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */ + void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */ + void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */ + void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */ + int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */ + int (*tcl_UniCharNcasecmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 419 */ + int (*tcl_UniCharCaseMatch) (const Tcl_UniChar *uniStr, const Tcl_UniChar *uniPattern, int nocase); /* 420 */ + Tcl_HashEntry * (*tcl_FindHashEntry) (Tcl_HashTable *tablePtr, const void *key); /* 421 */ + Tcl_HashEntry * (*tcl_CreateHashEntry) (Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 422 */ + void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */ + void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */ + ClientData (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData); /* 425 */ + int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 426 */ + void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 427 */ + char * (*tcl_AttemptAlloc) (unsigned int size); /* 428 */ + char * (*tcl_AttemptDbCkalloc) (unsigned int size, const char *file, int line); /* 429 */ + char * (*tcl_AttemptRealloc) (char *ptr, unsigned int size); /* 430 */ + char * (*tcl_AttemptDbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 431 */ + int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, int length); /* 432 */ + Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */ + Tcl_UniChar * (*tcl_GetUnicodeFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 434 */ + int (*tcl_GetMathFuncInfo) (Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr); /* 435 */ + Tcl_Obj * (*tcl_ListMathFuncs) (Tcl_Interp *interp, const char *pattern); /* 436 */ + Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */ + int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */ + int (*tcl_IsStandardChannel) (Tcl_Channel channel); /* 439 */ + int (*tcl_FSCopyFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 440 */ + int (*tcl_FSCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 441 */ + int (*tcl_FSCreateDirectory) (Tcl_Obj *pathPtr); /* 442 */ + int (*tcl_FSDeleteFile) (Tcl_Obj *pathPtr); /* 443 */ + 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); /* 444 */ + int (*tcl_FSMatchInDirectory) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 445 */ + Tcl_Obj * (*tcl_FSLink) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 446 */ + int (*tcl_FSRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 447 */ + int (*tcl_FSRenameFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 448 */ + int (*tcl_FSLstat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 449 */ + int (*tcl_FSUtime) (Tcl_Obj *pathPtr, struct utimbuf *tval); /* 450 */ + int (*tcl_FSFileAttrsGet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 451 */ + int (*tcl_FSFileAttrsSet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 452 */ + const char *CONST86 * (*tcl_FSFileAttrStrings) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 453 */ + int (*tcl_FSStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 454 */ + int (*tcl_FSAccess) (Tcl_Obj *pathPtr, int mode); /* 455 */ + Tcl_Channel (*tcl_FSOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 456 */ + Tcl_Obj * (*tcl_FSGetCwd) (Tcl_Interp *interp); /* 457 */ + int (*tcl_FSChdir) (Tcl_Obj *pathPtr); /* 458 */ + int (*tcl_FSConvertToPathType) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 459 */ + Tcl_Obj * (*tcl_FSJoinPath) (Tcl_Obj *listObj, int elements); /* 460 */ + Tcl_Obj * (*tcl_FSSplitPath) (Tcl_Obj *pathPtr, int *lenPtr); /* 461 */ + int (*tcl_FSEqualPaths) (Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 462 */ + Tcl_Obj * (*tcl_FSGetNormalizedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 463 */ + Tcl_Obj * (*tcl_FSJoinToPath) (Tcl_Obj *pathPtr, int objc, Tcl_Obj *const objv[]); /* 464 */ + ClientData (*tcl_FSGetInternalRep) (Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 465 */ + Tcl_Obj * (*tcl_FSGetTranslatedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 466 */ + int (*tcl_FSEvalFile) (Tcl_Interp *interp, Tcl_Obj *fileName); /* 467 */ + Tcl_Obj * (*tcl_FSNewNativePath) (const Tcl_Filesystem *fromFilesystem, ClientData clientData); /* 468 */ + const void * (*tcl_FSGetNativePath) (Tcl_Obj *pathPtr); /* 469 */ + Tcl_Obj * (*tcl_FSFileSystemInfo) (Tcl_Obj *pathPtr); /* 470 */ + Tcl_Obj * (*tcl_FSPathSeparator) (Tcl_Obj *pathPtr); /* 471 */ + Tcl_Obj * (*tcl_FSListVolumes) (void); /* 472 */ + int (*tcl_FSRegister) (ClientData clientData, const Tcl_Filesystem *fsPtr); /* 473 */ + int (*tcl_FSUnregister) (const Tcl_Filesystem *fsPtr); /* 474 */ + ClientData (*tcl_FSData) (const Tcl_Filesystem *fsPtr); /* 475 */ + const char * (*tcl_FSGetTranslatedStringPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 476 */ + CONST86 Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) (Tcl_Obj *pathPtr); /* 477 */ + Tcl_PathType (*tcl_FSGetPathType) (Tcl_Obj *pathPtr); /* 478 */ + int (*tcl_OutputBuffered) (Tcl_Channel chan); /* 479 */ + void (*tcl_FSMountsChanged) (const Tcl_Filesystem *fsPtr); /* 480 */ + int (*tcl_EvalTokensStandard) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 481 */ + void (*tcl_GetTime) (Tcl_Time *timeBuf); /* 482 */ + Tcl_Trace (*tcl_CreateObjTrace) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 483 */ + int (*tcl_GetCommandInfoFromToken) (Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 484 */ + int (*tcl_SetCommandInfoFromToken) (Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 485 */ + Tcl_Obj * (*tcl_DbNewWideIntObj) (Tcl_WideInt wideValue, const char *file, int line); /* 486 */ + int (*tcl_GetWideIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 487 */ + Tcl_Obj * (*tcl_NewWideIntObj) (Tcl_WideInt wideValue); /* 488 */ + void (*tcl_SetWideIntObj) (Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 489 */ + Tcl_StatBuf * (*tcl_AllocStatBuf) (void); /* 490 */ + Tcl_WideInt (*tcl_Seek) (Tcl_Channel chan, Tcl_WideInt offset, int mode); /* 491 */ + Tcl_WideInt (*tcl_Tell) (Tcl_Channel chan); /* 492 */ + Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 493 */ + int (*tcl_DictObjPut) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 494 */ + int (*tcl_DictObjGet) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 495 */ + int (*tcl_DictObjRemove) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 496 */ + int (*tcl_DictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr); /* 497 */ + int (*tcl_DictObjFirst) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 498 */ + void (*tcl_DictObjNext) (Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */ + void (*tcl_DictObjDone) (Tcl_DictSearch *searchPtr); /* 500 */ + int (*tcl_DictObjPutKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 501 */ + int (*tcl_DictObjRemoveKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv); /* 502 */ + Tcl_Obj * (*tcl_NewDictObj) (void); /* 503 */ + Tcl_Obj * (*tcl_DbNewDictObj) (const char *file, int line); /* 504 */ + void (*tcl_RegisterConfig) (Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 505 */ + Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, const char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 506 */ + void (*tcl_DeleteNamespace) (Tcl_Namespace *nsPtr); /* 507 */ + int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 508 */ + int (*tcl_Export) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 509 */ + int (*tcl_Import) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 510 */ + int (*tcl_ForgetImport) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 511 */ + Tcl_Namespace * (*tcl_GetCurrentNamespace) (Tcl_Interp *interp); /* 512 */ + Tcl_Namespace * (*tcl_GetGlobalNamespace) (Tcl_Interp *interp); /* 513 */ + Tcl_Namespace * (*tcl_FindNamespace) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 514 */ + Tcl_Command (*tcl_FindCommand) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */ + Tcl_Command (*tcl_GetCommandFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 516 */ + void (*tcl_GetCommandFullName) (Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 517 */ + int (*tcl_FSEvalFileEx) (Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 518 */ + Tcl_ExitProc * (*tcl_SetExitProc) (Tcl_ExitProc *proc); /* 519 */ + void (*tcl_LimitAddHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 520 */ + void (*tcl_LimitRemoveHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData); /* 521 */ + int (*tcl_LimitReady) (Tcl_Interp *interp); /* 522 */ + int (*tcl_LimitCheck) (Tcl_Interp *interp); /* 523 */ + int (*tcl_LimitExceeded) (Tcl_Interp *interp); /* 524 */ + void (*tcl_LimitSetCommands) (Tcl_Interp *interp, int commandLimit); /* 525 */ + void (*tcl_LimitSetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 526 */ + void (*tcl_LimitSetGranularity) (Tcl_Interp *interp, int type, int granularity); /* 527 */ + int (*tcl_LimitTypeEnabled) (Tcl_Interp *interp, int type); /* 528 */ + int (*tcl_LimitTypeExceeded) (Tcl_Interp *interp, int type); /* 529 */ + void (*tcl_LimitTypeSet) (Tcl_Interp *interp, int type); /* 530 */ + void (*tcl_LimitTypeReset) (Tcl_Interp *interp, int type); /* 531 */ + int (*tcl_LimitGetCommands) (Tcl_Interp *interp); /* 532 */ + void (*tcl_LimitGetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 533 */ + int (*tcl_LimitGetGranularity) (Tcl_Interp *interp, int type); /* 534 */ + Tcl_InterpState (*tcl_SaveInterpState) (Tcl_Interp *interp, int status); /* 535 */ + int (*tcl_RestoreInterpState) (Tcl_Interp *interp, Tcl_InterpState state); /* 536 */ + void (*tcl_DiscardInterpState) (Tcl_InterpState state); /* 537 */ + int (*tcl_SetReturnOptions) (Tcl_Interp *interp, Tcl_Obj *options); /* 538 */ + Tcl_Obj * (*tcl_GetReturnOptions) (Tcl_Interp *interp, int result); /* 539 */ + int (*tcl_IsEnsemble) (Tcl_Command token); /* 540 */ + Tcl_Command (*tcl_CreateEnsemble) (Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 541 */ + Tcl_Command (*tcl_FindEnsemble) (Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 542 */ + int (*tcl_SetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 543 */ + int (*tcl_SetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 544 */ + int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */ + int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */ + int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */ + int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */ + int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */ + int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */ + int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */ + void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, ClientData clientData); /* 552 */ + void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, ClientData *clientData); /* 553 */ + Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */ + Tcl_Obj * (*tcl_NewBignumObj) (mp_int *value); /* 555 */ + Tcl_Obj * (*tcl_DbNewBignumObj) (mp_int *value, const char *file, int line); /* 556 */ + void (*tcl_SetBignumObj) (Tcl_Obj *obj, mp_int *value); /* 557 */ + int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 558 */ + int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 559 */ + int (*tcl_TruncateChannel) (Tcl_Channel chan, Tcl_WideInt length); /* 560 */ + Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) (const Tcl_ChannelType *chanTypePtr); /* 561 */ + void (*tcl_SetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj *msg); /* 562 */ + void (*tcl_GetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj **msg); /* 563 */ + void (*tcl_SetChannelError) (Tcl_Channel chan, Tcl_Obj *msg); /* 564 */ + void (*tcl_GetChannelError) (Tcl_Channel chan, Tcl_Obj **msg); /* 565 */ + int (*tcl_InitBignumFromDouble) (Tcl_Interp *interp, double initval, mp_int *toInit); /* 566 */ + Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 567 */ + int (*tcl_SetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 568 */ + int (*tcl_GetEncodingFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 569 */ + Tcl_Obj * (*tcl_GetEncodingSearchPath) (void); /* 570 */ + int (*tcl_SetEncodingSearchPath) (Tcl_Obj *searchPath); /* 571 */ + const char * (*tcl_GetEncodingNameFromEnvironment) (Tcl_DString *bufPtr); /* 572 */ + int (*tcl_PkgRequireProc) (Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 573 */ + void (*tcl_AppendObjToErrorInfo) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 574 */ + void (*tcl_AppendLimitedToObj) (Tcl_Obj *objPtr, const char *bytes, int length, int limit, const char *ellipsis); /* 575 */ + Tcl_Obj * (*tcl_Format) (Tcl_Interp *interp, const char *format, int objc, Tcl_Obj *const objv[]); /* 576 */ + int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, int objc, Tcl_Obj *const objv[]); /* 577 */ + Tcl_Obj * (*tcl_ObjPrintf) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 578 */ + void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 579 */ + int (*tcl_CancelEval) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr, ClientData clientData, int flags); /* 580 */ + int (*tcl_Canceled) (Tcl_Interp *interp, int flags); /* 581 */ + int (*tcl_CreatePipe) (Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 582 */ + Tcl_Command (*tcl_NRCreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 583 */ + int (*tcl_NREvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 584 */ + int (*tcl_NREvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 585 */ + int (*tcl_NRCmdSwap) (Tcl_Interp *interp, Tcl_Command cmd, int objc, Tcl_Obj *const objv[], int flags); /* 586 */ + void (*tcl_NRAddCallback) (Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, ClientData data0, ClientData data1, ClientData data2, ClientData data3); /* 587 */ + int (*tcl_NRCallObjProc) (Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, ClientData clientData, int objc, Tcl_Obj *const objv[]); /* 588 */ + unsigned (*tcl_GetFSDeviceFromStat) (const Tcl_StatBuf *statPtr); /* 589 */ + unsigned (*tcl_GetFSInodeFromStat) (const Tcl_StatBuf *statPtr); /* 590 */ + unsigned (*tcl_GetModeFromStat) (const Tcl_StatBuf *statPtr); /* 591 */ + int (*tcl_GetLinkCountFromStat) (const Tcl_StatBuf *statPtr); /* 592 */ + int (*tcl_GetUserIdFromStat) (const Tcl_StatBuf *statPtr); /* 593 */ + int (*tcl_GetGroupIdFromStat) (const Tcl_StatBuf *statPtr); /* 594 */ + int (*tcl_GetDeviceTypeFromStat) (const Tcl_StatBuf *statPtr); /* 595 */ + Tcl_WideInt (*tcl_GetAccessTimeFromStat) (const Tcl_StatBuf *statPtr); /* 596 */ + Tcl_WideInt (*tcl_GetModificationTimeFromStat) (const Tcl_StatBuf *statPtr); /* 597 */ + Tcl_WideInt (*tcl_GetChangeTimeFromStat) (const Tcl_StatBuf *statPtr); /* 598 */ + Tcl_WideUInt (*tcl_GetSizeFromStat) (const Tcl_StatBuf *statPtr); /* 599 */ + Tcl_WideUInt (*tcl_GetBlocksFromStat) (const Tcl_StatBuf *statPtr); /* 600 */ + unsigned (*tcl_GetBlockSizeFromStat) (const Tcl_StatBuf *statPtr); /* 601 */ + int (*tcl_SetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 602 */ + int (*tcl_GetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 603 */ + int (*tcl_ParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 604 */ + int (*tcl_GetErrorLine) (Tcl_Interp *interp); /* 605 */ + void (*tcl_SetErrorLine) (Tcl_Interp *interp, int lineNum); /* 606 */ + void (*tcl_TransferResult) (Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp); /* 607 */ + int (*tcl_InterpActive) (Tcl_Interp *interp); /* 608 */ + void (*tcl_BackgroundException) (Tcl_Interp *interp, int code); /* 609 */ + int (*tcl_ZlibDeflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 610 */ + int (*tcl_ZlibInflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int buffersize, Tcl_Obj *gzipHeaderDictObj); /* 611 */ + unsigned int (*tcl_ZlibCRC32) (unsigned int crc, const unsigned char *buf, int len); /* 612 */ + unsigned int (*tcl_ZlibAdler32) (unsigned int adler, const unsigned char *buf, int len); /* 613 */ + int (*tcl_ZlibStreamInit) (Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 614 */ + Tcl_Obj * (*tcl_ZlibStreamGetCommandName) (Tcl_ZlibStream zshandle); /* 615 */ + int (*tcl_ZlibStreamEof) (Tcl_ZlibStream zshandle); /* 616 */ + int (*tcl_ZlibStreamChecksum) (Tcl_ZlibStream zshandle); /* 617 */ + int (*tcl_ZlibStreamPut) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 618 */ + int (*tcl_ZlibStreamGet) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int count); /* 619 */ + int (*tcl_ZlibStreamClose) (Tcl_ZlibStream zshandle); /* 620 */ + int (*tcl_ZlibStreamReset) (Tcl_ZlibStream zshandle); /* 621 */ + void (*tcl_SetStartupScript) (Tcl_Obj *path, const char *encoding); /* 622 */ + Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */ + int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */ + int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */ + int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */ + int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */ + void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */ + int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */ + void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */ +} TclStubs; + +extern const TclStubs *tclStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +#define Tcl_PkgProvideEx \ + (tclStubsPtr->tcl_PkgProvideEx) /* 0 */ +#define Tcl_PkgRequireEx \ + (tclStubsPtr->tcl_PkgRequireEx) /* 1 */ +#define Tcl_Panic \ + (tclStubsPtr->tcl_Panic) /* 2 */ +#define Tcl_Alloc \ + (tclStubsPtr->tcl_Alloc) /* 3 */ +#define Tcl_Free \ + (tclStubsPtr->tcl_Free) /* 4 */ +#define Tcl_Realloc \ + (tclStubsPtr->tcl_Realloc) /* 5 */ +#define Tcl_DbCkalloc \ + (tclStubsPtr->tcl_DbCkalloc) /* 6 */ +#define Tcl_DbCkfree \ + (tclStubsPtr->tcl_DbCkfree) /* 7 */ +#define Tcl_DbCkrealloc \ + (tclStubsPtr->tcl_DbCkrealloc) /* 8 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +#define Tcl_CreateFileHandler \ + (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_CreateFileHandler \ + (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ +#endif /* MACOSX */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +#define Tcl_DeleteFileHandler \ + (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_DeleteFileHandler \ + (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ +#endif /* MACOSX */ +#define Tcl_SetTimer \ + (tclStubsPtr->tcl_SetTimer) /* 11 */ +#define Tcl_Sleep \ + (tclStubsPtr->tcl_Sleep) /* 12 */ +#define Tcl_WaitForEvent \ + (tclStubsPtr->tcl_WaitForEvent) /* 13 */ +#define Tcl_AppendAllObjTypes \ + (tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */ +#define Tcl_AppendStringsToObj \ + (tclStubsPtr->tcl_AppendStringsToObj) /* 15 */ +#define Tcl_AppendToObj \ + (tclStubsPtr->tcl_AppendToObj) /* 16 */ +#define Tcl_ConcatObj \ + (tclStubsPtr->tcl_ConcatObj) /* 17 */ +#define Tcl_ConvertToType \ + (tclStubsPtr->tcl_ConvertToType) /* 18 */ +#define Tcl_DbDecrRefCount \ + (tclStubsPtr->tcl_DbDecrRefCount) /* 19 */ +#define Tcl_DbIncrRefCount \ + (tclStubsPtr->tcl_DbIncrRefCount) /* 20 */ +#define Tcl_DbIsShared \ + (tclStubsPtr->tcl_DbIsShared) /* 21 */ +#define Tcl_DbNewBooleanObj \ + (tclStubsPtr->tcl_DbNewBooleanObj) /* 22 */ +#define Tcl_DbNewByteArrayObj \ + (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ +#define Tcl_DbNewDoubleObj \ + (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ +#define Tcl_DbNewListObj \ + (tclStubsPtr->tcl_DbNewListObj) /* 25 */ +#define Tcl_DbNewLongObj \ + (tclStubsPtr->tcl_DbNewLongObj) /* 26 */ +#define Tcl_DbNewObj \ + (tclStubsPtr->tcl_DbNewObj) /* 27 */ +#define Tcl_DbNewStringObj \ + (tclStubsPtr->tcl_DbNewStringObj) /* 28 */ +#define Tcl_DuplicateObj \ + (tclStubsPtr->tcl_DuplicateObj) /* 29 */ +#define TclFreeObj \ + (tclStubsPtr->tclFreeObj) /* 30 */ +#define Tcl_GetBoolean \ + (tclStubsPtr->tcl_GetBoolean) /* 31 */ +#define Tcl_GetBooleanFromObj \ + (tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */ +#define Tcl_GetByteArrayFromObj \ + (tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */ +#define Tcl_GetDouble \ + (tclStubsPtr->tcl_GetDouble) /* 34 */ +#define Tcl_GetDoubleFromObj \ + (tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */ +#define Tcl_GetIndexFromObj \ + (tclStubsPtr->tcl_GetIndexFromObj) /* 36 */ +#define Tcl_GetInt \ + (tclStubsPtr->tcl_GetInt) /* 37 */ +#define Tcl_GetIntFromObj \ + (tclStubsPtr->tcl_GetIntFromObj) /* 38 */ +#define Tcl_GetLongFromObj \ + (tclStubsPtr->tcl_GetLongFromObj) /* 39 */ +#define Tcl_GetObjType \ + (tclStubsPtr->tcl_GetObjType) /* 40 */ +#define Tcl_GetStringFromObj \ + (tclStubsPtr->tcl_GetStringFromObj) /* 41 */ +#define Tcl_InvalidateStringRep \ + (tclStubsPtr->tcl_InvalidateStringRep) /* 42 */ +#define Tcl_ListObjAppendList \ + (tclStubsPtr->tcl_ListObjAppendList) /* 43 */ +#define Tcl_ListObjAppendElement \ + (tclStubsPtr->tcl_ListObjAppendElement) /* 44 */ +#define Tcl_ListObjGetElements \ + (tclStubsPtr->tcl_ListObjGetElements) /* 45 */ +#define Tcl_ListObjIndex \ + (tclStubsPtr->tcl_ListObjIndex) /* 46 */ +#define Tcl_ListObjLength \ + (tclStubsPtr->tcl_ListObjLength) /* 47 */ +#define Tcl_ListObjReplace \ + (tclStubsPtr->tcl_ListObjReplace) /* 48 */ +#define Tcl_NewBooleanObj \ + (tclStubsPtr->tcl_NewBooleanObj) /* 49 */ +#define Tcl_NewByteArrayObj \ + (tclStubsPtr->tcl_NewByteArrayObj) /* 50 */ +#define Tcl_NewDoubleObj \ + (tclStubsPtr->tcl_NewDoubleObj) /* 51 */ +#define Tcl_NewIntObj \ + (tclStubsPtr->tcl_NewIntObj) /* 52 */ +#define Tcl_NewListObj \ + (tclStubsPtr->tcl_NewListObj) /* 53 */ +#define Tcl_NewLongObj \ + (tclStubsPtr->tcl_NewLongObj) /* 54 */ +#define Tcl_NewObj \ + (tclStubsPtr->tcl_NewObj) /* 55 */ +#define Tcl_NewStringObj \ + (tclStubsPtr->tcl_NewStringObj) /* 56 */ +#define Tcl_SetBooleanObj \ + (tclStubsPtr->tcl_SetBooleanObj) /* 57 */ +#define Tcl_SetByteArrayLength \ + (tclStubsPtr->tcl_SetByteArrayLength) /* 58 */ +#define Tcl_SetByteArrayObj \ + (tclStubsPtr->tcl_SetByteArrayObj) /* 59 */ +#define Tcl_SetDoubleObj \ + (tclStubsPtr->tcl_SetDoubleObj) /* 60 */ +#define Tcl_SetIntObj \ + (tclStubsPtr->tcl_SetIntObj) /* 61 */ +#define Tcl_SetListObj \ + (tclStubsPtr->tcl_SetListObj) /* 62 */ +#define Tcl_SetLongObj \ + (tclStubsPtr->tcl_SetLongObj) /* 63 */ +#define Tcl_SetObjLength \ + (tclStubsPtr->tcl_SetObjLength) /* 64 */ +#define Tcl_SetStringObj \ + (tclStubsPtr->tcl_SetStringObj) /* 65 */ +#define Tcl_AddErrorInfo \ + (tclStubsPtr->tcl_AddErrorInfo) /* 66 */ +#define Tcl_AddObjErrorInfo \ + (tclStubsPtr->tcl_AddObjErrorInfo) /* 67 */ +#define Tcl_AllowExceptions \ + (tclStubsPtr->tcl_AllowExceptions) /* 68 */ +#define Tcl_AppendElement \ + (tclStubsPtr->tcl_AppendElement) /* 69 */ +#define Tcl_AppendResult \ + (tclStubsPtr->tcl_AppendResult) /* 70 */ +#define Tcl_AsyncCreate \ + (tclStubsPtr->tcl_AsyncCreate) /* 71 */ +#define Tcl_AsyncDelete \ + (tclStubsPtr->tcl_AsyncDelete) /* 72 */ +#define Tcl_AsyncInvoke \ + (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ +#define Tcl_AsyncMark \ + (tclStubsPtr->tcl_AsyncMark) /* 74 */ +#define Tcl_AsyncReady \ + (tclStubsPtr->tcl_AsyncReady) /* 75 */ +#define Tcl_BackgroundError \ + (tclStubsPtr->tcl_BackgroundError) /* 76 */ +#define Tcl_Backslash \ + (tclStubsPtr->tcl_Backslash) /* 77 */ +#define Tcl_BadChannelOption \ + (tclStubsPtr->tcl_BadChannelOption) /* 78 */ +#define Tcl_CallWhenDeleted \ + (tclStubsPtr->tcl_CallWhenDeleted) /* 79 */ +#define Tcl_CancelIdleCall \ + (tclStubsPtr->tcl_CancelIdleCall) /* 80 */ +#define Tcl_Close \ + (tclStubsPtr->tcl_Close) /* 81 */ +#define Tcl_CommandComplete \ + (tclStubsPtr->tcl_CommandComplete) /* 82 */ +#define Tcl_Concat \ + (tclStubsPtr->tcl_Concat) /* 83 */ +#define Tcl_ConvertElement \ + (tclStubsPtr->tcl_ConvertElement) /* 84 */ +#define Tcl_ConvertCountedElement \ + (tclStubsPtr->tcl_ConvertCountedElement) /* 85 */ +#define Tcl_CreateAlias \ + (tclStubsPtr->tcl_CreateAlias) /* 86 */ +#define Tcl_CreateAliasObj \ + (tclStubsPtr->tcl_CreateAliasObj) /* 87 */ +#define Tcl_CreateChannel \ + (tclStubsPtr->tcl_CreateChannel) /* 88 */ +#define Tcl_CreateChannelHandler \ + (tclStubsPtr->tcl_CreateChannelHandler) /* 89 */ +#define Tcl_CreateCloseHandler \ + (tclStubsPtr->tcl_CreateCloseHandler) /* 90 */ +#define Tcl_CreateCommand \ + (tclStubsPtr->tcl_CreateCommand) /* 91 */ +#define Tcl_CreateEventSource \ + (tclStubsPtr->tcl_CreateEventSource) /* 92 */ +#define Tcl_CreateExitHandler \ + (tclStubsPtr->tcl_CreateExitHandler) /* 93 */ +#define Tcl_CreateInterp \ + (tclStubsPtr->tcl_CreateInterp) /* 94 */ +#define Tcl_CreateMathFunc \ + (tclStubsPtr->tcl_CreateMathFunc) /* 95 */ +#define Tcl_CreateObjCommand \ + (tclStubsPtr->tcl_CreateObjCommand) /* 96 */ +#define Tcl_CreateSlave \ + (tclStubsPtr->tcl_CreateSlave) /* 97 */ +#define Tcl_CreateTimerHandler \ + (tclStubsPtr->tcl_CreateTimerHandler) /* 98 */ +#define Tcl_CreateTrace \ + (tclStubsPtr->tcl_CreateTrace) /* 99 */ +#define Tcl_DeleteAssocData \ + (tclStubsPtr->tcl_DeleteAssocData) /* 100 */ +#define Tcl_DeleteChannelHandler \ + (tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */ +#define Tcl_DeleteCloseHandler \ + (tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */ +#define Tcl_DeleteCommand \ + (tclStubsPtr->tcl_DeleteCommand) /* 103 */ +#define Tcl_DeleteCommandFromToken \ + (tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */ +#define Tcl_DeleteEvents \ + (tclStubsPtr->tcl_DeleteEvents) /* 105 */ +#define Tcl_DeleteEventSource \ + (tclStubsPtr->tcl_DeleteEventSource) /* 106 */ +#define Tcl_DeleteExitHandler \ + (tclStubsPtr->tcl_DeleteExitHandler) /* 107 */ +#define Tcl_DeleteHashEntry \ + (tclStubsPtr->tcl_DeleteHashEntry) /* 108 */ +#define Tcl_DeleteHashTable \ + (tclStubsPtr->tcl_DeleteHashTable) /* 109 */ +#define Tcl_DeleteInterp \ + (tclStubsPtr->tcl_DeleteInterp) /* 110 */ +#define Tcl_DetachPids \ + (tclStubsPtr->tcl_DetachPids) /* 111 */ +#define Tcl_DeleteTimerHandler \ + (tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */ +#define Tcl_DeleteTrace \ + (tclStubsPtr->tcl_DeleteTrace) /* 113 */ +#define Tcl_DontCallWhenDeleted \ + (tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */ +#define Tcl_DoOneEvent \ + (tclStubsPtr->tcl_DoOneEvent) /* 115 */ +#define Tcl_DoWhenIdle \ + (tclStubsPtr->tcl_DoWhenIdle) /* 116 */ +#define Tcl_DStringAppend \ + (tclStubsPtr->tcl_DStringAppend) /* 117 */ +#define Tcl_DStringAppendElement \ + (tclStubsPtr->tcl_DStringAppendElement) /* 118 */ +#define Tcl_DStringEndSublist \ + (tclStubsPtr->tcl_DStringEndSublist) /* 119 */ +#define Tcl_DStringFree \ + (tclStubsPtr->tcl_DStringFree) /* 120 */ +#define Tcl_DStringGetResult \ + (tclStubsPtr->tcl_DStringGetResult) /* 121 */ +#define Tcl_DStringInit \ + (tclStubsPtr->tcl_DStringInit) /* 122 */ +#define Tcl_DStringResult \ + (tclStubsPtr->tcl_DStringResult) /* 123 */ +#define Tcl_DStringSetLength \ + (tclStubsPtr->tcl_DStringSetLength) /* 124 */ +#define Tcl_DStringStartSublist \ + (tclStubsPtr->tcl_DStringStartSublist) /* 125 */ +#define Tcl_Eof \ + (tclStubsPtr->tcl_Eof) /* 126 */ +#define Tcl_ErrnoId \ + (tclStubsPtr->tcl_ErrnoId) /* 127 */ +#define Tcl_ErrnoMsg \ + (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ +#define Tcl_Eval \ + (tclStubsPtr->tcl_Eval) /* 129 */ +#define Tcl_EvalFile \ + (tclStubsPtr->tcl_EvalFile) /* 130 */ +#define Tcl_EvalObj \ + (tclStubsPtr->tcl_EvalObj) /* 131 */ +#define Tcl_EventuallyFree \ + (tclStubsPtr->tcl_EventuallyFree) /* 132 */ +#define Tcl_Exit \ + (tclStubsPtr->tcl_Exit) /* 133 */ +#define Tcl_ExposeCommand \ + (tclStubsPtr->tcl_ExposeCommand) /* 134 */ +#define Tcl_ExprBoolean \ + (tclStubsPtr->tcl_ExprBoolean) /* 135 */ +#define Tcl_ExprBooleanObj \ + (tclStubsPtr->tcl_ExprBooleanObj) /* 136 */ +#define Tcl_ExprDouble \ + (tclStubsPtr->tcl_ExprDouble) /* 137 */ +#define Tcl_ExprDoubleObj \ + (tclStubsPtr->tcl_ExprDoubleObj) /* 138 */ +#define Tcl_ExprLong \ + (tclStubsPtr->tcl_ExprLong) /* 139 */ +#define Tcl_ExprLongObj \ + (tclStubsPtr->tcl_ExprLongObj) /* 140 */ +#define Tcl_ExprObj \ + (tclStubsPtr->tcl_ExprObj) /* 141 */ +#define Tcl_ExprString \ + (tclStubsPtr->tcl_ExprString) /* 142 */ +#define Tcl_Finalize \ + (tclStubsPtr->tcl_Finalize) /* 143 */ +#define Tcl_FindExecutable \ + (tclStubsPtr->tcl_FindExecutable) /* 144 */ +#define Tcl_FirstHashEntry \ + (tclStubsPtr->tcl_FirstHashEntry) /* 145 */ +#define Tcl_Flush \ + (tclStubsPtr->tcl_Flush) /* 146 */ +#define Tcl_FreeResult \ + (tclStubsPtr->tcl_FreeResult) /* 147 */ +#define Tcl_GetAlias \ + (tclStubsPtr->tcl_GetAlias) /* 148 */ +#define Tcl_GetAliasObj \ + (tclStubsPtr->tcl_GetAliasObj) /* 149 */ +#define Tcl_GetAssocData \ + (tclStubsPtr->tcl_GetAssocData) /* 150 */ +#define Tcl_GetChannel \ + (tclStubsPtr->tcl_GetChannel) /* 151 */ +#define Tcl_GetChannelBufferSize \ + (tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */ +#define Tcl_GetChannelHandle \ + (tclStubsPtr->tcl_GetChannelHandle) /* 153 */ +#define Tcl_GetChannelInstanceData \ + (tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */ +#define Tcl_GetChannelMode \ + (tclStubsPtr->tcl_GetChannelMode) /* 155 */ +#define Tcl_GetChannelName \ + (tclStubsPtr->tcl_GetChannelName) /* 156 */ +#define Tcl_GetChannelOption \ + (tclStubsPtr->tcl_GetChannelOption) /* 157 */ +#define Tcl_GetChannelType \ + (tclStubsPtr->tcl_GetChannelType) /* 158 */ +#define Tcl_GetCommandInfo \ + (tclStubsPtr->tcl_GetCommandInfo) /* 159 */ +#define Tcl_GetCommandName \ + (tclStubsPtr->tcl_GetCommandName) /* 160 */ +#define Tcl_GetErrno \ + (tclStubsPtr->tcl_GetErrno) /* 161 */ +#define Tcl_GetHostName \ + (tclStubsPtr->tcl_GetHostName) /* 162 */ +#define Tcl_GetInterpPath \ + (tclStubsPtr->tcl_GetInterpPath) /* 163 */ +#define Tcl_GetMaster \ + (tclStubsPtr->tcl_GetMaster) /* 164 */ +#define Tcl_GetNameOfExecutable \ + (tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */ +#define Tcl_GetObjResult \ + (tclStubsPtr->tcl_GetObjResult) /* 166 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +#define Tcl_GetOpenFile \ + (tclStubsPtr->tcl_GetOpenFile) /* 167 */ +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_GetOpenFile \ + (tclStubsPtr->tcl_GetOpenFile) /* 167 */ +#endif /* MACOSX */ +#define Tcl_GetPathType \ + (tclStubsPtr->tcl_GetPathType) /* 168 */ +#define Tcl_Gets \ + (tclStubsPtr->tcl_Gets) /* 169 */ +#define Tcl_GetsObj \ + (tclStubsPtr->tcl_GetsObj) /* 170 */ +#define Tcl_GetServiceMode \ + (tclStubsPtr->tcl_GetServiceMode) /* 171 */ +#define Tcl_GetSlave \ + (tclStubsPtr->tcl_GetSlave) /* 172 */ +#define Tcl_GetStdChannel \ + (tclStubsPtr->tcl_GetStdChannel) /* 173 */ +#define Tcl_GetStringResult \ + (tclStubsPtr->tcl_GetStringResult) /* 174 */ +#define Tcl_GetVar \ + (tclStubsPtr->tcl_GetVar) /* 175 */ +#define Tcl_GetVar2 \ + (tclStubsPtr->tcl_GetVar2) /* 176 */ +#define Tcl_GlobalEval \ + (tclStubsPtr->tcl_GlobalEval) /* 177 */ +#define Tcl_GlobalEvalObj \ + (tclStubsPtr->tcl_GlobalEvalObj) /* 178 */ +#define Tcl_HideCommand \ + (tclStubsPtr->tcl_HideCommand) /* 179 */ +#define Tcl_Init \ + (tclStubsPtr->tcl_Init) /* 180 */ +#define Tcl_InitHashTable \ + (tclStubsPtr->tcl_InitHashTable) /* 181 */ +#define Tcl_InputBlocked \ + (tclStubsPtr->tcl_InputBlocked) /* 182 */ +#define Tcl_InputBuffered \ + (tclStubsPtr->tcl_InputBuffered) /* 183 */ +#define Tcl_InterpDeleted \ + (tclStubsPtr->tcl_InterpDeleted) /* 184 */ +#define Tcl_IsSafe \ + (tclStubsPtr->tcl_IsSafe) /* 185 */ +#define Tcl_JoinPath \ + (tclStubsPtr->tcl_JoinPath) /* 186 */ +#define Tcl_LinkVar \ + (tclStubsPtr->tcl_LinkVar) /* 187 */ +/* Slot 188 is reserved */ +#define Tcl_MakeFileChannel \ + (tclStubsPtr->tcl_MakeFileChannel) /* 189 */ +#define Tcl_MakeSafe \ + (tclStubsPtr->tcl_MakeSafe) /* 190 */ +#define Tcl_MakeTcpClientChannel \ + (tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */ +#define Tcl_Merge \ + (tclStubsPtr->tcl_Merge) /* 192 */ +#define Tcl_NextHashEntry \ + (tclStubsPtr->tcl_NextHashEntry) /* 193 */ +#define Tcl_NotifyChannel \ + (tclStubsPtr->tcl_NotifyChannel) /* 194 */ +#define Tcl_ObjGetVar2 \ + (tclStubsPtr->tcl_ObjGetVar2) /* 195 */ +#define Tcl_ObjSetVar2 \ + (tclStubsPtr->tcl_ObjSetVar2) /* 196 */ +#define Tcl_OpenCommandChannel \ + (tclStubsPtr->tcl_OpenCommandChannel) /* 197 */ +#define Tcl_OpenFileChannel \ + (tclStubsPtr->tcl_OpenFileChannel) /* 198 */ +#define Tcl_OpenTcpClient \ + (tclStubsPtr->tcl_OpenTcpClient) /* 199 */ +#define Tcl_OpenTcpServer \ + (tclStubsPtr->tcl_OpenTcpServer) /* 200 */ +#define Tcl_Preserve \ + (tclStubsPtr->tcl_Preserve) /* 201 */ +#define Tcl_PrintDouble \ + (tclStubsPtr->tcl_PrintDouble) /* 202 */ +#define Tcl_PutEnv \ + (tclStubsPtr->tcl_PutEnv) /* 203 */ +#define Tcl_PosixError \ + (tclStubsPtr->tcl_PosixError) /* 204 */ +#define Tcl_QueueEvent \ + (tclStubsPtr->tcl_QueueEvent) /* 205 */ +#define Tcl_Read \ + (tclStubsPtr->tcl_Read) /* 206 */ +#define Tcl_ReapDetachedProcs \ + (tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */ +#define Tcl_RecordAndEval \ + (tclStubsPtr->tcl_RecordAndEval) /* 208 */ +#define Tcl_RecordAndEvalObj \ + (tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */ +#define Tcl_RegisterChannel \ + (tclStubsPtr->tcl_RegisterChannel) /* 210 */ +#define Tcl_RegisterObjType \ + (tclStubsPtr->tcl_RegisterObjType) /* 211 */ +#define Tcl_RegExpCompile \ + (tclStubsPtr->tcl_RegExpCompile) /* 212 */ +#define Tcl_RegExpExec \ + (tclStubsPtr->tcl_RegExpExec) /* 213 */ +#define Tcl_RegExpMatch \ + (tclStubsPtr->tcl_RegExpMatch) /* 214 */ +#define Tcl_RegExpRange \ + (tclStubsPtr->tcl_RegExpRange) /* 215 */ +#define Tcl_Release \ + (tclStubsPtr->tcl_Release) /* 216 */ +#define Tcl_ResetResult \ + (tclStubsPtr->tcl_ResetResult) /* 217 */ +#define Tcl_ScanElement \ + (tclStubsPtr->tcl_ScanElement) /* 218 */ +#define Tcl_ScanCountedElement \ + (tclStubsPtr->tcl_ScanCountedElement) /* 219 */ +#define Tcl_SeekOld \ + (tclStubsPtr->tcl_SeekOld) /* 220 */ +#define Tcl_ServiceAll \ + (tclStubsPtr->tcl_ServiceAll) /* 221 */ +#define Tcl_ServiceEvent \ + (tclStubsPtr->tcl_ServiceEvent) /* 222 */ +#define Tcl_SetAssocData \ + (tclStubsPtr->tcl_SetAssocData) /* 223 */ +#define Tcl_SetChannelBufferSize \ + (tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */ +#define Tcl_SetChannelOption \ + (tclStubsPtr->tcl_SetChannelOption) /* 225 */ +#define Tcl_SetCommandInfo \ + (tclStubsPtr->tcl_SetCommandInfo) /* 226 */ +#define Tcl_SetErrno \ + (tclStubsPtr->tcl_SetErrno) /* 227 */ +#define Tcl_SetErrorCode \ + (tclStubsPtr->tcl_SetErrorCode) /* 228 */ +#define Tcl_SetMaxBlockTime \ + (tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */ +#define Tcl_SetPanicProc \ + (tclStubsPtr->tcl_SetPanicProc) /* 230 */ +#define Tcl_SetRecursionLimit \ + (tclStubsPtr->tcl_SetRecursionLimit) /* 231 */ +#define Tcl_SetResult \ + (tclStubsPtr->tcl_SetResult) /* 232 */ +#define Tcl_SetServiceMode \ + (tclStubsPtr->tcl_SetServiceMode) /* 233 */ +#define Tcl_SetObjErrorCode \ + (tclStubsPtr->tcl_SetObjErrorCode) /* 234 */ +#define Tcl_SetObjResult \ + (tclStubsPtr->tcl_SetObjResult) /* 235 */ +#define Tcl_SetStdChannel \ + (tclStubsPtr->tcl_SetStdChannel) /* 236 */ +#define Tcl_SetVar \ + (tclStubsPtr->tcl_SetVar) /* 237 */ +#define Tcl_SetVar2 \ + (tclStubsPtr->tcl_SetVar2) /* 238 */ +#define Tcl_SignalId \ + (tclStubsPtr->tcl_SignalId) /* 239 */ +#define Tcl_SignalMsg \ + (tclStubsPtr->tcl_SignalMsg) /* 240 */ +#define Tcl_SourceRCFile \ + (tclStubsPtr->tcl_SourceRCFile) /* 241 */ +#define Tcl_SplitList \ + (tclStubsPtr->tcl_SplitList) /* 242 */ +#define Tcl_SplitPath \ + (tclStubsPtr->tcl_SplitPath) /* 243 */ +#define Tcl_StaticPackage \ + (tclStubsPtr->tcl_StaticPackage) /* 244 */ +#define Tcl_StringMatch \ + (tclStubsPtr->tcl_StringMatch) /* 245 */ +#define Tcl_TellOld \ + (tclStubsPtr->tcl_TellOld) /* 246 */ +#define Tcl_TraceVar \ + (tclStubsPtr->tcl_TraceVar) /* 247 */ +#define Tcl_TraceVar2 \ + (tclStubsPtr->tcl_TraceVar2) /* 248 */ +#define Tcl_TranslateFileName \ + (tclStubsPtr->tcl_TranslateFileName) /* 249 */ +#define Tcl_Ungets \ + (tclStubsPtr->tcl_Ungets) /* 250 */ +#define Tcl_UnlinkVar \ + (tclStubsPtr->tcl_UnlinkVar) /* 251 */ +#define Tcl_UnregisterChannel \ + (tclStubsPtr->tcl_UnregisterChannel) /* 252 */ +#define Tcl_UnsetVar \ + (tclStubsPtr->tcl_UnsetVar) /* 253 */ +#define Tcl_UnsetVar2 \ + (tclStubsPtr->tcl_UnsetVar2) /* 254 */ +#define Tcl_UntraceVar \ + (tclStubsPtr->tcl_UntraceVar) /* 255 */ +#define Tcl_UntraceVar2 \ + (tclStubsPtr->tcl_UntraceVar2) /* 256 */ +#define Tcl_UpdateLinkedVar \ + (tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */ +#define Tcl_UpVar \ + (tclStubsPtr->tcl_UpVar) /* 258 */ +#define Tcl_UpVar2 \ + (tclStubsPtr->tcl_UpVar2) /* 259 */ +#define Tcl_VarEval \ + (tclStubsPtr->tcl_VarEval) /* 260 */ +#define Tcl_VarTraceInfo \ + (tclStubsPtr->tcl_VarTraceInfo) /* 261 */ +#define Tcl_VarTraceInfo2 \ + (tclStubsPtr->tcl_VarTraceInfo2) /* 262 */ +#define Tcl_Write \ + (tclStubsPtr->tcl_Write) /* 263 */ +#define Tcl_WrongNumArgs \ + (tclStubsPtr->tcl_WrongNumArgs) /* 264 */ +#define Tcl_DumpActiveMemory \ + (tclStubsPtr->tcl_DumpActiveMemory) /* 265 */ +#define Tcl_ValidateAllMemory \ + (tclStubsPtr->tcl_ValidateAllMemory) /* 266 */ +#define Tcl_AppendResultVA \ + (tclStubsPtr->tcl_AppendResultVA) /* 267 */ +#define Tcl_AppendStringsToObjVA \ + (tclStubsPtr->tcl_AppendStringsToObjVA) /* 268 */ +#define Tcl_HashStats \ + (tclStubsPtr->tcl_HashStats) /* 269 */ +#define Tcl_ParseVar \ + (tclStubsPtr->tcl_ParseVar) /* 270 */ +#define Tcl_PkgPresent \ + (tclStubsPtr->tcl_PkgPresent) /* 271 */ +#define Tcl_PkgPresentEx \ + (tclStubsPtr->tcl_PkgPresentEx) /* 272 */ +#define Tcl_PkgProvide \ + (tclStubsPtr->tcl_PkgProvide) /* 273 */ +#define Tcl_PkgRequire \ + (tclStubsPtr->tcl_PkgRequire) /* 274 */ +#define Tcl_SetErrorCodeVA \ + (tclStubsPtr->tcl_SetErrorCodeVA) /* 275 */ +#define Tcl_VarEvalVA \ + (tclStubsPtr->tcl_VarEvalVA) /* 276 */ +#define Tcl_WaitPid \ + (tclStubsPtr->tcl_WaitPid) /* 277 */ +#define Tcl_PanicVA \ + (tclStubsPtr->tcl_PanicVA) /* 278 */ +#define Tcl_GetVersion \ + (tclStubsPtr->tcl_GetVersion) /* 279 */ +#define Tcl_InitMemory \ + (tclStubsPtr->tcl_InitMemory) /* 280 */ +#define Tcl_StackChannel \ + (tclStubsPtr->tcl_StackChannel) /* 281 */ +#define Tcl_UnstackChannel \ + (tclStubsPtr->tcl_UnstackChannel) /* 282 */ +#define Tcl_GetStackedChannel \ + (tclStubsPtr->tcl_GetStackedChannel) /* 283 */ +#define Tcl_SetMainLoop \ + (tclStubsPtr->tcl_SetMainLoop) /* 284 */ +/* Slot 285 is reserved */ +#define Tcl_AppendObjToObj \ + (tclStubsPtr->tcl_AppendObjToObj) /* 286 */ +#define Tcl_CreateEncoding \ + (tclStubsPtr->tcl_CreateEncoding) /* 287 */ +#define Tcl_CreateThreadExitHandler \ + (tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */ +#define Tcl_DeleteThreadExitHandler \ + (tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */ +#define Tcl_DiscardResult \ + (tclStubsPtr->tcl_DiscardResult) /* 290 */ +#define Tcl_EvalEx \ + (tclStubsPtr->tcl_EvalEx) /* 291 */ +#define Tcl_EvalObjv \ + (tclStubsPtr->tcl_EvalObjv) /* 292 */ +#define Tcl_EvalObjEx \ + (tclStubsPtr->tcl_EvalObjEx) /* 293 */ +#define Tcl_ExitThread \ + (tclStubsPtr->tcl_ExitThread) /* 294 */ +#define Tcl_ExternalToUtf \ + (tclStubsPtr->tcl_ExternalToUtf) /* 295 */ +#define Tcl_ExternalToUtfDString \ + (tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */ +#define Tcl_FinalizeThread \ + (tclStubsPtr->tcl_FinalizeThread) /* 297 */ +#define Tcl_FinalizeNotifier \ + (tclStubsPtr->tcl_FinalizeNotifier) /* 298 */ +#define Tcl_FreeEncoding \ + (tclStubsPtr->tcl_FreeEncoding) /* 299 */ +#define Tcl_GetCurrentThread \ + (tclStubsPtr->tcl_GetCurrentThread) /* 300 */ +#define Tcl_GetEncoding \ + (tclStubsPtr->tcl_GetEncoding) /* 301 */ +#define Tcl_GetEncodingName \ + (tclStubsPtr->tcl_GetEncodingName) /* 302 */ +#define Tcl_GetEncodingNames \ + (tclStubsPtr->tcl_GetEncodingNames) /* 303 */ +#define Tcl_GetIndexFromObjStruct \ + (tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */ +#define Tcl_GetThreadData \ + (tclStubsPtr->tcl_GetThreadData) /* 305 */ +#define Tcl_GetVar2Ex \ + (tclStubsPtr->tcl_GetVar2Ex) /* 306 */ +#define Tcl_InitNotifier \ + (tclStubsPtr->tcl_InitNotifier) /* 307 */ +#define Tcl_MutexLock \ + (tclStubsPtr->tcl_MutexLock) /* 308 */ +#define Tcl_MutexUnlock \ + (tclStubsPtr->tcl_MutexUnlock) /* 309 */ +#define Tcl_ConditionNotify \ + (tclStubsPtr->tcl_ConditionNotify) /* 310 */ +#define Tcl_ConditionWait \ + (tclStubsPtr->tcl_ConditionWait) /* 311 */ +#define Tcl_NumUtfChars \ + (tclStubsPtr->tcl_NumUtfChars) /* 312 */ +#define Tcl_ReadChars \ + (tclStubsPtr->tcl_ReadChars) /* 313 */ +#define Tcl_RestoreResult \ + (tclStubsPtr->tcl_RestoreResult) /* 314 */ +#define Tcl_SaveResult \ + (tclStubsPtr->tcl_SaveResult) /* 315 */ +#define Tcl_SetSystemEncoding \ + (tclStubsPtr->tcl_SetSystemEncoding) /* 316 */ +#define Tcl_SetVar2Ex \ + (tclStubsPtr->tcl_SetVar2Ex) /* 317 */ +#define Tcl_ThreadAlert \ + (tclStubsPtr->tcl_ThreadAlert) /* 318 */ +#define Tcl_ThreadQueueEvent \ + (tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */ +#define Tcl_UniCharAtIndex \ + (tclStubsPtr->tcl_UniCharAtIndex) /* 320 */ +#define Tcl_UniCharToLower \ + (tclStubsPtr->tcl_UniCharToLower) /* 321 */ +#define Tcl_UniCharToTitle \ + (tclStubsPtr->tcl_UniCharToTitle) /* 322 */ +#define Tcl_UniCharToUpper \ + (tclStubsPtr->tcl_UniCharToUpper) /* 323 */ +#define Tcl_UniCharToUtf \ + (tclStubsPtr->tcl_UniCharToUtf) /* 324 */ +#define Tcl_UtfAtIndex \ + (tclStubsPtr->tcl_UtfAtIndex) /* 325 */ +#define Tcl_UtfCharComplete \ + (tclStubsPtr->tcl_UtfCharComplete) /* 326 */ +#define Tcl_UtfBackslash \ + (tclStubsPtr->tcl_UtfBackslash) /* 327 */ +#define Tcl_UtfFindFirst \ + (tclStubsPtr->tcl_UtfFindFirst) /* 328 */ +#define Tcl_UtfFindLast \ + (tclStubsPtr->tcl_UtfFindLast) /* 329 */ +#define Tcl_UtfNext \ + (tclStubsPtr->tcl_UtfNext) /* 330 */ +#define Tcl_UtfPrev \ + (tclStubsPtr->tcl_UtfPrev) /* 331 */ +#define Tcl_UtfToExternal \ + (tclStubsPtr->tcl_UtfToExternal) /* 332 */ +#define Tcl_UtfToExternalDString \ + (tclStubsPtr->tcl_UtfToExternalDString) /* 333 */ +#define Tcl_UtfToLower \ + (tclStubsPtr->tcl_UtfToLower) /* 334 */ +#define Tcl_UtfToTitle \ + (tclStubsPtr->tcl_UtfToTitle) /* 335 */ +#define Tcl_UtfToUniChar \ + (tclStubsPtr->tcl_UtfToUniChar) /* 336 */ +#define Tcl_UtfToUpper \ + (tclStubsPtr->tcl_UtfToUpper) /* 337 */ +#define Tcl_WriteChars \ + (tclStubsPtr->tcl_WriteChars) /* 338 */ +#define Tcl_WriteObj \ + (tclStubsPtr->tcl_WriteObj) /* 339 */ +#define Tcl_GetString \ + (tclStubsPtr->tcl_GetString) /* 340 */ +#define Tcl_GetDefaultEncodingDir \ + (tclStubsPtr->tcl_GetDefaultEncodingDir) /* 341 */ +#define Tcl_SetDefaultEncodingDir \ + (tclStubsPtr->tcl_SetDefaultEncodingDir) /* 342 */ +#define Tcl_AlertNotifier \ + (tclStubsPtr->tcl_AlertNotifier) /* 343 */ +#define Tcl_ServiceModeHook \ + (tclStubsPtr->tcl_ServiceModeHook) /* 344 */ +#define Tcl_UniCharIsAlnum \ + (tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */ +#define Tcl_UniCharIsAlpha \ + (tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */ +#define Tcl_UniCharIsDigit \ + (tclStubsPtr->tcl_UniCharIsDigit) /* 347 */ +#define Tcl_UniCharIsLower \ + (tclStubsPtr->tcl_UniCharIsLower) /* 348 */ +#define Tcl_UniCharIsSpace \ + (tclStubsPtr->tcl_UniCharIsSpace) /* 349 */ +#define Tcl_UniCharIsUpper \ + (tclStubsPtr->tcl_UniCharIsUpper) /* 350 */ +#define Tcl_UniCharIsWordChar \ + (tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */ +#define Tcl_UniCharLen \ + (tclStubsPtr->tcl_UniCharLen) /* 352 */ +#define Tcl_UniCharNcmp \ + (tclStubsPtr->tcl_UniCharNcmp) /* 353 */ +#define Tcl_UniCharToUtfDString \ + (tclStubsPtr->tcl_UniCharToUtfDString) /* 354 */ +#define Tcl_UtfToUniCharDString \ + (tclStubsPtr->tcl_UtfToUniCharDString) /* 355 */ +#define Tcl_GetRegExpFromObj \ + (tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */ +#define Tcl_EvalTokens \ + (tclStubsPtr->tcl_EvalTokens) /* 357 */ +#define Tcl_FreeParse \ + (tclStubsPtr->tcl_FreeParse) /* 358 */ +#define Tcl_LogCommandInfo \ + (tclStubsPtr->tcl_LogCommandInfo) /* 359 */ +#define Tcl_ParseBraces \ + (tclStubsPtr->tcl_ParseBraces) /* 360 */ +#define Tcl_ParseCommand \ + (tclStubsPtr->tcl_ParseCommand) /* 361 */ +#define Tcl_ParseExpr \ + (tclStubsPtr->tcl_ParseExpr) /* 362 */ +#define Tcl_ParseQuotedString \ + (tclStubsPtr->tcl_ParseQuotedString) /* 363 */ +#define Tcl_ParseVarName \ + (tclStubsPtr->tcl_ParseVarName) /* 364 */ +#define Tcl_GetCwd \ + (tclStubsPtr->tcl_GetCwd) /* 365 */ +#define Tcl_Chdir \ + (tclStubsPtr->tcl_Chdir) /* 366 */ +#define Tcl_Access \ + (tclStubsPtr->tcl_Access) /* 367 */ +#define Tcl_Stat \ + (tclStubsPtr->tcl_Stat) /* 368 */ +#define Tcl_UtfNcmp \ + (tclStubsPtr->tcl_UtfNcmp) /* 369 */ +#define Tcl_UtfNcasecmp \ + (tclStubsPtr->tcl_UtfNcasecmp) /* 370 */ +#define Tcl_StringCaseMatch \ + (tclStubsPtr->tcl_StringCaseMatch) /* 371 */ +#define Tcl_UniCharIsControl \ + (tclStubsPtr->tcl_UniCharIsControl) /* 372 */ +#define Tcl_UniCharIsGraph \ + (tclStubsPtr->tcl_UniCharIsGraph) /* 373 */ +#define Tcl_UniCharIsPrint \ + (tclStubsPtr->tcl_UniCharIsPrint) /* 374 */ +#define Tcl_UniCharIsPunct \ + (tclStubsPtr->tcl_UniCharIsPunct) /* 375 */ +#define Tcl_RegExpExecObj \ + (tclStubsPtr->tcl_RegExpExecObj) /* 376 */ +#define Tcl_RegExpGetInfo \ + (tclStubsPtr->tcl_RegExpGetInfo) /* 377 */ +#define Tcl_NewUnicodeObj \ + (tclStubsPtr->tcl_NewUnicodeObj) /* 378 */ +#define Tcl_SetUnicodeObj \ + (tclStubsPtr->tcl_SetUnicodeObj) /* 379 */ +#define Tcl_GetCharLength \ + (tclStubsPtr->tcl_GetCharLength) /* 380 */ +#define Tcl_GetUniChar \ + (tclStubsPtr->tcl_GetUniChar) /* 381 */ +#define Tcl_GetUnicode \ + (tclStubsPtr->tcl_GetUnicode) /* 382 */ +#define Tcl_GetRange \ + (tclStubsPtr->tcl_GetRange) /* 383 */ +#define Tcl_AppendUnicodeToObj \ + (tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */ +#define Tcl_RegExpMatchObj \ + (tclStubsPtr->tcl_RegExpMatchObj) /* 385 */ +#define Tcl_SetNotifier \ + (tclStubsPtr->tcl_SetNotifier) /* 386 */ +#define Tcl_GetAllocMutex \ + (tclStubsPtr->tcl_GetAllocMutex) /* 387 */ +#define Tcl_GetChannelNames \ + (tclStubsPtr->tcl_GetChannelNames) /* 388 */ +#define Tcl_GetChannelNamesEx \ + (tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */ +#define Tcl_ProcObjCmd \ + (tclStubsPtr->tcl_ProcObjCmd) /* 390 */ +#define Tcl_ConditionFinalize \ + (tclStubsPtr->tcl_ConditionFinalize) /* 391 */ +#define Tcl_MutexFinalize \ + (tclStubsPtr->tcl_MutexFinalize) /* 392 */ +#define Tcl_CreateThread \ + (tclStubsPtr->tcl_CreateThread) /* 393 */ +#define Tcl_ReadRaw \ + (tclStubsPtr->tcl_ReadRaw) /* 394 */ +#define Tcl_WriteRaw \ + (tclStubsPtr->tcl_WriteRaw) /* 395 */ +#define Tcl_GetTopChannel \ + (tclStubsPtr->tcl_GetTopChannel) /* 396 */ +#define Tcl_ChannelBuffered \ + (tclStubsPtr->tcl_ChannelBuffered) /* 397 */ +#define Tcl_ChannelName \ + (tclStubsPtr->tcl_ChannelName) /* 398 */ +#define Tcl_ChannelVersion \ + (tclStubsPtr->tcl_ChannelVersion) /* 399 */ +#define Tcl_ChannelBlockModeProc \ + (tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */ +#define Tcl_ChannelCloseProc \ + (tclStubsPtr->tcl_ChannelCloseProc) /* 401 */ +#define Tcl_ChannelClose2Proc \ + (tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */ +#define Tcl_ChannelInputProc \ + (tclStubsPtr->tcl_ChannelInputProc) /* 403 */ +#define Tcl_ChannelOutputProc \ + (tclStubsPtr->tcl_ChannelOutputProc) /* 404 */ +#define Tcl_ChannelSeekProc \ + (tclStubsPtr->tcl_ChannelSeekProc) /* 405 */ +#define Tcl_ChannelSetOptionProc \ + (tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */ +#define Tcl_ChannelGetOptionProc \ + (tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */ +#define Tcl_ChannelWatchProc \ + (tclStubsPtr->tcl_ChannelWatchProc) /* 408 */ +#define Tcl_ChannelGetHandleProc \ + (tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */ +#define Tcl_ChannelFlushProc \ + (tclStubsPtr->tcl_ChannelFlushProc) /* 410 */ +#define Tcl_ChannelHandlerProc \ + (tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */ +#define Tcl_JoinThread \ + (tclStubsPtr->tcl_JoinThread) /* 412 */ +#define Tcl_IsChannelShared \ + (tclStubsPtr->tcl_IsChannelShared) /* 413 */ +#define Tcl_IsChannelRegistered \ + (tclStubsPtr->tcl_IsChannelRegistered) /* 414 */ +#define Tcl_CutChannel \ + (tclStubsPtr->tcl_CutChannel) /* 415 */ +#define Tcl_SpliceChannel \ + (tclStubsPtr->tcl_SpliceChannel) /* 416 */ +#define Tcl_ClearChannelHandlers \ + (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ +#define Tcl_IsChannelExisting \ + (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ +#define Tcl_UniCharNcasecmp \ + (tclStubsPtr->tcl_UniCharNcasecmp) /* 419 */ +#define Tcl_UniCharCaseMatch \ + (tclStubsPtr->tcl_UniCharCaseMatch) /* 420 */ +#define Tcl_FindHashEntry \ + (tclStubsPtr->tcl_FindHashEntry) /* 421 */ +#define Tcl_CreateHashEntry \ + (tclStubsPtr->tcl_CreateHashEntry) /* 422 */ +#define Tcl_InitCustomHashTable \ + (tclStubsPtr->tcl_InitCustomHashTable) /* 423 */ +#define Tcl_InitObjHashTable \ + (tclStubsPtr->tcl_InitObjHashTable) /* 424 */ +#define Tcl_CommandTraceInfo \ + (tclStubsPtr->tcl_CommandTraceInfo) /* 425 */ +#define Tcl_TraceCommand \ + (tclStubsPtr->tcl_TraceCommand) /* 426 */ +#define Tcl_UntraceCommand \ + (tclStubsPtr->tcl_UntraceCommand) /* 427 */ +#define Tcl_AttemptAlloc \ + (tclStubsPtr->tcl_AttemptAlloc) /* 428 */ +#define Tcl_AttemptDbCkalloc \ + (tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */ +#define Tcl_AttemptRealloc \ + (tclStubsPtr->tcl_AttemptRealloc) /* 430 */ +#define Tcl_AttemptDbCkrealloc \ + (tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */ +#define Tcl_AttemptSetObjLength \ + (tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */ +#define Tcl_GetChannelThread \ + (tclStubsPtr->tcl_GetChannelThread) /* 433 */ +#define Tcl_GetUnicodeFromObj \ + (tclStubsPtr->tcl_GetUnicodeFromObj) /* 434 */ +#define Tcl_GetMathFuncInfo \ + (tclStubsPtr->tcl_GetMathFuncInfo) /* 435 */ +#define Tcl_ListMathFuncs \ + (tclStubsPtr->tcl_ListMathFuncs) /* 436 */ +#define Tcl_SubstObj \ + (tclStubsPtr->tcl_SubstObj) /* 437 */ +#define Tcl_DetachChannel \ + (tclStubsPtr->tcl_DetachChannel) /* 438 */ +#define Tcl_IsStandardChannel \ + (tclStubsPtr->tcl_IsStandardChannel) /* 439 */ +#define Tcl_FSCopyFile \ + (tclStubsPtr->tcl_FSCopyFile) /* 440 */ +#define Tcl_FSCopyDirectory \ + (tclStubsPtr->tcl_FSCopyDirectory) /* 441 */ +#define Tcl_FSCreateDirectory \ + (tclStubsPtr->tcl_FSCreateDirectory) /* 442 */ +#define Tcl_FSDeleteFile \ + (tclStubsPtr->tcl_FSDeleteFile) /* 443 */ +#define Tcl_FSLoadFile \ + (tclStubsPtr->tcl_FSLoadFile) /* 444 */ +#define Tcl_FSMatchInDirectory \ + (tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */ +#define Tcl_FSLink \ + (tclStubsPtr->tcl_FSLink) /* 446 */ +#define Tcl_FSRemoveDirectory \ + (tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */ +#define Tcl_FSRenameFile \ + (tclStubsPtr->tcl_FSRenameFile) /* 448 */ +#define Tcl_FSLstat \ + (tclStubsPtr->tcl_FSLstat) /* 449 */ +#define Tcl_FSUtime \ + (tclStubsPtr->tcl_FSUtime) /* 450 */ +#define Tcl_FSFileAttrsGet \ + (tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */ +#define Tcl_FSFileAttrsSet \ + (tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */ +#define Tcl_FSFileAttrStrings \ + (tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */ +#define Tcl_FSStat \ + (tclStubsPtr->tcl_FSStat) /* 454 */ +#define Tcl_FSAccess \ + (tclStubsPtr->tcl_FSAccess) /* 455 */ +#define Tcl_FSOpenFileChannel \ + (tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */ +#define Tcl_FSGetCwd \ + (tclStubsPtr->tcl_FSGetCwd) /* 457 */ +#define Tcl_FSChdir \ + (tclStubsPtr->tcl_FSChdir) /* 458 */ +#define Tcl_FSConvertToPathType \ + (tclStubsPtr->tcl_FSConvertToPathType) /* 459 */ +#define Tcl_FSJoinPath \ + (tclStubsPtr->tcl_FSJoinPath) /* 460 */ +#define Tcl_FSSplitPath \ + (tclStubsPtr->tcl_FSSplitPath) /* 461 */ +#define Tcl_FSEqualPaths \ + (tclStubsPtr->tcl_FSEqualPaths) /* 462 */ +#define Tcl_FSGetNormalizedPath \ + (tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */ +#define Tcl_FSJoinToPath \ + (tclStubsPtr->tcl_FSJoinToPath) /* 464 */ +#define Tcl_FSGetInternalRep \ + (tclStubsPtr->tcl_FSGetInternalRep) /* 465 */ +#define Tcl_FSGetTranslatedPath \ + (tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */ +#define Tcl_FSEvalFile \ + (tclStubsPtr->tcl_FSEvalFile) /* 467 */ +#define Tcl_FSNewNativePath \ + (tclStubsPtr->tcl_FSNewNativePath) /* 468 */ +#define Tcl_FSGetNativePath \ + (tclStubsPtr->tcl_FSGetNativePath) /* 469 */ +#define Tcl_FSFileSystemInfo \ + (tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */ +#define Tcl_FSPathSeparator \ + (tclStubsPtr->tcl_FSPathSeparator) /* 471 */ +#define Tcl_FSListVolumes \ + (tclStubsPtr->tcl_FSListVolumes) /* 472 */ +#define Tcl_FSRegister \ + (tclStubsPtr->tcl_FSRegister) /* 473 */ +#define Tcl_FSUnregister \ + (tclStubsPtr->tcl_FSUnregister) /* 474 */ +#define Tcl_FSData \ + (tclStubsPtr->tcl_FSData) /* 475 */ +#define Tcl_FSGetTranslatedStringPath \ + (tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */ +#define Tcl_FSGetFileSystemForPath \ + (tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */ +#define Tcl_FSGetPathType \ + (tclStubsPtr->tcl_FSGetPathType) /* 478 */ +#define Tcl_OutputBuffered \ + (tclStubsPtr->tcl_OutputBuffered) /* 479 */ +#define Tcl_FSMountsChanged \ + (tclStubsPtr->tcl_FSMountsChanged) /* 480 */ +#define Tcl_EvalTokensStandard \ + (tclStubsPtr->tcl_EvalTokensStandard) /* 481 */ +#define Tcl_GetTime \ + (tclStubsPtr->tcl_GetTime) /* 482 */ +#define Tcl_CreateObjTrace \ + (tclStubsPtr->tcl_CreateObjTrace) /* 483 */ +#define Tcl_GetCommandInfoFromToken \ + (tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */ +#define Tcl_SetCommandInfoFromToken \ + (tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */ +#define Tcl_DbNewWideIntObj \ + (tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */ +#define Tcl_GetWideIntFromObj \ + (tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */ +#define Tcl_NewWideIntObj \ + (tclStubsPtr->tcl_NewWideIntObj) /* 488 */ +#define Tcl_SetWideIntObj \ + (tclStubsPtr->tcl_SetWideIntObj) /* 489 */ +#define Tcl_AllocStatBuf \ + (tclStubsPtr->tcl_AllocStatBuf) /* 490 */ +#define Tcl_Seek \ + (tclStubsPtr->tcl_Seek) /* 491 */ +#define Tcl_Tell \ + (tclStubsPtr->tcl_Tell) /* 492 */ +#define Tcl_ChannelWideSeekProc \ + (tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */ +#define Tcl_DictObjPut \ + (tclStubsPtr->tcl_DictObjPut) /* 494 */ +#define Tcl_DictObjGet \ + (tclStubsPtr->tcl_DictObjGet) /* 495 */ +#define Tcl_DictObjRemove \ + (tclStubsPtr->tcl_DictObjRemove) /* 496 */ +#define Tcl_DictObjSize \ + (tclStubsPtr->tcl_DictObjSize) /* 497 */ +#define Tcl_DictObjFirst \ + (tclStubsPtr->tcl_DictObjFirst) /* 498 */ +#define Tcl_DictObjNext \ + (tclStubsPtr->tcl_DictObjNext) /* 499 */ +#define Tcl_DictObjDone \ + (tclStubsPtr->tcl_DictObjDone) /* 500 */ +#define Tcl_DictObjPutKeyList \ + (tclStubsPtr->tcl_DictObjPutKeyList) /* 501 */ +#define Tcl_DictObjRemoveKeyList \ + (tclStubsPtr->tcl_DictObjRemoveKeyList) /* 502 */ +#define Tcl_NewDictObj \ + (tclStubsPtr->tcl_NewDictObj) /* 503 */ +#define Tcl_DbNewDictObj \ + (tclStubsPtr->tcl_DbNewDictObj) /* 504 */ +#define Tcl_RegisterConfig \ + (tclStubsPtr->tcl_RegisterConfig) /* 505 */ +#define Tcl_CreateNamespace \ + (tclStubsPtr->tcl_CreateNamespace) /* 506 */ +#define Tcl_DeleteNamespace \ + (tclStubsPtr->tcl_DeleteNamespace) /* 507 */ +#define Tcl_AppendExportList \ + (tclStubsPtr->tcl_AppendExportList) /* 508 */ +#define Tcl_Export \ + (tclStubsPtr->tcl_Export) /* 509 */ +#define Tcl_Import \ + (tclStubsPtr->tcl_Import) /* 510 */ +#define Tcl_ForgetImport \ + (tclStubsPtr->tcl_ForgetImport) /* 511 */ +#define Tcl_GetCurrentNamespace \ + (tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */ +#define Tcl_GetGlobalNamespace \ + (tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */ +#define Tcl_FindNamespace \ + (tclStubsPtr->tcl_FindNamespace) /* 514 */ +#define Tcl_FindCommand \ + (tclStubsPtr->tcl_FindCommand) /* 515 */ +#define Tcl_GetCommandFromObj \ + (tclStubsPtr->tcl_GetCommandFromObj) /* 516 */ +#define Tcl_GetCommandFullName \ + (tclStubsPtr->tcl_GetCommandFullName) /* 517 */ +#define Tcl_FSEvalFileEx \ + (tclStubsPtr->tcl_FSEvalFileEx) /* 518 */ +#define Tcl_SetExitProc \ + (tclStubsPtr->tcl_SetExitProc) /* 519 */ +#define Tcl_LimitAddHandler \ + (tclStubsPtr->tcl_LimitAddHandler) /* 520 */ +#define Tcl_LimitRemoveHandler \ + (tclStubsPtr->tcl_LimitRemoveHandler) /* 521 */ +#define Tcl_LimitReady \ + (tclStubsPtr->tcl_LimitReady) /* 522 */ +#define Tcl_LimitCheck \ + (tclStubsPtr->tcl_LimitCheck) /* 523 */ +#define Tcl_LimitExceeded \ + (tclStubsPtr->tcl_LimitExceeded) /* 524 */ +#define Tcl_LimitSetCommands \ + (tclStubsPtr->tcl_LimitSetCommands) /* 525 */ +#define Tcl_LimitSetTime \ + (tclStubsPtr->tcl_LimitSetTime) /* 526 */ +#define Tcl_LimitSetGranularity \ + (tclStubsPtr->tcl_LimitSetGranularity) /* 527 */ +#define Tcl_LimitTypeEnabled \ + (tclStubsPtr->tcl_LimitTypeEnabled) /* 528 */ +#define Tcl_LimitTypeExceeded \ + (tclStubsPtr->tcl_LimitTypeExceeded) /* 529 */ +#define Tcl_LimitTypeSet \ + (tclStubsPtr->tcl_LimitTypeSet) /* 530 */ +#define Tcl_LimitTypeReset \ + (tclStubsPtr->tcl_LimitTypeReset) /* 531 */ +#define Tcl_LimitGetCommands \ + (tclStubsPtr->tcl_LimitGetCommands) /* 532 */ +#define Tcl_LimitGetTime \ + (tclStubsPtr->tcl_LimitGetTime) /* 533 */ +#define Tcl_LimitGetGranularity \ + (tclStubsPtr->tcl_LimitGetGranularity) /* 534 */ +#define Tcl_SaveInterpState \ + (tclStubsPtr->tcl_SaveInterpState) /* 535 */ +#define Tcl_RestoreInterpState \ + (tclStubsPtr->tcl_RestoreInterpState) /* 536 */ +#define Tcl_DiscardInterpState \ + (tclStubsPtr->tcl_DiscardInterpState) /* 537 */ +#define Tcl_SetReturnOptions \ + (tclStubsPtr->tcl_SetReturnOptions) /* 538 */ +#define Tcl_GetReturnOptions \ + (tclStubsPtr->tcl_GetReturnOptions) /* 539 */ +#define Tcl_IsEnsemble \ + (tclStubsPtr->tcl_IsEnsemble) /* 540 */ +#define Tcl_CreateEnsemble \ + (tclStubsPtr->tcl_CreateEnsemble) /* 541 */ +#define Tcl_FindEnsemble \ + (tclStubsPtr->tcl_FindEnsemble) /* 542 */ +#define Tcl_SetEnsembleSubcommandList \ + (tclStubsPtr->tcl_SetEnsembleSubcommandList) /* 543 */ +#define Tcl_SetEnsembleMappingDict \ + (tclStubsPtr->tcl_SetEnsembleMappingDict) /* 544 */ +#define Tcl_SetEnsembleUnknownHandler \ + (tclStubsPtr->tcl_SetEnsembleUnknownHandler) /* 545 */ +#define Tcl_SetEnsembleFlags \ + (tclStubsPtr->tcl_SetEnsembleFlags) /* 546 */ +#define Tcl_GetEnsembleSubcommandList \ + (tclStubsPtr->tcl_GetEnsembleSubcommandList) /* 547 */ +#define Tcl_GetEnsembleMappingDict \ + (tclStubsPtr->tcl_GetEnsembleMappingDict) /* 548 */ +#define Tcl_GetEnsembleUnknownHandler \ + (tclStubsPtr->tcl_GetEnsembleUnknownHandler) /* 549 */ +#define Tcl_GetEnsembleFlags \ + (tclStubsPtr->tcl_GetEnsembleFlags) /* 550 */ +#define Tcl_GetEnsembleNamespace \ + (tclStubsPtr->tcl_GetEnsembleNamespace) /* 551 */ +#define Tcl_SetTimeProc \ + (tclStubsPtr->tcl_SetTimeProc) /* 552 */ +#define Tcl_QueryTimeProc \ + (tclStubsPtr->tcl_QueryTimeProc) /* 553 */ +#define Tcl_ChannelThreadActionProc \ + (tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */ +#define Tcl_NewBignumObj \ + (tclStubsPtr->tcl_NewBignumObj) /* 555 */ +#define Tcl_DbNewBignumObj \ + (tclStubsPtr->tcl_DbNewBignumObj) /* 556 */ +#define Tcl_SetBignumObj \ + (tclStubsPtr->tcl_SetBignumObj) /* 557 */ +#define Tcl_GetBignumFromObj \ + (tclStubsPtr->tcl_GetBignumFromObj) /* 558 */ +#define Tcl_TakeBignumFromObj \ + (tclStubsPtr->tcl_TakeBignumFromObj) /* 559 */ +#define Tcl_TruncateChannel \ + (tclStubsPtr->tcl_TruncateChannel) /* 560 */ +#define Tcl_ChannelTruncateProc \ + (tclStubsPtr->tcl_ChannelTruncateProc) /* 561 */ +#define Tcl_SetChannelErrorInterp \ + (tclStubsPtr->tcl_SetChannelErrorInterp) /* 562 */ +#define Tcl_GetChannelErrorInterp \ + (tclStubsPtr->tcl_GetChannelErrorInterp) /* 563 */ +#define Tcl_SetChannelError \ + (tclStubsPtr->tcl_SetChannelError) /* 564 */ +#define Tcl_GetChannelError \ + (tclStubsPtr->tcl_GetChannelError) /* 565 */ +#define Tcl_InitBignumFromDouble \ + (tclStubsPtr->tcl_InitBignumFromDouble) /* 566 */ +#define Tcl_GetNamespaceUnknownHandler \ + (tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 567 */ +#define Tcl_SetNamespaceUnknownHandler \ + (tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 568 */ +#define Tcl_GetEncodingFromObj \ + (tclStubsPtr->tcl_GetEncodingFromObj) /* 569 */ +#define Tcl_GetEncodingSearchPath \ + (tclStubsPtr->tcl_GetEncodingSearchPath) /* 570 */ +#define Tcl_SetEncodingSearchPath \ + (tclStubsPtr->tcl_SetEncodingSearchPath) /* 571 */ +#define Tcl_GetEncodingNameFromEnvironment \ + (tclStubsPtr->tcl_GetEncodingNameFromEnvironment) /* 572 */ +#define Tcl_PkgRequireProc \ + (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ +#define Tcl_AppendObjToErrorInfo \ + (tclStubsPtr->tcl_AppendObjToErrorInfo) /* 574 */ +#define Tcl_AppendLimitedToObj \ + (tclStubsPtr->tcl_AppendLimitedToObj) /* 575 */ +#define Tcl_Format \ + (tclStubsPtr->tcl_Format) /* 576 */ +#define Tcl_AppendFormatToObj \ + (tclStubsPtr->tcl_AppendFormatToObj) /* 577 */ +#define Tcl_ObjPrintf \ + (tclStubsPtr->tcl_ObjPrintf) /* 578 */ +#define Tcl_AppendPrintfToObj \ + (tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */ +#define Tcl_CancelEval \ + (tclStubsPtr->tcl_CancelEval) /* 580 */ +#define Tcl_Canceled \ + (tclStubsPtr->tcl_Canceled) /* 581 */ +#define Tcl_CreatePipe \ + (tclStubsPtr->tcl_CreatePipe) /* 582 */ +#define Tcl_NRCreateCommand \ + (tclStubsPtr->tcl_NRCreateCommand) /* 583 */ +#define Tcl_NREvalObj \ + (tclStubsPtr->tcl_NREvalObj) /* 584 */ +#define Tcl_NREvalObjv \ + (tclStubsPtr->tcl_NREvalObjv) /* 585 */ +#define Tcl_NRCmdSwap \ + (tclStubsPtr->tcl_NRCmdSwap) /* 586 */ +#define Tcl_NRAddCallback \ + (tclStubsPtr->tcl_NRAddCallback) /* 587 */ +#define Tcl_NRCallObjProc \ + (tclStubsPtr->tcl_NRCallObjProc) /* 588 */ +#define Tcl_GetFSDeviceFromStat \ + (tclStubsPtr->tcl_GetFSDeviceFromStat) /* 589 */ +#define Tcl_GetFSInodeFromStat \ + (tclStubsPtr->tcl_GetFSInodeFromStat) /* 590 */ +#define Tcl_GetModeFromStat \ + (tclStubsPtr->tcl_GetModeFromStat) /* 591 */ +#define Tcl_GetLinkCountFromStat \ + (tclStubsPtr->tcl_GetLinkCountFromStat) /* 592 */ +#define Tcl_GetUserIdFromStat \ + (tclStubsPtr->tcl_GetUserIdFromStat) /* 593 */ +#define Tcl_GetGroupIdFromStat \ + (tclStubsPtr->tcl_GetGroupIdFromStat) /* 594 */ +#define Tcl_GetDeviceTypeFromStat \ + (tclStubsPtr->tcl_GetDeviceTypeFromStat) /* 595 */ +#define Tcl_GetAccessTimeFromStat \ + (tclStubsPtr->tcl_GetAccessTimeFromStat) /* 596 */ +#define Tcl_GetModificationTimeFromStat \ + (tclStubsPtr->tcl_GetModificationTimeFromStat) /* 597 */ +#define Tcl_GetChangeTimeFromStat \ + (tclStubsPtr->tcl_GetChangeTimeFromStat) /* 598 */ +#define Tcl_GetSizeFromStat \ + (tclStubsPtr->tcl_GetSizeFromStat) /* 599 */ +#define Tcl_GetBlocksFromStat \ + (tclStubsPtr->tcl_GetBlocksFromStat) /* 600 */ +#define Tcl_GetBlockSizeFromStat \ + (tclStubsPtr->tcl_GetBlockSizeFromStat) /* 601 */ +#define Tcl_SetEnsembleParameterList \ + (tclStubsPtr->tcl_SetEnsembleParameterList) /* 602 */ +#define Tcl_GetEnsembleParameterList \ + (tclStubsPtr->tcl_GetEnsembleParameterList) /* 603 */ +#define Tcl_ParseArgsObjv \ + (tclStubsPtr->tcl_ParseArgsObjv) /* 604 */ +#define Tcl_GetErrorLine \ + (tclStubsPtr->tcl_GetErrorLine) /* 605 */ +#define Tcl_SetErrorLine \ + (tclStubsPtr->tcl_SetErrorLine) /* 606 */ +#define Tcl_TransferResult \ + (tclStubsPtr->tcl_TransferResult) /* 607 */ +#define Tcl_InterpActive \ + (tclStubsPtr->tcl_InterpActive) /* 608 */ +#define Tcl_BackgroundException \ + (tclStubsPtr->tcl_BackgroundException) /* 609 */ +#define Tcl_ZlibDeflate \ + (tclStubsPtr->tcl_ZlibDeflate) /* 610 */ +#define Tcl_ZlibInflate \ + (tclStubsPtr->tcl_ZlibInflate) /* 611 */ +#define Tcl_ZlibCRC32 \ + (tclStubsPtr->tcl_ZlibCRC32) /* 612 */ +#define Tcl_ZlibAdler32 \ + (tclStubsPtr->tcl_ZlibAdler32) /* 613 */ +#define Tcl_ZlibStreamInit \ + (tclStubsPtr->tcl_ZlibStreamInit) /* 614 */ +#define Tcl_ZlibStreamGetCommandName \ + (tclStubsPtr->tcl_ZlibStreamGetCommandName) /* 615 */ +#define Tcl_ZlibStreamEof \ + (tclStubsPtr->tcl_ZlibStreamEof) /* 616 */ +#define Tcl_ZlibStreamChecksum \ + (tclStubsPtr->tcl_ZlibStreamChecksum) /* 617 */ +#define Tcl_ZlibStreamPut \ + (tclStubsPtr->tcl_ZlibStreamPut) /* 618 */ +#define Tcl_ZlibStreamGet \ + (tclStubsPtr->tcl_ZlibStreamGet) /* 619 */ +#define Tcl_ZlibStreamClose \ + (tclStubsPtr->tcl_ZlibStreamClose) /* 620 */ +#define Tcl_ZlibStreamReset \ + (tclStubsPtr->tcl_ZlibStreamReset) /* 621 */ +#define Tcl_SetStartupScript \ + (tclStubsPtr->tcl_SetStartupScript) /* 622 */ +#define Tcl_GetStartupScript \ + (tclStubsPtr->tcl_GetStartupScript) /* 623 */ +#define Tcl_CloseEx \ + (tclStubsPtr->tcl_CloseEx) /* 624 */ +#define Tcl_NRExprObj \ + (tclStubsPtr->tcl_NRExprObj) /* 625 */ +#define Tcl_NRSubstObj \ + (tclStubsPtr->tcl_NRSubstObj) /* 626 */ +#define Tcl_LoadFile \ + (tclStubsPtr->tcl_LoadFile) /* 627 */ +#define Tcl_FindSymbol \ + (tclStubsPtr->tcl_FindSymbol) /* 628 */ +#define Tcl_FSUnloadFile \ + (tclStubsPtr->tcl_FSUnloadFile) /* 629 */ +#define Tcl_ZlibStreamSetCompressionDictionary \ + (tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */ + +#endif /* defined(USE_TCL_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#if defined(USE_TCL_STUBS) +# undef Tcl_CreateInterp +# undef Tcl_FindExecutable +# undef Tcl_GetStringResult +# undef Tcl_Init +# undef Tcl_SetPanicProc +# undef Tcl_SetVar +# undef Tcl_ObjSetVar2 +# undef Tcl_StaticPackage +# undef TclFSGetNativePath +# define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp()) +# define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp)) +# define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp)) +# define Tcl_SetPanicProc(proc) (tclStubsPtr->tcl_SetPanicProc(proc)) +# define Tcl_SetVar(interp, varName, newValue, flags) \ + (tclStubsPtr->tcl_SetVar(interp, varName, newValue, flags)) +# define Tcl_ObjSetVar2(interp, part1, part2, newValue, flags) \ + (tclStubsPtr->tcl_ObjSetVar2(interp, part1, part2, newValue, flags)) +#endif + +#if defined(_WIN32) && defined(UNICODE) +# define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg))) +# define Tcl_MainEx Tcl_MainExW + EXTERN void Tcl_MainExW(int argc, wchar_t **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#undef Tcl_SeekOld +#undef Tcl_TellOld + +#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_NewBooleanObj +#define Tcl_NewBooleanObj(boolValue) \ + Tcl_NewIntObj((boolValue)!=0) +#undef Tcl_DbNewBooleanObj +#define Tcl_DbNewBooleanObj(boolValue, file, line) \ + Tcl_DbNewLongObj((boolValue)!=0, file, line) +#undef Tcl_SetBooleanObj +#define Tcl_SetBooleanObj(objPtr, boolValue) \ + Tcl_SetIntObj((objPtr), (boolValue)!=0) +#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 */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tclPlatDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tclPlatDecls.h new file mode 100644 index 00000000..abc8ee81 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tclPlatDecls.h @@ -0,0 +1,122 @@ +/* + * tclPlatDecls.h -- + * + * Declarations of platform specific Tcl APIs. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * All rights reserved. + */ + +#ifndef _TCLPLATDECLS +#define _TCLPLATDECLS + +#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 + +/* + * 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. + */ + +/* + * 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. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +/* 0 */ +EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len, + Tcl_DString *dsPtr); +/* 1 */ +EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len, + Tcl_DString *dsPtr); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 0 */ +EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, + const char *bundleName, int hasResourceFile, + int maxPathLen, char *libraryPath); +/* 1 */ +EXTERN int Tcl_MacOSXOpenVersionedBundleResources( + Tcl_Interp *interp, const char *bundleName, + const char *bundleVersion, + int hasResourceFile, int maxPathLen, + char *libraryPath); +#endif /* MACOSX */ + +typedef struct TclPlatStubs { + int magic; + void *hooks; + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ + TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */ + char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */ +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 0 */ + int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */ +#endif /* MACOSX */ +} TclPlatStubs; + +extern const TclPlatStubs *tclPlatStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +#define Tcl_WinUtfToTChar \ + (tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */ +#define Tcl_WinTCharToUtf \ + (tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */ +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_MacOSXOpenBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ +#define Tcl_MacOSXOpenVersionedBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ +#endif /* MACOSX */ + +#endif /* defined(USE_TCL_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TCLPLATDECLS */ + + diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tk.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tk.h new file mode 100644 index 00000000..4a655a49 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tk.h @@ -0,0 +1,1619 @@ +/* + * tk.h -- + * + * Declarations for Tk-related things that are visible outside of the Tk + * module itself. + * + * Copyright (c) 1989-1994 The Regents of the University of California. + * Copyright (c) 1994 The Australian National University. + * Copyright (c) 1994-1998 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. + */ + +#ifndef _TK +#define _TK + +#include +#if (TCL_MAJOR_VERSION != 8) || (TCL_MINOR_VERSION < 6) +# error Tk 8.6 must be compiled with tcl.h from Tcl 8.6 or better +#endif + +#ifndef CONST84 +# define CONST84 const +# define CONST84_RETURN const +#endif +#ifndef CONST86 +# define CONST86 CONST84 +#endif +#ifndef EXTERN +# define EXTERN extern TCL_STORAGE_CLASS +#endif + +/* + * 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 + +/* + * For C++ compilers, use extern "C" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * When version numbers change here, you must also go into the following files + * and update the version numbers: + * + * library/tk.tcl (1 LOC patch) + * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch) + * win/configure.in (as above) + * README (sections 0 and 1) + * macosx/Tk-Common.xcconfig (not patchlevel) 1 LOC + * win/README (not patchlevel) + * unix/README (not patchlevel) + * unix/tk.spec (1 LOC patch) + * win/tcl.m4 (not patchlevel) + * + * You may also need to update some of these files when the numbers change for + * the version of Tcl that this release of Tk is compiled against. + */ + +#define TK_MAJOR_VERSION 8 +#define TK_MINOR_VERSION 6 +#define TK_RELEASE_LEVEL TCL_FINAL_RELEASE +#define TK_RELEASE_SERIAL 4 + +#define TK_VERSION "8.6" +#define TK_PATCH_LEVEL "8.6.4" + +/* + * A special definition used to allow this header file to be included from + * windows or mac resource files so that they can obtain version information. + * RC_INVOKED is defined by default by the windows RC tool and manually set + * for macintosh. + * + * Resource compilers don't like all the C stuff, like typedefs and procedure + * declarations, that occur below, so block them out. + */ + +#ifndef RC_INVOKED + +#ifndef _XLIB_H +# include +# ifdef MAC_OSX_TK +# include +# endif +#endif +#ifdef __STDC__ +# include +#endif + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +/* + *---------------------------------------------------------------------- + * + * Decide whether or not to use input methods. + */ + +#ifdef XNQueryInputStyle +#define TK_USE_INPUT_METHODS +#endif + +/* + * Dummy types that are used by clients: + */ + +typedef struct Tk_BindingTable_ *Tk_BindingTable; +typedef struct Tk_Canvas_ *Tk_Canvas; +typedef struct Tk_Cursor_ *Tk_Cursor; +typedef struct Tk_ErrorHandler_ *Tk_ErrorHandler; +typedef struct Tk_Font_ *Tk_Font; +typedef struct Tk_Image__ *Tk_Image; +typedef struct Tk_ImageMaster_ *Tk_ImageMaster; +typedef struct Tk_OptionTable_ *Tk_OptionTable; +typedef struct Tk_PostscriptInfo_ *Tk_PostscriptInfo; +typedef struct Tk_TextLayout_ *Tk_TextLayout; +typedef struct Tk_Window_ *Tk_Window; +typedef struct Tk_3DBorder_ *Tk_3DBorder; +typedef struct Tk_Style_ *Tk_Style; +typedef struct Tk_StyleEngine_ *Tk_StyleEngine; +typedef struct Tk_StyledElement_ *Tk_StyledElement; + +/* + * Additional types exported to clients. + */ + +typedef const char *Tk_Uid; + +/* + *---------------------------------------------------------------------- + * + * The enum below defines the valid types for Tk configuration options as + * implemented by Tk_InitOptions, Tk_SetOptions, etc. + */ + +typedef enum { + TK_OPTION_BOOLEAN, + TK_OPTION_INT, + TK_OPTION_DOUBLE, + TK_OPTION_STRING, + TK_OPTION_STRING_TABLE, + TK_OPTION_COLOR, + TK_OPTION_FONT, + TK_OPTION_BITMAP, + TK_OPTION_BORDER, + TK_OPTION_RELIEF, + TK_OPTION_CURSOR, + TK_OPTION_JUSTIFY, + TK_OPTION_ANCHOR, + TK_OPTION_SYNONYM, + TK_OPTION_PIXELS, + TK_OPTION_WINDOW, + TK_OPTION_END, + TK_OPTION_CUSTOM, + TK_OPTION_STYLE +} Tk_OptionType; + +/* + * Structures of the following type are used by widgets to specify their + * configuration options. Typically each widget has a static array of these + * structures, where each element of the array describes a single + * configuration option. The array is passed to Tk_CreateOptionTable. + */ + +typedef struct Tk_OptionSpec { + Tk_OptionType type; /* Type of option, such as TK_OPTION_COLOR; + * see definitions above. Last option in table + * must have type TK_OPTION_END. */ + const char *optionName; /* Name used to specify option in Tcl + * commands. */ + const char *dbName; /* Name for option in option database. */ + const char *dbClass; /* Class for option in database. */ + const char *defValue; /* Default value for option if not specified + * in command line, the option database, or + * the system. */ + int objOffset; /* Where in record to store a Tcl_Obj * that + * holds the value of this option, specified + * as an offset in bytes from the start of the + * record. Use the Tk_Offset macro to generate + * values for this. -1 means don't store the + * Tcl_Obj in the record. */ + int internalOffset; /* Where in record to store the internal + * representation of the value of this option, + * such as an int or XColor *. This field is + * specified as an offset in bytes from the + * start of the record. Use the Tk_Offset + * macro to generate values for it. -1 means + * don't store the internal representation in + * the record. */ + int flags; /* Any combination of the values defined + * below. */ + const void *clientData; /* An alternate place to put option-specific + * data. Used for the monochrome default value + * for colors, etc. */ + int typeMask; /* An arbitrary bit mask defined by the class + * manager; typically bits correspond to + * certain kinds of options such as all those + * that require a redisplay when they change. + * Tk_SetOptions returns the bit-wise OR of + * the typeMasks of all options that were + * changed. */ +} Tk_OptionSpec; + +/* + * Flag values for Tk_OptionSpec structures. These flags are shared by + * Tk_ConfigSpec structures, so be sure to coordinate any changes carefully. + */ + +#define TK_OPTION_NULL_OK (1 << 0) +#define TK_OPTION_DONT_SET_DEFAULT (1 << 3) + +/* + * The following structure and function types are used by TK_OPTION_CUSTOM + * options; the structure holds pointers to the functions needed by the Tk + * option config code to handle a custom option. + */ + +typedef int (Tk_CustomOptionSetProc) (ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *widgRec, + int offset, char *saveInternalPtr, int flags); +typedef Tcl_Obj *(Tk_CustomOptionGetProc) (ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset); +typedef void (Tk_CustomOptionRestoreProc) (ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *saveInternalPtr); +typedef void (Tk_CustomOptionFreeProc) (ClientData clientData, Tk_Window tkwin, + char *internalPtr); + +typedef struct Tk_ObjCustomOption { + const char *name; /* Name of the custom option. */ + Tk_CustomOptionSetProc *setProc; + /* Function to use to set a record's option + * value from a Tcl_Obj */ + Tk_CustomOptionGetProc *getProc; + /* Function to use to get a Tcl_Obj + * representation from an internal + * representation of an option. */ + Tk_CustomOptionRestoreProc *restoreProc; + /* Function to use to restore a saved value + * for the internal representation. */ + Tk_CustomOptionFreeProc *freeProc; + /* Function to use to free the internal + * representation of an option. */ + ClientData clientData; /* Arbitrary one-word value passed to the + * handling procs. */ +} Tk_ObjCustomOption; + +/* + * Macro to use to fill in "offset" fields of the Tk_OptionSpec structure. + * Computes number of bytes from beginning of structure to a given field. + */ + +#ifdef offsetof +#define Tk_Offset(type, field) ((int) offsetof(type, field)) +#else +#define Tk_Offset(type, field) ((int) ((char *) &((type *) 0)->field)) +#endif + +/* + * The following two structures are used for error handling. When config + * options are being modified, the old values are saved in a Tk_SavedOptions + * structure. If an error occurs, then the contents of the structure can be + * used to restore all of the old values. The contents of this structure are + * for the private use Tk. No-one outside Tk should ever read or write any of + * the fields of these structures. + */ + +typedef struct Tk_SavedOption { + struct TkOption *optionPtr; /* Points to information that describes the + * option. */ + Tcl_Obj *valuePtr; /* The old value of the option, in the form of + * a Tcl object; may be NULL if the value was + * not saved as an object. */ + double internalForm; /* The old value of the option, in some + * internal representation such as an int or + * (XColor *). Valid only if the field + * optionPtr->specPtr->objOffset is < 0. The + * space must be large enough to accommodate a + * double, a long, or a pointer; right now it + * looks like a double (i.e., 8 bytes) is big + * enough. Also, using a double guarantees + * that the field is properly aligned for + * storing large values. */ +} Tk_SavedOption; + +#ifdef TCL_MEM_DEBUG +# define TK_NUM_SAVED_OPTIONS 2 +#else +# define TK_NUM_SAVED_OPTIONS 20 +#endif + +typedef struct Tk_SavedOptions { + char *recordPtr; /* The data structure in which to restore + * configuration options. */ + Tk_Window tkwin; /* Window associated with recordPtr; needed to + * restore certain options. */ + int numItems; /* The number of valid items in items field. */ + Tk_SavedOption items[TK_NUM_SAVED_OPTIONS]; + /* Items used to hold old values. */ + struct Tk_SavedOptions *nextPtr; + /* Points to next structure in list; needed if + * too many options changed to hold all the + * old values in a single structure. NULL + * means no more structures. */ +} Tk_SavedOptions; + +/* + * Structure used to describe application-specific configuration options: + * indicates procedures to call to parse an option and to return a text string + * describing an option. THESE ARE DEPRECATED; PLEASE USE THE NEW STRUCTURES + * LISTED ABOVE. + */ + +/* + * This is a temporary flag used while tkObjConfig and new widgets are in + * development. + */ + +#ifndef __NO_OLD_CONFIG + +typedef int (Tk_OptionParseProc) (ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST84 char *value, char *widgRec, int offset); +typedef CONST86 char *(Tk_OptionPrintProc) (ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr); + +typedef struct Tk_CustomOption { + Tk_OptionParseProc *parseProc; + /* Procedure to call to parse an option and + * store it in converted form. */ + Tk_OptionPrintProc *printProc; + /* Procedure to return a printable string + * describing an existing option. */ + ClientData clientData; /* Arbitrary one-word value used by option + * parser: passed to parseProc and + * printProc. */ +} Tk_CustomOption; + +/* + * Structure used to specify information for Tk_ConfigureWidget. Each + * structure gives complete information for one option, including how the + * option is specified on the command line, where it appears in the option + * database, etc. + */ + +typedef struct Tk_ConfigSpec { + int type; /* Type of option, such as TK_CONFIG_COLOR; + * see definitions below. Last option in table + * must have type TK_CONFIG_END. */ + CONST86 char *argvName; /* Switch used to specify option in argv. NULL + * means this spec is part of a group. */ + Tk_Uid dbName; /* Name for option in option database. */ + Tk_Uid dbClass; /* Class for option in database. */ + Tk_Uid defValue; /* Default value for option if not specified + * in command line or database. */ + int offset; /* Where in widget record to store value; use + * Tk_Offset macro to generate values for + * this. */ + int specFlags; /* Any combination of the values defined + * below; other bits are used internally by + * tkConfig.c. */ + CONST86 Tk_CustomOption *customPtr; + /* If type is TK_CONFIG_CUSTOM then this is a + * pointer to info about how to parse and + * print the option. Otherwise it is + * irrelevant. */ +} Tk_ConfigSpec; + +/* + * Type values for Tk_ConfigSpec structures. See the user documentation for + * details. + */ + +typedef enum { + TK_CONFIG_BOOLEAN, TK_CONFIG_INT, TK_CONFIG_DOUBLE, TK_CONFIG_STRING, + TK_CONFIG_UID, TK_CONFIG_COLOR, TK_CONFIG_FONT, TK_CONFIG_BITMAP, + TK_CONFIG_BORDER, TK_CONFIG_RELIEF, TK_CONFIG_CURSOR, + TK_CONFIG_ACTIVE_CURSOR, TK_CONFIG_JUSTIFY, TK_CONFIG_ANCHOR, + TK_CONFIG_SYNONYM, TK_CONFIG_CAP_STYLE, TK_CONFIG_JOIN_STYLE, + TK_CONFIG_PIXELS, TK_CONFIG_MM, TK_CONFIG_WINDOW, TK_CONFIG_CUSTOM, + TK_CONFIG_END +} Tk_ConfigTypes; + +/* + * Possible values for flags argument to Tk_ConfigureWidget: + */ + +#define TK_CONFIG_ARGV_ONLY 1 +#define TK_CONFIG_OBJS 0x80 + +/* + * Possible flag values for Tk_ConfigSpec structures. Any bits at or above + * TK_CONFIG_USER_BIT may be used by clients for selecting certain entries. + * Before changing any values here, coordinate with tkOldConfig.c + * (internal-use-only flags are defined there). + */ + +#define TK_CONFIG_NULL_OK (1 << 0) +#define TK_CONFIG_COLOR_ONLY (1 << 1) +#define TK_CONFIG_MONO_ONLY (1 << 2) +#define TK_CONFIG_DONT_SET_DEFAULT (1 << 3) +#define TK_CONFIG_OPTION_SPECIFIED (1 << 4) +#define TK_CONFIG_USER_BIT 0x100 +#endif /* __NO_OLD_CONFIG */ + +/* + * Structure used to specify how to handle argv options. + */ + +typedef struct { + CONST86 char *key; /* The key string that flags the option in the + * argv array. */ + int type; /* Indicates option type; see below. */ + char *src; /* Value to be used in setting dst; usage + * depends on type. */ + char *dst; /* Address of value to be modified; usage + * depends on type. */ + CONST86 char *help; /* Documentation message describing this + * option. */ +} Tk_ArgvInfo; + +/* + * Legal values for the type field of a Tk_ArgvInfo: see the user + * documentation for details. + */ + +#define TK_ARGV_CONSTANT 15 +#define TK_ARGV_INT 16 +#define TK_ARGV_STRING 17 +#define TK_ARGV_UID 18 +#define TK_ARGV_REST 19 +#define TK_ARGV_FLOAT 20 +#define TK_ARGV_FUNC 21 +#define TK_ARGV_GENFUNC 22 +#define TK_ARGV_HELP 23 +#define TK_ARGV_CONST_OPTION 24 +#define TK_ARGV_OPTION_VALUE 25 +#define TK_ARGV_OPTION_NAME_VALUE 26 +#define TK_ARGV_END 27 + +/* + * Flag bits for passing to Tk_ParseArgv: + */ + +#define TK_ARGV_NO_DEFAULTS 0x1 +#define TK_ARGV_NO_LEFTOVERS 0x2 +#define TK_ARGV_NO_ABBREV 0x4 +#define TK_ARGV_DONT_SKIP_FIRST_ARG 0x8 + +/* + * Enumerated type for describing actions to be taken in response to a + * restrictProc established by Tk_RestrictEvents. + */ + +typedef enum { + TK_DEFER_EVENT, TK_PROCESS_EVENT, TK_DISCARD_EVENT +} Tk_RestrictAction; + +/* + * Priority levels to pass to Tk_AddOption: + */ + +#define TK_WIDGET_DEFAULT_PRIO 20 +#define TK_STARTUP_FILE_PRIO 40 +#define TK_USER_DEFAULT_PRIO 60 +#define TK_INTERACTIVE_PRIO 80 +#define TK_MAX_PRIO 100 + +/* + * Relief values returned by Tk_GetRelief: + */ + +#define TK_RELIEF_NULL -1 +#define TK_RELIEF_FLAT 0 +#define TK_RELIEF_GROOVE 1 +#define TK_RELIEF_RAISED 2 +#define TK_RELIEF_RIDGE 3 +#define TK_RELIEF_SOLID 4 +#define TK_RELIEF_SUNKEN 5 + +/* + * "Which" argument values for Tk_3DBorderGC: + */ + +#define TK_3D_FLAT_GC 1 +#define TK_3D_LIGHT_GC 2 +#define TK_3D_DARK_GC 3 + +/* + * Special EnterNotify/LeaveNotify "mode" for use in events generated by + * tkShare.c. Pick a high enough value that it's unlikely to conflict with + * existing values (like NotifyNormal) or any new values defined in the + * future. + */ + +#define TK_NOTIFY_SHARE 20 + +/* + * Enumerated type for describing a point by which to anchor something: + */ + +typedef enum { + TK_ANCHOR_N, TK_ANCHOR_NE, TK_ANCHOR_E, TK_ANCHOR_SE, + TK_ANCHOR_S, TK_ANCHOR_SW, TK_ANCHOR_W, TK_ANCHOR_NW, + TK_ANCHOR_CENTER +} Tk_Anchor; + +/* + * Enumerated type for describing a style of justification: + */ + +typedef enum { + TK_JUSTIFY_LEFT, TK_JUSTIFY_RIGHT, TK_JUSTIFY_CENTER +} Tk_Justify; + +/* + * The following structure is used by Tk_GetFontMetrics() to return + * information about the properties of a Tk_Font. + */ + +typedef struct Tk_FontMetrics { + int ascent; /* The amount in pixels that the tallest + * letter sticks up above the baseline, plus + * any extra blank space added by the designer + * of the font. */ + int descent; /* The largest amount in pixels that any + * letter sticks below the baseline, plus any + * extra blank space added by the designer of + * the font. */ + int linespace; /* The sum of the ascent and descent. How far + * apart two lines of text in the same font + * should be placed so that none of the + * characters in one line overlap any of the + * characters in the other line. */ +} Tk_FontMetrics; + +/* + * Flags passed to Tk_MeasureChars: + */ + +#define TK_WHOLE_WORDS 1 +#define TK_AT_LEAST_ONE 2 +#define TK_PARTIAL_OK 4 + +/* + * Flags passed to Tk_ComputeTextLayout: + */ + +#define TK_IGNORE_TABS 8 +#define TK_IGNORE_NEWLINES 16 + +/* + * Widget class procedures used to implement platform specific widget + * behavior. + */ + +typedef Window (Tk_ClassCreateProc) (Tk_Window tkwin, Window parent, + ClientData instanceData); +typedef void (Tk_ClassWorldChangedProc) (ClientData instanceData); +typedef void (Tk_ClassModalProc) (Tk_Window tkwin, XEvent *eventPtr); + +typedef struct Tk_ClassProcs { + unsigned int size; + Tk_ClassWorldChangedProc *worldChangedProc; + /* Procedure to invoke when the widget needs + * to respond in some way to a change in the + * world (font changes, etc.) */ + Tk_ClassCreateProc *createProc; + /* Procedure to invoke when the platform- + * dependent window needs to be created. */ + Tk_ClassModalProc *modalProc; + /* Procedure to invoke after all bindings on a + * widget have been triggered in order to + * handle a modal loop. */ +} Tk_ClassProcs; + +/* + * Simple accessor for Tk_ClassProcs structure. Checks that the structure is + * not NULL, then checks the size field and returns either the requested + * field, if present, or NULL if the structure is too small to have the field + * (or NULL if the structure is NULL). + * + * A more general version of this function may be useful if other + * size-versioned structure pop up in the future: + * + * #define Tk_GetField(name, who, which) \ + * (((who) == NULL) ? NULL : + * (((who)->size <= Tk_Offset(name, which)) ? NULL :(name)->which)) + */ + +#define Tk_GetClassProc(procs, which) \ + (((procs) == NULL) ? NULL : \ + (((procs)->size <= Tk_Offset(Tk_ClassProcs, which)) ? NULL:(procs)->which)) + +/* + * Each geometry manager (the packer, the placer, etc.) is represented by a + * structure of the following form, which indicates procedures to invoke in + * the geometry manager to carry out certain functions. + */ + +typedef void (Tk_GeomRequestProc) (ClientData clientData, Tk_Window tkwin); +typedef void (Tk_GeomLostSlaveProc) (ClientData clientData, Tk_Window tkwin); + +typedef struct Tk_GeomMgr { + const char *name; /* Name of the geometry manager (command used + * to invoke it, or name of widget class that + * allows embedded widgets). */ + Tk_GeomRequestProc *requestProc; + /* Procedure to invoke when a slave's + * requested geometry changes. */ + Tk_GeomLostSlaveProc *lostSlaveProc; + /* Procedure to invoke when a slave is taken + * away from one geometry manager by another. + * NULL means geometry manager doesn't care + * when slaves are lost. */ +} Tk_GeomMgr; + +/* + * Result values returned by Tk_GetScrollInfo: + */ + +#define TK_SCROLL_MOVETO 1 +#define TK_SCROLL_PAGES 2 +#define TK_SCROLL_UNITS 3 +#define TK_SCROLL_ERROR 4 + +/* + *---------------------------------------------------------------------- + * + * Extensions to the X event set + * + *---------------------------------------------------------------------- + */ + +#define VirtualEvent (MappingNotify + 1) +#define ActivateNotify (MappingNotify + 2) +#define DeactivateNotify (MappingNotify + 3) +#define MouseWheelEvent (MappingNotify + 4) +#define TK_LASTEVENT (MappingNotify + 5) + +#define MouseWheelMask (1L << 28) +#define ActivateMask (1L << 29) +#define VirtualEventMask (1L << 30) + +/* + * A virtual event shares most of its fields with the XKeyEvent and + * XButtonEvent structures. 99% of the time a virtual event will be an + * abstraction of a key or button event, so this structure provides the most + * information to the user. The only difference is the changing of the detail + * field for a virtual event so that it holds the name of the virtual event + * being triggered. + * + * When using this structure, you should ensure that you zero out all the + * fields first using memset() or bzero(). + */ + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server. */ + Bool send_event; /* True if this came from a SendEvent + * request. */ + Display *display; /* Display the event was read from. */ + Window event; /* Window on which event was requested. */ + Window root; /* Root window that the event occured on. */ + Window subwindow; /* Child window. */ + Time time; /* Milliseconds. */ + int x, y; /* Pointer x, y coordinates in event + * window. */ + int x_root, y_root; /* Coordinates relative to root. */ + unsigned int state; /* Key or button mask */ + Tk_Uid name; /* Name of virtual event. */ + Bool same_screen; /* Same screen flag. */ + Tcl_Obj *user_data; /* Application-specific data reference; Tk + * will decrement the reference count *once* + * when it has finished processing the + * event. */ +} XVirtualEvent; + +typedef struct { + int type; + unsigned long serial; /* # of last request processed by server. */ + Bool send_event; /* True if this came from a SendEvent + * request. */ + Display *display; /* Display the event was read from. */ + Window window; /* Window in which event occurred. */ +} XActivateDeactivateEvent; +typedef XActivateDeactivateEvent XActivateEvent; +typedef XActivateDeactivateEvent XDeactivateEvent; + +/* + *---------------------------------------------------------------------- + * + * Macros for querying Tk_Window structures. See the manual entries for + * documentation. + * + *---------------------------------------------------------------------- + */ + +#define Tk_Display(tkwin) (((Tk_FakeWin *) (tkwin))->display) +#define Tk_ScreenNumber(tkwin) (((Tk_FakeWin *) (tkwin))->screenNum) +#define Tk_Screen(tkwin) \ + (ScreenOfDisplay(Tk_Display(tkwin), Tk_ScreenNumber(tkwin))) +#define Tk_Depth(tkwin) (((Tk_FakeWin *) (tkwin))->depth) +#define Tk_Visual(tkwin) (((Tk_FakeWin *) (tkwin))->visual) +#define Tk_WindowId(tkwin) (((Tk_FakeWin *) (tkwin))->window) +#define Tk_PathName(tkwin) (((Tk_FakeWin *) (tkwin))->pathName) +#define Tk_Name(tkwin) (((Tk_FakeWin *) (tkwin))->nameUid) +#define Tk_Class(tkwin) (((Tk_FakeWin *) (tkwin))->classUid) +#define Tk_X(tkwin) (((Tk_FakeWin *) (tkwin))->changes.x) +#define Tk_Y(tkwin) (((Tk_FakeWin *) (tkwin))->changes.y) +#define Tk_Width(tkwin) (((Tk_FakeWin *) (tkwin))->changes.width) +#define Tk_Height(tkwin) \ + (((Tk_FakeWin *) (tkwin))->changes.height) +#define Tk_Changes(tkwin) (&((Tk_FakeWin *) (tkwin))->changes) +#define Tk_Attributes(tkwin) (&((Tk_FakeWin *) (tkwin))->atts) +#define Tk_IsEmbedded(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_EMBEDDED) +#define Tk_IsContainer(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_CONTAINER) +#define Tk_IsMapped(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_MAPPED) +#define Tk_IsTopLevel(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) +#define Tk_HasWrapper(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_HAS_WRAPPER) +#define Tk_WinManaged(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_WIN_MANAGED) +#define Tk_TopWinHierarchy(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_HIERARCHY) +#define Tk_IsManageable(tkwin) \ + (((Tk_FakeWin *) (tkwin))->flags & TK_WM_MANAGEABLE) +#define Tk_ReqWidth(tkwin) (((Tk_FakeWin *) (tkwin))->reqWidth) +#define Tk_ReqHeight(tkwin) (((Tk_FakeWin *) (tkwin))->reqHeight) +/* Tk_InternalBorderWidth is deprecated */ +#define Tk_InternalBorderWidth(tkwin) \ + (((Tk_FakeWin *) (tkwin))->internalBorderLeft) +#define Tk_InternalBorderLeft(tkwin) \ + (((Tk_FakeWin *) (tkwin))->internalBorderLeft) +#define Tk_InternalBorderRight(tkwin) \ + (((Tk_FakeWin *) (tkwin))->internalBorderRight) +#define Tk_InternalBorderTop(tkwin) \ + (((Tk_FakeWin *) (tkwin))->internalBorderTop) +#define Tk_InternalBorderBottom(tkwin) \ + (((Tk_FakeWin *) (tkwin))->internalBorderBottom) +#define Tk_MinReqWidth(tkwin) (((Tk_FakeWin *) (tkwin))->minReqWidth) +#define Tk_MinReqHeight(tkwin) (((Tk_FakeWin *) (tkwin))->minReqHeight) +#define Tk_Parent(tkwin) (((Tk_FakeWin *) (tkwin))->parentPtr) +#define Tk_Colormap(tkwin) (((Tk_FakeWin *) (tkwin))->atts.colormap) + +/* + * The structure below is needed by the macros above so that they can access + * the fields of a Tk_Window. The fields not needed by the macros are declared + * as "dummyX". The structure has its own type in order to prevent apps from + * accessing Tk_Window fields except using official macros. WARNING!! The + * structure definition must be kept consistent with the TkWindow structure in + * tkInt.h. If you change one, then change the other. See the declaration in + * tkInt.h for documentation on what the fields are used for internally. + */ + +typedef struct Tk_FakeWin { + Display *display; + char *dummy1; /* dispPtr */ + int screenNum; + Visual *visual; + int depth; + Window window; + char *dummy2; /* childList */ + char *dummy3; /* lastChildPtr */ + Tk_Window parentPtr; /* parentPtr */ + char *dummy4; /* nextPtr */ + char *dummy5; /* mainPtr */ + char *pathName; + Tk_Uid nameUid; + Tk_Uid classUid; + XWindowChanges changes; + unsigned int dummy6; /* dirtyChanges */ + XSetWindowAttributes atts; + unsigned long dummy7; /* dirtyAtts */ + unsigned int flags; + char *dummy8; /* handlerList */ +#ifdef TK_USE_INPUT_METHODS + XIC dummy9; /* inputContext */ +#endif /* TK_USE_INPUT_METHODS */ + ClientData *dummy10; /* tagPtr */ + int dummy11; /* numTags */ + int dummy12; /* optionLevel */ + char *dummy13; /* selHandlerList */ + char *dummy14; /* geomMgrPtr */ + ClientData dummy15; /* geomData */ + int reqWidth, reqHeight; + int internalBorderLeft; + char *dummy16; /* wmInfoPtr */ + char *dummy17; /* classProcPtr */ + ClientData dummy18; /* instanceData */ + char *dummy19; /* privatePtr */ + int internalBorderRight; + int internalBorderTop; + int internalBorderBottom; + int minReqWidth; + int minReqHeight; + char *dummy20; /* geometryMaster */ +} Tk_FakeWin; + +/* + * Flag values for TkWindow (and Tk_FakeWin) structures are: + * + * TK_MAPPED: 1 means window is currently mapped, + * 0 means unmapped. + * TK_TOP_LEVEL: 1 means this is a top-level widget. + * TK_ALREADY_DEAD: 1 means the window is in the process of + * being destroyed already. + * TK_NEED_CONFIG_NOTIFY: 1 means that the window has been reconfigured + * before it was made to exist. At the time of + * making it exist a ConfigureNotify event needs + * to be generated. + * TK_GRAB_FLAG: Used to manage grabs. See tkGrab.c for details + * TK_CHECKED_IC: 1 means we've already tried to get an input + * context for this window; if the ic field is + * NULL it means that there isn't a context for + * the field. + * TK_DONT_DESTROY_WINDOW: 1 means that Tk_DestroyWindow should not + * invoke XDestroyWindow to destroy this widget's + * X window. The flag is set when the window has + * already been destroyed elsewhere (e.g. by + * another application) or when it will be + * destroyed later (e.g. by destroying its parent) + * TK_WM_COLORMAP_WINDOW: 1 means that this window has at some time + * appeared in the WM_COLORMAP_WINDOWS property + * for its toplevel, so we have to remove it from + * that property if the window is deleted and the + * toplevel isn't. + * TK_EMBEDDED: 1 means that this window (which must be a + * toplevel) is not a free-standing window but + * rather is embedded in some other application. + * TK_CONTAINER: 1 means that this window is a container, and + * that some other application (either in this + * process or elsewhere) may be embedding itself + * inside the window. + * TK_BOTH_HALVES: 1 means that this window is used for + * application embedding (either as container or + * embedded application), and both the containing + * and embedded halves are associated with + * windows in this particular process. + * TK_WRAPPER: 1 means that this window is the extra wrapper + * window created around a toplevel to hold the + * menubar under Unix. See tkUnixWm.c for more + * information. + * TK_REPARENTED: 1 means that this window has been reparented + * so that as far as the window system is + * concerned it isn't a child of its Tk parent. + * Initially this is used only for special Unix + * menubar windows. + * TK_ANONYMOUS_WINDOW: 1 means that this window has no name, and is + * thus not accessible from Tk. + * TK_HAS_WRAPPER 1 means that this window has a wrapper window + * TK_WIN_MANAGED 1 means that this window is a child of the root + * window, and is managed by the window manager. + * TK_TOP_HIERARCHY 1 means this window is at the top of a physical + * window hierarchy within this process, i.e. the + * window's parent either doesn't exist or is not + * owned by this Tk application. + * TK_PROP_PROPCHANGE 1 means that PropertyNotify events in the + * window's children should propagate up to this + * window. + * TK_WM_MANAGEABLE 1 marks a window as capable of being converted + * into a toplevel using [wm manage]. + */ + +#define TK_MAPPED 1 +#define TK_TOP_LEVEL 2 +#define TK_ALREADY_DEAD 4 +#define TK_NEED_CONFIG_NOTIFY 8 +#define TK_GRAB_FLAG 0x10 +#define TK_CHECKED_IC 0x20 +#define TK_DONT_DESTROY_WINDOW 0x40 +#define TK_WM_COLORMAP_WINDOW 0x80 +#define TK_EMBEDDED 0x100 +#define TK_CONTAINER 0x200 +#define TK_BOTH_HALVES 0x400 +#define TK_WRAPPER 0x1000 +#define TK_REPARENTED 0x2000 +#define TK_ANONYMOUS_WINDOW 0x4000 +#define TK_HAS_WRAPPER 0x8000 +#define TK_WIN_MANAGED 0x10000 +#define TK_TOP_HIERARCHY 0x20000 +#define TK_PROP_PROPCHANGE 0x40000 +#define TK_WM_MANAGEABLE 0x80000 + +/* + *---------------------------------------------------------------------- + * + * Procedure prototypes and structures used for defining new canvas items: + * + *---------------------------------------------------------------------- + */ + +typedef enum { + TK_STATE_NULL = -1, TK_STATE_ACTIVE, TK_STATE_DISABLED, + TK_STATE_NORMAL, TK_STATE_HIDDEN +} Tk_State; + +typedef struct Tk_SmoothMethod { + CONST86 char *name; + int (*coordProc) (Tk_Canvas canvas, double *pointPtr, int numPoints, + int numSteps, XPoint xPoints[], double dblPoints[]); + void (*postscriptProc) (Tcl_Interp *interp, Tk_Canvas canvas, + double *coordPtr, int numPoints, int numSteps); +} Tk_SmoothMethod; + +/* + * For each item in a canvas widget there exists one record with the following + * structure. Each actual item is represented by a record with the following + * stuff at its beginning, plus additional type-specific stuff after that. + */ + +#define TK_TAG_SPACE 3 + +typedef struct Tk_Item { + int id; /* Unique identifier for this item (also + * serves as first tag for item). */ + struct Tk_Item *nextPtr; /* Next in display list of all items in this + * canvas. Later items in list are drawn on + * top of earlier ones. */ + Tk_Uid staticTagSpace[TK_TAG_SPACE]; + /* Built-in space for limited # of tags. */ + Tk_Uid *tagPtr; /* Pointer to array of tags. Usually points to + * staticTagSpace, but may point to malloc-ed + * space if there are lots of tags. */ + int tagSpace; /* Total amount of tag space available at + * tagPtr. */ + int numTags; /* Number of tag slots actually used at + * *tagPtr. */ + struct Tk_ItemType *typePtr;/* Table of procedures that implement this + * type of item. */ + int x1, y1, x2, y2; /* Bounding box for item, in integer canvas + * units. Set by item-specific code and + * guaranteed to contain every pixel drawn in + * item. Item area includes x1 and y1 but not + * x2 and y2. */ + struct Tk_Item *prevPtr; /* Previous in display list of all items in + * this canvas. Later items in list are drawn + * just below earlier ones. */ + Tk_State state; /* State of item. */ + char *reserved1; /* reserved for future use */ + int redraw_flags; /* Some flags used in the canvas */ + + /* + *------------------------------------------------------------------ + * Starting here is additional type-specific stuff; see the declarations + * for individual types to see what is part of each type. The actual space + * below is determined by the "itemInfoSize" of the type's Tk_ItemType + * record. + *------------------------------------------------------------------ + */ +} Tk_Item; + +/* + * Flag bits for canvases (redraw_flags): + * + * TK_ITEM_STATE_DEPENDANT - 1 means that object needs to be redrawn if the + * canvas state changes. + * TK_ITEM_DONT_REDRAW - 1 means that the object redraw is already been + * prepared, so the general canvas code doesn't + * need to do that any more. + */ + +#define TK_ITEM_STATE_DEPENDANT 1 +#define TK_ITEM_DONT_REDRAW 2 + +/* + * Records of the following type are used to describe a type of item (e.g. + * lines, circles, etc.) that can form part of a canvas widget. + */ + +#ifdef USE_OLD_CANVAS +typedef int (Tk_ItemCreateProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int argc, char **argv); +typedef int (Tk_ItemConfigureProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int argc, char **argv, int flags); +typedef int (Tk_ItemCoordProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int argc, char **argv); +#else +typedef int (Tk_ItemCreateProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int argc, Tcl_Obj *const objv[]); +typedef int (Tk_ItemConfigureProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int argc, Tcl_Obj *const objv[], + int flags); +typedef int (Tk_ItemCoordProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int argc, Tcl_Obj *const argv[]); +#endif /* USE_OLD_CANVAS */ +typedef void (Tk_ItemDeleteProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + Display *display); +typedef void (Tk_ItemDisplayProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + Display *display, Drawable dst, int x, int y, int width, + int height); +typedef double (Tk_ItemPointProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + double *pointPtr); +typedef int (Tk_ItemAreaProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + double *rectPtr); +typedef int (Tk_ItemPostscriptProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, int prepass); +typedef void (Tk_ItemScaleProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + double originX, double originY, double scaleX, + double scaleY); +typedef void (Tk_ItemTranslateProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + double deltaX, double deltaY); +#ifdef USE_OLD_CANVAS +typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, char *indexString, int *indexPtr); +#else +typedef int (Tk_ItemIndexProc)(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Item *itemPtr, Tcl_Obj *indexString, int *indexPtr); +#endif /* USE_OLD_CANVAS */ +typedef void (Tk_ItemCursorProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int index); +typedef int (Tk_ItemSelectionProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int offset, char *buffer, int maxBytes); +#ifdef USE_OLD_CANVAS +typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int beforeThis, char *string); +#else +typedef void (Tk_ItemInsertProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int beforeThis, Tcl_Obj *string); +#endif /* USE_OLD_CANVAS */ +typedef void (Tk_ItemDCharsProc)(Tk_Canvas canvas, Tk_Item *itemPtr, + int first, int last); + +#ifndef __NO_OLD_CONFIG + +typedef struct Tk_ItemType { + CONST86 char *name; /* The name of this type of item, such as + * "line". */ + int itemSize; /* Total amount of space needed for item's + * record. */ + Tk_ItemCreateProc *createProc; + /* Procedure to create a new item of this + * type. */ + CONST86 Tk_ConfigSpec *configSpecs; /* Pointer to array of configuration specs for + * this type. Used for returning configuration + * info. */ + Tk_ItemConfigureProc *configProc; + /* Procedure to call to change configuration + * options. */ + Tk_ItemCoordProc *coordProc;/* Procedure to call to get and set the item's + * coordinates. */ + Tk_ItemDeleteProc *deleteProc; + /* Procedure to delete existing item of this + * type. */ + Tk_ItemDisplayProc *displayProc; + /* Procedure to display items of this type. */ + int alwaysRedraw; /* Non-zero means displayProc should be called + * even when the item has been moved + * off-screen. */ + Tk_ItemPointProc *pointProc;/* Computes distance from item to a given + * point. */ + Tk_ItemAreaProc *areaProc; /* Computes whether item is inside, outside, + * or overlapping an area. */ + Tk_ItemPostscriptProc *postscriptProc; + /* Procedure to write a Postscript description + * for items of this type. */ + Tk_ItemScaleProc *scaleProc;/* Procedure to rescale items of this type. */ + Tk_ItemTranslateProc *translateProc; + /* Procedure to translate items of this + * type. */ + Tk_ItemIndexProc *indexProc;/* Procedure to determine index of indicated + * character. NULL if item doesn't support + * indexing. */ + Tk_ItemCursorProc *icursorProc; + /* Procedure to set insert cursor posn to just + * before a given position. */ + Tk_ItemSelectionProc *selectionProc; + /* Procedure to return selection (in STRING + * format) when it is in this item. */ + Tk_ItemInsertProc *insertProc; + /* Procedure to insert something into an + * item. */ + Tk_ItemDCharsProc *dCharsProc; + /* Procedure to delete characters from an + * item. */ + struct Tk_ItemType *nextPtr;/* Used to link types together into a list. */ + char *reserved1; /* Reserved for future extension. */ + int reserved2; /* Carefully compatible with */ + char *reserved3; /* Jan Nijtmans dash patch */ + char *reserved4; +} Tk_ItemType; + +/* + * Flag (used in the alwaysRedraw field) to say whether an item supports + * point-level manipulation like the line and polygon items. + */ + +#define TK_MOVABLE_POINTS 2 + +#endif /* __NO_OLD_CONFIG */ + +/* + * The following structure provides information about the selection and the + * insertion cursor. It is needed by only a few items, such as those that + * display text. It is shared by the generic canvas code and the item-specific + * code, but most of the fields should be written only by the canvas generic + * code. + */ + +typedef struct Tk_CanvasTextInfo { + Tk_3DBorder selBorder; /* Border and background for selected + * characters. Read-only to items.*/ + int selBorderWidth; /* Width of border around selection. Read-only + * to items. */ + XColor *selFgColorPtr; /* Foreground color for selected text. + * Read-only to items. */ + Tk_Item *selItemPtr; /* Pointer to selected item. NULL means + * selection isn't in this canvas. Writable by + * items. */ + int selectFirst; /* Character index of first selected + * character. Writable by items. */ + int selectLast; /* Character index of last selected character. + * Writable by items. */ + Tk_Item *anchorItemPtr; /* Item corresponding to "selectAnchor": not + * necessarily selItemPtr. Read-only to + * items. */ + int selectAnchor; /* Character index of fixed end of selection + * (i.e. "select to" operation will use this + * as one end of the selection). Writable by + * items. */ + Tk_3DBorder insertBorder; /* Used to draw vertical bar for insertion + * cursor. Read-only to items. */ + int insertWidth; /* Total width of insertion cursor. Read-only + * to items. */ + int insertBorderWidth; /* Width of 3-D border around insert cursor. + * Read-only to items. */ + Tk_Item *focusItemPtr; /* Item that currently has the input focus, or + * NULL if no such item. Read-only to items. */ + int gotFocus; /* Non-zero means that the canvas widget has + * the input focus. Read-only to items.*/ + int cursorOn; /* Non-zero means that an insertion cursor + * should be displayed in focusItemPtr. + * Read-only to items.*/ +} Tk_CanvasTextInfo; + +/* + * Structures used for Dashing and Outline. + */ + +typedef struct Tk_Dash { + int number; + union { + char *pt; + char array[sizeof(char *)]; + } pattern; +} Tk_Dash; + +typedef struct Tk_TSOffset { + int flags; /* Flags; see below for possible values */ + int xoffset; /* x offset */ + int yoffset; /* y offset */ +} Tk_TSOffset; + +/* + * Bit fields in Tk_Offset->flags: + */ + +#define TK_OFFSET_INDEX 1 +#define TK_OFFSET_RELATIVE 2 +#define TK_OFFSET_LEFT 4 +#define TK_OFFSET_CENTER 8 +#define TK_OFFSET_RIGHT 16 +#define TK_OFFSET_TOP 32 +#define TK_OFFSET_MIDDLE 64 +#define TK_OFFSET_BOTTOM 128 + +typedef struct Tk_Outline { + GC gc; /* Graphics context. */ + double width; /* Width of outline. */ + double activeWidth; /* Width of outline. */ + double disabledWidth; /* Width of outline. */ + int offset; /* Dash offset. */ + Tk_Dash dash; /* Dash pattern. */ + Tk_Dash activeDash; /* Dash pattern if state is active. */ + Tk_Dash disabledDash; /* Dash pattern if state is disabled. */ + void *reserved1; /* Reserved for future expansion. */ + void *reserved2; + void *reserved3; + Tk_TSOffset tsoffset; /* Stipple offset for outline. */ + XColor *color; /* Outline color. */ + XColor *activeColor; /* Outline color if state is active. */ + XColor *disabledColor; /* Outline color if state is disabled. */ + Pixmap stipple; /* Outline Stipple pattern. */ + Pixmap activeStipple; /* Outline Stipple pattern if state is + * active. */ + Pixmap disabledStipple; /* Outline Stipple pattern if state is + * disabled. */ +} Tk_Outline; + +/* + *---------------------------------------------------------------------- + * + * Procedure prototypes and structures used for managing images: + * + *---------------------------------------------------------------------- + */ + +typedef struct Tk_ImageType Tk_ImageType; +#ifdef USE_OLD_IMAGE +typedef int (Tk_ImageCreateProc) (Tcl_Interp *interp, char *name, int argc, + char **argv, Tk_ImageType *typePtr, Tk_ImageMaster master, + ClientData *masterDataPtr); +#else +typedef int (Tk_ImageCreateProc) (Tcl_Interp *interp, CONST86 char *name, int objc, + Tcl_Obj *const objv[], CONST86 Tk_ImageType *typePtr, Tk_ImageMaster master, + ClientData *masterDataPtr); +#endif /* USE_OLD_IMAGE */ +typedef ClientData (Tk_ImageGetProc) (Tk_Window tkwin, ClientData masterData); +typedef void (Tk_ImageDisplayProc) (ClientData instanceData, Display *display, + Drawable drawable, int imageX, int imageY, int width, int height, + int drawableX, int drawableY); +typedef void (Tk_ImageFreeProc) (ClientData instanceData, Display *display); +typedef void (Tk_ImageDeleteProc) (ClientData masterData); +typedef void (Tk_ImageChangedProc) (ClientData clientData, int x, int y, + int width, int height, int imageWidth, int imageHeight); +typedef int (Tk_ImagePostscriptProc) (ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psinfo, + int x, int y, int width, int height, int prepass); + +/* + * The following structure represents a particular type of image (bitmap, xpm + * image, etc.). It provides information common to all images of that type, + * such as the type name and a collection of procedures in the image manager + * that respond to various events. Each image manager is represented by one of + * these structures. + */ + +struct Tk_ImageType { + CONST86 char *name; /* Name of image type. */ + Tk_ImageCreateProc *createProc; + /* Procedure to call to create a new image of + * this type. */ + Tk_ImageGetProc *getProc; /* Procedure to call the first time + * Tk_GetImage is called in a new way (new + * visual or screen). */ + Tk_ImageDisplayProc *displayProc; + /* Call to draw image, in response to + * Tk_RedrawImage calls. */ + Tk_ImageFreeProc *freeProc; /* Procedure to call whenever Tk_FreeImage is + * called to release an instance of an + * image. */ + Tk_ImageDeleteProc *deleteProc; + /* Procedure to call to delete image. It will + * not be called until after freeProc has been + * called for each instance of the image. */ + Tk_ImagePostscriptProc *postscriptProc; + /* Procedure to call to produce postscript + * output for the image. */ + struct Tk_ImageType *nextPtr; + /* Next in list of all image types currently + * known. Filled in by Tk, not by image + * manager. */ + char *reserved; /* reserved for future expansion */ +}; + +/* + *---------------------------------------------------------------------- + * + * Additional definitions used to manage images of type "photo". + * + *---------------------------------------------------------------------- + */ + +/* + * The following type is used to identify a particular photo image to be + * manipulated: + */ + +typedef void *Tk_PhotoHandle; + +/* + * The following structure describes a block of pixels in memory: + */ + +typedef struct Tk_PhotoImageBlock { + unsigned char *pixelPtr; /* Pointer to the first pixel. */ + int width; /* Width of block, in pixels. */ + int height; /* Height of block, in pixels. */ + int pitch; /* Address difference between corresponding + * pixels in successive lines. */ + int pixelSize; /* Address difference between successive + * pixels in the same line. */ + int offset[4]; /* Address differences between the red, green, + * blue and alpha components of the pixel and + * the pixel as a whole. */ +} Tk_PhotoImageBlock; + +/* + * The following values control how blocks are combined into photo images when + * the alpha component of a pixel is not 255, a.k.a. the compositing rule. + */ + +#define TK_PHOTO_COMPOSITE_OVERLAY 0 +#define TK_PHOTO_COMPOSITE_SET 1 + +/* + * Procedure prototypes and structures used in reading and writing photo + * images: + */ + +typedef struct Tk_PhotoImageFormat Tk_PhotoImageFormat; +#ifdef USE_OLD_IMAGE +typedef int (Tk_ImageFileMatchProc) (Tcl_Channel chan, char *fileName, + char *formatString, int *widthPtr, int *heightPtr); +typedef int (Tk_ImageStringMatchProc) (char *string, char *formatString, + int *widthPtr, int *heightPtr); +typedef int (Tk_ImageFileReadProc) (Tcl_Interp *interp, Tcl_Channel chan, + char *fileName, char *formatString, Tk_PhotoHandle imageHandle, + int destX, int destY, int width, int height, int srcX, int srcY); +typedef int (Tk_ImageStringReadProc) (Tcl_Interp *interp, char *string, + char *formatString, Tk_PhotoHandle imageHandle, int destX, int destY, + int width, int height, int srcX, int srcY); +typedef int (Tk_ImageFileWriteProc) (Tcl_Interp *interp, char *fileName, + char *formatString, Tk_PhotoImageBlock *blockPtr); +typedef int (Tk_ImageStringWriteProc) (Tcl_Interp *interp, + Tcl_DString *dataPtr, char *formatString, Tk_PhotoImageBlock *blockPtr); +#else +typedef int (Tk_ImageFileMatchProc) (Tcl_Channel chan, const char *fileName, + Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp); +typedef int (Tk_ImageStringMatchProc) (Tcl_Obj *dataObj, Tcl_Obj *format, + int *widthPtr, int *heightPtr, Tcl_Interp *interp); +typedef int (Tk_ImageFileReadProc) (Tcl_Interp *interp, Tcl_Channel chan, + const char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, + int destX, int destY, int width, int height, int srcX, int srcY); +typedef int (Tk_ImageStringReadProc) (Tcl_Interp *interp, Tcl_Obj *dataObj, + Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, + int width, int height, int srcX, int srcY); +typedef int (Tk_ImageFileWriteProc) (Tcl_Interp *interp, const char *fileName, + Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr); +typedef int (Tk_ImageStringWriteProc) (Tcl_Interp *interp, Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr); +#endif /* USE_OLD_IMAGE */ + +/* + * The following structure represents a particular file format for storing + * images (e.g., PPM, GIF, JPEG, etc.). It provides information to allow image + * files of that format to be recognized and read into a photo image. + */ + +struct Tk_PhotoImageFormat { + CONST86 char *name; /* Name of image file format */ + Tk_ImageFileMatchProc *fileMatchProc; + /* Procedure to call to determine whether an + * image file matches this format. */ + Tk_ImageStringMatchProc *stringMatchProc; + /* Procedure to call to determine whether the + * data in a string matches this format. */ + Tk_ImageFileReadProc *fileReadProc; + /* Procedure to call to read data from an + * image file into a photo image. */ + Tk_ImageStringReadProc *stringReadProc; + /* Procedure to call to read data from a + * string into a photo image. */ + Tk_ImageFileWriteProc *fileWriteProc; + /* Procedure to call to write data from a + * photo image to a file. */ + Tk_ImageStringWriteProc *stringWriteProc; + /* Procedure to call to obtain a string + * representation of the data in a photo + * image.*/ + struct Tk_PhotoImageFormat *nextPtr; + /* Next in list of all photo image formats + * currently known. Filled in by Tk, not by + * image format handler. */ +}; + +/* + *---------------------------------------------------------------------- + * + * Procedure prototypes and structures used for managing styles: + * + *---------------------------------------------------------------------- + */ + +/* + * Style support version tag. + */ + +#define TK_STYLE_VERSION_1 0x1 +#define TK_STYLE_VERSION TK_STYLE_VERSION_1 + +/* + * The following structures and prototypes are used as static templates to + * declare widget elements. + */ + +typedef void (Tk_GetElementSizeProc) (ClientData clientData, char *recordPtr, + const Tk_OptionSpec **optionsPtr, Tk_Window tkwin, int width, + int height, int inner, int *widthPtr, int *heightPtr); +typedef void (Tk_GetElementBoxProc) (ClientData clientData, char *recordPtr, + const Tk_OptionSpec **optionsPtr, Tk_Window tkwin, int x, int y, + int width, int height, int inner, int *xPtr, int *yPtr, int *widthPtr, + int *heightPtr); +typedef int (Tk_GetElementBorderWidthProc) (ClientData clientData, + char *recordPtr, const Tk_OptionSpec **optionsPtr, Tk_Window tkwin); +typedef void (Tk_DrawElementProc) (ClientData clientData, char *recordPtr, + const Tk_OptionSpec **optionsPtr, Tk_Window tkwin, Drawable d, int x, + int y, int width, int height, int state); + +typedef struct Tk_ElementOptionSpec { + char *name; /* Name of the required option. */ + Tk_OptionType type; /* Accepted option type. TK_OPTION_END means + * any. */ +} Tk_ElementOptionSpec; + +typedef struct Tk_ElementSpec { + int version; /* Version of the style support. */ + char *name; /* Name of element. */ + Tk_ElementOptionSpec *options; + /* List of required options. Last one's name + * must be NULL. */ + Tk_GetElementSizeProc *getSize; + /* Compute the external (resp. internal) size + * of the element from its desired internal + * (resp. external) size. */ + Tk_GetElementBoxProc *getBox; + /* Compute the inscribed or bounding boxes + * within a given area. */ + Tk_GetElementBorderWidthProc *getBorderWidth; + /* Return the element's internal border width. + * Mostly useful for widgets. */ + Tk_DrawElementProc *draw; /* Draw the element in the given bounding + * box. */ +} Tk_ElementSpec; + +/* + * Element state flags. Can be OR'ed. + */ + +#define TK_ELEMENT_STATE_ACTIVE 1<<0 +#define TK_ELEMENT_STATE_DISABLED 1<<1 +#define TK_ELEMENT_STATE_FOCUS 1<<2 +#define TK_ELEMENT_STATE_PRESSED 1<<3 + +/* + *---------------------------------------------------------------------- + * + * The definitions below provide backward compatibility for functions and + * types related to event handling that used to be in Tk but have moved to + * Tcl. + * + *---------------------------------------------------------------------- + */ + +#define TK_READABLE TCL_READABLE +#define TK_WRITABLE TCL_WRITABLE +#define TK_EXCEPTION TCL_EXCEPTION + +#define TK_DONT_WAIT TCL_DONT_WAIT +#define TK_X_EVENTS TCL_WINDOW_EVENTS +#define TK_WINDOW_EVENTS TCL_WINDOW_EVENTS +#define TK_FILE_EVENTS TCL_FILE_EVENTS +#define TK_TIMER_EVENTS TCL_TIMER_EVENTS +#define TK_IDLE_EVENTS TCL_IDLE_EVENTS +#define TK_ALL_EVENTS TCL_ALL_EVENTS + +#define Tk_IdleProc Tcl_IdleProc +#define Tk_FileProc Tcl_FileProc +#define Tk_TimerProc Tcl_TimerProc +#define Tk_TimerToken Tcl_TimerToken + +#define Tk_BackgroundError Tcl_BackgroundError +#define Tk_CancelIdleCall Tcl_CancelIdleCall +#define Tk_CreateFileHandler Tcl_CreateFileHandler +#define Tk_CreateTimerHandler Tcl_CreateTimerHandler +#define Tk_DeleteFileHandler Tcl_DeleteFileHandler +#define Tk_DeleteTimerHandler Tcl_DeleteTimerHandler +#define Tk_DoOneEvent Tcl_DoOneEvent +#define Tk_DoWhenIdle Tcl_DoWhenIdle +#define Tk_Sleep Tcl_Sleep + +/* Additional stuff that has moved to Tcl: */ + +#define Tk_EventuallyFree Tcl_EventuallyFree +#define Tk_FreeProc Tcl_FreeProc +#define Tk_Preserve Tcl_Preserve +#define Tk_Release Tcl_Release + +/* Removed Tk_Main, use macro instead */ +#if defined(_WIN32) || defined(__CYGWIN__) +#define Tk_Main(argc, argv, proc) Tk_MainEx(argc, argv, proc, \ + (Tcl_FindExecutable(0), (Tcl_CreateInterp)())) +#else +#define Tk_Main(argc, argv, proc) Tk_MainEx(argc, argv, proc, \ + (Tcl_FindExecutable(argv[0]), (Tcl_CreateInterp)())) +#endif +const char * Tk_InitStubs(Tcl_Interp *interp, const char *version, + int exact); +EXTERN const char * Tk_PkgInitStubsCheck(Tcl_Interp *interp, + const char *version, int exact); + +#ifndef USE_TK_STUBS +#define Tk_InitStubs(interp, version, exact) \ + Tk_PkgInitStubsCheck(interp, version, exact) +#endif /* USE_TK_STUBS */ + +#define Tk_InitImageArgs(interp, argc, argv) /**/ + +/* + *---------------------------------------------------------------------- + * + * Additional procedure types defined by Tk. + * + *---------------------------------------------------------------------- + */ + +typedef int (Tk_ErrorProc) (ClientData clientData, XErrorEvent *errEventPtr); +typedef void (Tk_EventProc) (ClientData clientData, XEvent *eventPtr); +typedef int (Tk_GenericProc) (ClientData clientData, XEvent *eventPtr); +typedef int (Tk_ClientMessageProc) (Tk_Window tkwin, XEvent *eventPtr); +typedef int (Tk_GetSelProc) (ClientData clientData, Tcl_Interp *interp, + CONST86 char *portion); +typedef void (Tk_LostSelProc) (ClientData clientData); +typedef Tk_RestrictAction (Tk_RestrictProc) (ClientData clientData, + XEvent *eventPtr); +typedef int (Tk_SelectionProc) (ClientData clientData, int offset, + char *buffer, int maxBytes); + +/* + *---------------------------------------------------------------------- + * + * Platform independent exported procedures and variables. + * + *---------------------------------------------------------------------- + */ + +#include "tkDecls.h" + +#ifdef USE_OLD_IMAGE +#undef Tk_CreateImageType +#define Tk_CreateImageType Tk_CreateOldImageType +#undef Tk_CreatePhotoImageFormat +#define Tk_CreatePhotoImageFormat Tk_CreateOldPhotoImageFormat +#endif /* USE_OLD_IMAGE */ + +/* + *---------------------------------------------------------------------- + * + * Allow users to say that they don't want to alter their source to add extra + * arguments to Tk_PhotoPutBlock() et al; DO NOT DEFINE THIS WHEN BUILDING TK. + * + * This goes after the inclusion of the stubbed-decls so that the declarations + * of what is actually there can be correct. + */ + +#ifdef USE_COMPOSITELESS_PHOTO_PUT_BLOCK +# ifdef Tk_PhotoPutBlock +# undef Tk_PhotoPutBlock +# endif +# define Tk_PhotoPutBlock Tk_PhotoPutBlock_NoComposite +# ifdef Tk_PhotoPutZoomedBlock +# undef Tk_PhotoPutZoomedBlock +# endif +# define Tk_PhotoPutZoomedBlock Tk_PhotoPutZoomedBlock_NoComposite +# define USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#else /* !USE_COMPOSITELESS_PHOTO_PUT_BLOCK */ +# ifdef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +# ifdef Tk_PhotoPutBlock +# undef Tk_PhotoPutBlock +# endif +# define Tk_PhotoPutBlock Tk_PhotoPutBlock_Panic +# ifdef Tk_PhotoPutZoomedBlock +# undef Tk_PhotoPutZoomedBlock +# endif +# define Tk_PhotoPutZoomedBlock Tk_PhotoPutZoomedBlock_Panic +# endif /* USE_PANIC_ON_PHOTO_ALLOC_FAILURE */ +#endif /* USE_COMPOSITELESS_PHOTO_PUT_BLOCK */ +#ifdef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +# ifdef Tk_PhotoExpand +# undef Tk_PhotoExpand +# endif +# define Tk_PhotoExpand Tk_PhotoExpand_Panic +# ifdef Tk_PhotoSetSize +# undef Tk_PhotoSetSize +# endif +# define Tk_PhotoSetSize Tk_PhotoSetSize_Panic +#endif /* USE_PANIC_ON_PHOTO_ALLOC_FAILURE */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* RC_INVOKED */ + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TK */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tkDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tkDecls.h new file mode 100644 index 00000000..64c32cd2 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tkDecls.h @@ -0,0 +1,1733 @@ +/* + * tkDecls.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 _TKDECLS +#define _TKDECLS + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#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/tk.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +/* 0 */ +EXTERN void Tk_MainLoop(void); +/* 1 */ +EXTERN XColor * Tk_3DBorderColor(Tk_3DBorder border); +/* 2 */ +EXTERN GC Tk_3DBorderGC(Tk_Window tkwin, Tk_3DBorder border, + int which); +/* 3 */ +EXTERN void Tk_3DHorizontalBevel(Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, int leftIn, + int rightIn, int topBevel, int relief); +/* 4 */ +EXTERN void Tk_3DVerticalBevel(Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, int leftBevel, + int relief); +/* 5 */ +EXTERN void Tk_AddOption(Tk_Window tkwin, const char *name, + const char *value, int priority); +/* 6 */ +EXTERN void Tk_BindEvent(Tk_BindingTable bindingTable, + XEvent *eventPtr, Tk_Window tkwin, + int numObjects, ClientData *objectPtr); +/* 7 */ +EXTERN void Tk_CanvasDrawableCoords(Tk_Canvas canvas, double x, + double y, short *drawableXPtr, + short *drawableYPtr); +/* 8 */ +EXTERN void Tk_CanvasEventuallyRedraw(Tk_Canvas canvas, int x1, + int y1, int x2, int y2); +/* 9 */ +EXTERN int Tk_CanvasGetCoord(Tcl_Interp *interp, + Tk_Canvas canvas, const char *str, + double *doublePtr); +/* 10 */ +EXTERN Tk_CanvasTextInfo * Tk_CanvasGetTextInfo(Tk_Canvas canvas); +/* 11 */ +EXTERN int Tk_CanvasPsBitmap(Tcl_Interp *interp, + Tk_Canvas canvas, Pixmap bitmap, int x, + int y, int width, int height); +/* 12 */ +EXTERN int Tk_CanvasPsColor(Tcl_Interp *interp, + Tk_Canvas canvas, XColor *colorPtr); +/* 13 */ +EXTERN int Tk_CanvasPsFont(Tcl_Interp *interp, Tk_Canvas canvas, + Tk_Font font); +/* 14 */ +EXTERN void Tk_CanvasPsPath(Tcl_Interp *interp, Tk_Canvas canvas, + double *coordPtr, int numPoints); +/* 15 */ +EXTERN int Tk_CanvasPsStipple(Tcl_Interp *interp, + Tk_Canvas canvas, Pixmap bitmap); +/* 16 */ +EXTERN double Tk_CanvasPsY(Tk_Canvas canvas, double y); +/* 17 */ +EXTERN void Tk_CanvasSetStippleOrigin(Tk_Canvas canvas, GC gc); +/* 18 */ +EXTERN int Tk_CanvasTagsParseProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + const char *value, char *widgRec, int offset); +/* 19 */ +EXTERN CONST86 char * Tk_CanvasTagsPrintProc(ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr); +/* 20 */ +EXTERN Tk_Window Tk_CanvasTkwin(Tk_Canvas canvas); +/* 21 */ +EXTERN void Tk_CanvasWindowCoords(Tk_Canvas canvas, double x, + double y, short *screenXPtr, + short *screenYPtr); +/* 22 */ +EXTERN void Tk_ChangeWindowAttributes(Tk_Window tkwin, + unsigned long valueMask, + XSetWindowAttributes *attsPtr); +/* 23 */ +EXTERN int Tk_CharBbox(Tk_TextLayout layout, int index, + int *xPtr, int *yPtr, int *widthPtr, + int *heightPtr); +/* 24 */ +EXTERN void Tk_ClearSelection(Tk_Window tkwin, Atom selection); +/* 25 */ +EXTERN int Tk_ClipboardAppend(Tcl_Interp *interp, + Tk_Window tkwin, Atom target, Atom format, + const char *buffer); +/* 26 */ +EXTERN int Tk_ClipboardClear(Tcl_Interp *interp, + Tk_Window tkwin); +/* 27 */ +EXTERN int Tk_ConfigureInfo(Tcl_Interp *interp, Tk_Window tkwin, + const Tk_ConfigSpec *specs, char *widgRec, + const char *argvName, int flags); +/* 28 */ +EXTERN int Tk_ConfigureValue(Tcl_Interp *interp, + Tk_Window tkwin, const Tk_ConfigSpec *specs, + char *widgRec, const char *argvName, + int flags); +/* 29 */ +EXTERN int Tk_ConfigureWidget(Tcl_Interp *interp, + Tk_Window tkwin, const Tk_ConfigSpec *specs, + int argc, CONST84 char **argv, char *widgRec, + int flags); +/* 30 */ +EXTERN void Tk_ConfigureWindow(Tk_Window tkwin, + unsigned int valueMask, + XWindowChanges *valuePtr); +/* 31 */ +EXTERN Tk_TextLayout Tk_ComputeTextLayout(Tk_Font font, const char *str, + int numChars, int wrapLength, + Tk_Justify justify, int flags, int *widthPtr, + int *heightPtr); +/* 32 */ +EXTERN Tk_Window Tk_CoordsToWindow(int rootX, int rootY, + Tk_Window tkwin); +/* 33 */ +EXTERN unsigned long Tk_CreateBinding(Tcl_Interp *interp, + Tk_BindingTable bindingTable, + ClientData object, const char *eventStr, + const char *script, int append); +/* 34 */ +EXTERN Tk_BindingTable Tk_CreateBindingTable(Tcl_Interp *interp); +/* 35 */ +EXTERN Tk_ErrorHandler Tk_CreateErrorHandler(Display *display, int errNum, + int request, int minorCode, + Tk_ErrorProc *errorProc, + ClientData clientData); +/* 36 */ +EXTERN void Tk_CreateEventHandler(Tk_Window token, + unsigned long mask, Tk_EventProc *proc, + ClientData clientData); +/* 37 */ +EXTERN void Tk_CreateGenericHandler(Tk_GenericProc *proc, + ClientData clientData); +/* 38 */ +EXTERN void Tk_CreateImageType(const Tk_ImageType *typePtr); +/* 39 */ +EXTERN void Tk_CreateItemType(Tk_ItemType *typePtr); +/* 40 */ +EXTERN void Tk_CreatePhotoImageFormat( + const Tk_PhotoImageFormat *formatPtr); +/* 41 */ +EXTERN void Tk_CreateSelHandler(Tk_Window tkwin, Atom selection, + Atom target, Tk_SelectionProc *proc, + ClientData clientData, Atom format); +/* 42 */ +EXTERN Tk_Window Tk_CreateWindow(Tcl_Interp *interp, Tk_Window parent, + const char *name, const char *screenName); +/* 43 */ +EXTERN Tk_Window Tk_CreateWindowFromPath(Tcl_Interp *interp, + Tk_Window tkwin, const char *pathName, + const char *screenName); +/* 44 */ +EXTERN int Tk_DefineBitmap(Tcl_Interp *interp, const char *name, + const void *source, int width, int height); +/* 45 */ +EXTERN void Tk_DefineCursor(Tk_Window window, Tk_Cursor cursor); +/* 46 */ +EXTERN void Tk_DeleteAllBindings(Tk_BindingTable bindingTable, + ClientData object); +/* 47 */ +EXTERN int Tk_DeleteBinding(Tcl_Interp *interp, + Tk_BindingTable bindingTable, + ClientData object, const char *eventStr); +/* 48 */ +EXTERN void Tk_DeleteBindingTable(Tk_BindingTable bindingTable); +/* 49 */ +EXTERN void Tk_DeleteErrorHandler(Tk_ErrorHandler handler); +/* 50 */ +EXTERN void Tk_DeleteEventHandler(Tk_Window token, + unsigned long mask, Tk_EventProc *proc, + ClientData clientData); +/* 51 */ +EXTERN void Tk_DeleteGenericHandler(Tk_GenericProc *proc, + ClientData clientData); +/* 52 */ +EXTERN void Tk_DeleteImage(Tcl_Interp *interp, const char *name); +/* 53 */ +EXTERN void Tk_DeleteSelHandler(Tk_Window tkwin, Atom selection, + Atom target); +/* 54 */ +EXTERN void Tk_DestroyWindow(Tk_Window tkwin); +/* 55 */ +EXTERN CONST84_RETURN char * Tk_DisplayName(Tk_Window tkwin); +/* 56 */ +EXTERN int Tk_DistanceToTextLayout(Tk_TextLayout layout, int x, + int y); +/* 57 */ +EXTERN void Tk_Draw3DPolygon(Tk_Window tkwin, Drawable drawable, + Tk_3DBorder border, XPoint *pointPtr, + int numPoints, int borderWidth, + int leftRelief); +/* 58 */ +EXTERN void Tk_Draw3DRectangle(Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, + int borderWidth, int relief); +/* 59 */ +EXTERN void Tk_DrawChars(Display *display, Drawable drawable, + GC gc, Tk_Font tkfont, const char *source, + int numBytes, int x, int y); +/* 60 */ +EXTERN void Tk_DrawFocusHighlight(Tk_Window tkwin, GC gc, + int width, Drawable drawable); +/* 61 */ +EXTERN void Tk_DrawTextLayout(Display *display, + Drawable drawable, GC gc, + Tk_TextLayout layout, int x, int y, + int firstChar, int lastChar); +/* 62 */ +EXTERN void Tk_Fill3DPolygon(Tk_Window tkwin, Drawable drawable, + Tk_3DBorder border, XPoint *pointPtr, + int numPoints, int borderWidth, + int leftRelief); +/* 63 */ +EXTERN void Tk_Fill3DRectangle(Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, + int borderWidth, int relief); +/* 64 */ +EXTERN Tk_PhotoHandle Tk_FindPhoto(Tcl_Interp *interp, + const char *imageName); +/* 65 */ +EXTERN Font Tk_FontId(Tk_Font font); +/* 66 */ +EXTERN void Tk_Free3DBorder(Tk_3DBorder border); +/* 67 */ +EXTERN void Tk_FreeBitmap(Display *display, Pixmap bitmap); +/* 68 */ +EXTERN void Tk_FreeColor(XColor *colorPtr); +/* 69 */ +EXTERN void Tk_FreeColormap(Display *display, Colormap colormap); +/* 70 */ +EXTERN void Tk_FreeCursor(Display *display, Tk_Cursor cursor); +/* 71 */ +EXTERN void Tk_FreeFont(Tk_Font f); +/* 72 */ +EXTERN void Tk_FreeGC(Display *display, GC gc); +/* 73 */ +EXTERN void Tk_FreeImage(Tk_Image image); +/* 74 */ +EXTERN void Tk_FreeOptions(const Tk_ConfigSpec *specs, + char *widgRec, Display *display, + int needFlags); +/* 75 */ +EXTERN void Tk_FreePixmap(Display *display, Pixmap pixmap); +/* 76 */ +EXTERN void Tk_FreeTextLayout(Tk_TextLayout textLayout); +/* 77 */ +EXTERN void Tk_FreeXId(Display *display, XID xid); +/* 78 */ +EXTERN GC Tk_GCForColor(XColor *colorPtr, Drawable drawable); +/* 79 */ +EXTERN void Tk_GeometryRequest(Tk_Window tkwin, int reqWidth, + int reqHeight); +/* 80 */ +EXTERN Tk_3DBorder Tk_Get3DBorder(Tcl_Interp *interp, Tk_Window tkwin, + Tk_Uid colorName); +/* 81 */ +EXTERN void Tk_GetAllBindings(Tcl_Interp *interp, + Tk_BindingTable bindingTable, + ClientData object); +/* 82 */ +EXTERN int Tk_GetAnchor(Tcl_Interp *interp, const char *str, + Tk_Anchor *anchorPtr); +/* 83 */ +EXTERN CONST84_RETURN char * Tk_GetAtomName(Tk_Window tkwin, Atom atom); +/* 84 */ +EXTERN CONST84_RETURN char * Tk_GetBinding(Tcl_Interp *interp, + Tk_BindingTable bindingTable, + ClientData object, const char *eventStr); +/* 85 */ +EXTERN Pixmap Tk_GetBitmap(Tcl_Interp *interp, Tk_Window tkwin, + const char *str); +/* 86 */ +EXTERN Pixmap Tk_GetBitmapFromData(Tcl_Interp *interp, + Tk_Window tkwin, const void *source, + int width, int height); +/* 87 */ +EXTERN int Tk_GetCapStyle(Tcl_Interp *interp, const char *str, + int *capPtr); +/* 88 */ +EXTERN XColor * Tk_GetColor(Tcl_Interp *interp, Tk_Window tkwin, + Tk_Uid name); +/* 89 */ +EXTERN XColor * Tk_GetColorByValue(Tk_Window tkwin, XColor *colorPtr); +/* 90 */ +EXTERN Colormap Tk_GetColormap(Tcl_Interp *interp, Tk_Window tkwin, + const char *str); +/* 91 */ +EXTERN Tk_Cursor Tk_GetCursor(Tcl_Interp *interp, Tk_Window tkwin, + Tk_Uid str); +/* 92 */ +EXTERN Tk_Cursor Tk_GetCursorFromData(Tcl_Interp *interp, + Tk_Window tkwin, const char *source, + const char *mask, int width, int height, + int xHot, int yHot, Tk_Uid fg, Tk_Uid bg); +/* 93 */ +EXTERN Tk_Font Tk_GetFont(Tcl_Interp *interp, Tk_Window tkwin, + const char *str); +/* 94 */ +EXTERN Tk_Font Tk_GetFontFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +/* 95 */ +EXTERN void Tk_GetFontMetrics(Tk_Font font, + Tk_FontMetrics *fmPtr); +/* 96 */ +EXTERN GC Tk_GetGC(Tk_Window tkwin, unsigned long valueMask, + XGCValues *valuePtr); +/* 97 */ +EXTERN Tk_Image Tk_GetImage(Tcl_Interp *interp, Tk_Window tkwin, + const char *name, + Tk_ImageChangedProc *changeProc, + ClientData clientData); +/* 98 */ +EXTERN ClientData Tk_GetImageMasterData(Tcl_Interp *interp, + const char *name, + CONST86 Tk_ImageType **typePtrPtr); +/* 99 */ +EXTERN Tk_ItemType * Tk_GetItemTypes(void); +/* 100 */ +EXTERN int Tk_GetJoinStyle(Tcl_Interp *interp, const char *str, + int *joinPtr); +/* 101 */ +EXTERN int Tk_GetJustify(Tcl_Interp *interp, const char *str, + Tk_Justify *justifyPtr); +/* 102 */ +EXTERN int Tk_GetNumMainWindows(void); +/* 103 */ +EXTERN Tk_Uid Tk_GetOption(Tk_Window tkwin, const char *name, + const char *className); +/* 104 */ +EXTERN int Tk_GetPixels(Tcl_Interp *interp, Tk_Window tkwin, + const char *str, int *intPtr); +/* 105 */ +EXTERN Pixmap Tk_GetPixmap(Display *display, Drawable d, int width, + int height, int depth); +/* 106 */ +EXTERN int Tk_GetRelief(Tcl_Interp *interp, const char *name, + int *reliefPtr); +/* 107 */ +EXTERN void Tk_GetRootCoords(Tk_Window tkwin, int *xPtr, + int *yPtr); +/* 108 */ +EXTERN int Tk_GetScrollInfo(Tcl_Interp *interp, int argc, + CONST84 char **argv, double *dblPtr, + int *intPtr); +/* 109 */ +EXTERN int Tk_GetScreenMM(Tcl_Interp *interp, Tk_Window tkwin, + const char *str, double *doublePtr); +/* 110 */ +EXTERN int Tk_GetSelection(Tcl_Interp *interp, Tk_Window tkwin, + Atom selection, Atom target, + Tk_GetSelProc *proc, ClientData clientData); +/* 111 */ +EXTERN Tk_Uid Tk_GetUid(const char *str); +/* 112 */ +EXTERN Visual * Tk_GetVisual(Tcl_Interp *interp, Tk_Window tkwin, + const char *str, int *depthPtr, + Colormap *colormapPtr); +/* 113 */ +EXTERN void Tk_GetVRootGeometry(Tk_Window tkwin, int *xPtr, + int *yPtr, int *widthPtr, int *heightPtr); +/* 114 */ +EXTERN int Tk_Grab(Tcl_Interp *interp, Tk_Window tkwin, + int grabGlobal); +/* 115 */ +EXTERN void Tk_HandleEvent(XEvent *eventPtr); +/* 116 */ +EXTERN Tk_Window Tk_IdToWindow(Display *display, Window window); +/* 117 */ +EXTERN void Tk_ImageChanged(Tk_ImageMaster master, int x, int y, + int width, int height, int imageWidth, + int imageHeight); +/* 118 */ +EXTERN int Tk_Init(Tcl_Interp *interp); +/* 119 */ +EXTERN Atom Tk_InternAtom(Tk_Window tkwin, const char *name); +/* 120 */ +EXTERN int Tk_IntersectTextLayout(Tk_TextLayout layout, int x, + int y, int width, int height); +/* 121 */ +EXTERN void Tk_MaintainGeometry(Tk_Window slave, + Tk_Window master, int x, int y, int width, + int height); +/* 122 */ +EXTERN Tk_Window Tk_MainWindow(Tcl_Interp *interp); +/* 123 */ +EXTERN void Tk_MakeWindowExist(Tk_Window tkwin); +/* 124 */ +EXTERN void Tk_ManageGeometry(Tk_Window tkwin, + const Tk_GeomMgr *mgrPtr, + ClientData clientData); +/* 125 */ +EXTERN void Tk_MapWindow(Tk_Window tkwin); +/* 126 */ +EXTERN int Tk_MeasureChars(Tk_Font tkfont, const char *source, + int numBytes, int maxPixels, int flags, + int *lengthPtr); +/* 127 */ +EXTERN void Tk_MoveResizeWindow(Tk_Window tkwin, int x, int y, + int width, int height); +/* 128 */ +EXTERN void Tk_MoveWindow(Tk_Window tkwin, int x, int y); +/* 129 */ +EXTERN void Tk_MoveToplevelWindow(Tk_Window tkwin, int x, int y); +/* 130 */ +EXTERN CONST84_RETURN char * Tk_NameOf3DBorder(Tk_3DBorder border); +/* 131 */ +EXTERN CONST84_RETURN char * Tk_NameOfAnchor(Tk_Anchor anchor); +/* 132 */ +EXTERN CONST84_RETURN char * Tk_NameOfBitmap(Display *display, Pixmap bitmap); +/* 133 */ +EXTERN CONST84_RETURN char * Tk_NameOfCapStyle(int cap); +/* 134 */ +EXTERN CONST84_RETURN char * Tk_NameOfColor(XColor *colorPtr); +/* 135 */ +EXTERN CONST84_RETURN char * Tk_NameOfCursor(Display *display, + Tk_Cursor cursor); +/* 136 */ +EXTERN CONST84_RETURN char * Tk_NameOfFont(Tk_Font font); +/* 137 */ +EXTERN CONST84_RETURN char * Tk_NameOfImage(Tk_ImageMaster imageMaster); +/* 138 */ +EXTERN CONST84_RETURN char * Tk_NameOfJoinStyle(int join); +/* 139 */ +EXTERN CONST84_RETURN char * Tk_NameOfJustify(Tk_Justify justify); +/* 140 */ +EXTERN CONST84_RETURN char * Tk_NameOfRelief(int relief); +/* 141 */ +EXTERN Tk_Window Tk_NameToWindow(Tcl_Interp *interp, + const char *pathName, Tk_Window tkwin); +/* 142 */ +EXTERN void Tk_OwnSelection(Tk_Window tkwin, Atom selection, + Tk_LostSelProc *proc, ClientData clientData); +/* 143 */ +EXTERN int Tk_ParseArgv(Tcl_Interp *interp, Tk_Window tkwin, + int *argcPtr, CONST84 char **argv, + const Tk_ArgvInfo *argTable, int flags); +/* 144 */ +EXTERN void Tk_PhotoPutBlock_NoComposite(Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height); +/* 145 */ +EXTERN void Tk_PhotoPutZoomedBlock_NoComposite( + Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int zoomX, int zoomY, + int subsampleX, int subsampleY); +/* 146 */ +EXTERN int Tk_PhotoGetImage(Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr); +/* 147 */ +EXTERN void Tk_PhotoBlank(Tk_PhotoHandle handle); +/* 148 */ +EXTERN void Tk_PhotoExpand_Panic(Tk_PhotoHandle handle, + int width, int height); +/* 149 */ +EXTERN void Tk_PhotoGetSize(Tk_PhotoHandle handle, int *widthPtr, + int *heightPtr); +/* 150 */ +EXTERN void Tk_PhotoSetSize_Panic(Tk_PhotoHandle handle, + int width, int height); +/* 151 */ +EXTERN int Tk_PointToChar(Tk_TextLayout layout, int x, int y); +/* 152 */ +EXTERN int Tk_PostscriptFontName(Tk_Font tkfont, + Tcl_DString *dsPtr); +/* 153 */ +EXTERN void Tk_PreserveColormap(Display *display, + Colormap colormap); +/* 154 */ +EXTERN void Tk_QueueWindowEvent(XEvent *eventPtr, + Tcl_QueuePosition position); +/* 155 */ +EXTERN void Tk_RedrawImage(Tk_Image image, int imageX, + int imageY, int width, int height, + Drawable drawable, int drawableX, + int drawableY); +/* 156 */ +EXTERN void Tk_ResizeWindow(Tk_Window tkwin, int width, + int height); +/* 157 */ +EXTERN int Tk_RestackWindow(Tk_Window tkwin, int aboveBelow, + Tk_Window other); +/* 158 */ +EXTERN Tk_RestrictProc * Tk_RestrictEvents(Tk_RestrictProc *proc, + ClientData arg, ClientData *prevArgPtr); +/* 159 */ +EXTERN int Tk_SafeInit(Tcl_Interp *interp); +/* 160 */ +EXTERN const char * Tk_SetAppName(Tk_Window tkwin, const char *name); +/* 161 */ +EXTERN void Tk_SetBackgroundFromBorder(Tk_Window tkwin, + Tk_3DBorder border); +/* 162 */ +EXTERN void Tk_SetClass(Tk_Window tkwin, const char *className); +/* 163 */ +EXTERN void Tk_SetGrid(Tk_Window tkwin, int reqWidth, + int reqHeight, int gridWidth, int gridHeight); +/* 164 */ +EXTERN void Tk_SetInternalBorder(Tk_Window tkwin, int width); +/* 165 */ +EXTERN void Tk_SetWindowBackground(Tk_Window tkwin, + unsigned long pixel); +/* 166 */ +EXTERN void Tk_SetWindowBackgroundPixmap(Tk_Window tkwin, + Pixmap pixmap); +/* 167 */ +EXTERN void Tk_SetWindowBorder(Tk_Window tkwin, + unsigned long pixel); +/* 168 */ +EXTERN void Tk_SetWindowBorderWidth(Tk_Window tkwin, int width); +/* 169 */ +EXTERN void Tk_SetWindowBorderPixmap(Tk_Window tkwin, + Pixmap pixmap); +/* 170 */ +EXTERN void Tk_SetWindowColormap(Tk_Window tkwin, + Colormap colormap); +/* 171 */ +EXTERN int Tk_SetWindowVisual(Tk_Window tkwin, Visual *visual, + int depth, Colormap colormap); +/* 172 */ +EXTERN void Tk_SizeOfBitmap(Display *display, Pixmap bitmap, + int *widthPtr, int *heightPtr); +/* 173 */ +EXTERN void Tk_SizeOfImage(Tk_Image image, int *widthPtr, + int *heightPtr); +/* 174 */ +EXTERN int Tk_StrictMotif(Tk_Window tkwin); +/* 175 */ +EXTERN void Tk_TextLayoutToPostscript(Tcl_Interp *interp, + Tk_TextLayout layout); +/* 176 */ +EXTERN int Tk_TextWidth(Tk_Font font, const char *str, + int numBytes); +/* 177 */ +EXTERN void Tk_UndefineCursor(Tk_Window window); +/* 178 */ +EXTERN void Tk_UnderlineChars(Display *display, + Drawable drawable, GC gc, Tk_Font tkfont, + const char *source, int x, int y, + int firstByte, int lastByte); +/* 179 */ +EXTERN void Tk_UnderlineTextLayout(Display *display, + Drawable drawable, GC gc, + Tk_TextLayout layout, int x, int y, + int underline); +/* 180 */ +EXTERN void Tk_Ungrab(Tk_Window tkwin); +/* 181 */ +EXTERN void Tk_UnmaintainGeometry(Tk_Window slave, + Tk_Window master); +/* 182 */ +EXTERN void Tk_UnmapWindow(Tk_Window tkwin); +/* 183 */ +EXTERN void Tk_UnsetGrid(Tk_Window tkwin); +/* 184 */ +EXTERN void Tk_UpdatePointer(Tk_Window tkwin, int x, int y, + int state); +/* 185 */ +EXTERN Pixmap Tk_AllocBitmapFromObj(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr); +/* 186 */ +EXTERN Tk_3DBorder Tk_Alloc3DBorderFromObj(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr); +/* 187 */ +EXTERN XColor * Tk_AllocColorFromObj(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr); +/* 188 */ +EXTERN Tk_Cursor Tk_AllocCursorFromObj(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr); +/* 189 */ +EXTERN Tk_Font Tk_AllocFontFromObj(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr); +/* 190 */ +EXTERN Tk_OptionTable Tk_CreateOptionTable(Tcl_Interp *interp, + const Tk_OptionSpec *templatePtr); +/* 191 */ +EXTERN void Tk_DeleteOptionTable(Tk_OptionTable optionTable); +/* 192 */ +EXTERN void Tk_Free3DBorderFromObj(Tk_Window tkwin, + Tcl_Obj *objPtr); +/* 193 */ +EXTERN void Tk_FreeBitmapFromObj(Tk_Window tkwin, + Tcl_Obj *objPtr); +/* 194 */ +EXTERN void Tk_FreeColorFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +/* 195 */ +EXTERN void Tk_FreeConfigOptions(char *recordPtr, + Tk_OptionTable optionToken, Tk_Window tkwin); +/* 196 */ +EXTERN void Tk_FreeSavedOptions(Tk_SavedOptions *savePtr); +/* 197 */ +EXTERN void Tk_FreeCursorFromObj(Tk_Window tkwin, + Tcl_Obj *objPtr); +/* 198 */ +EXTERN void Tk_FreeFontFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +/* 199 */ +EXTERN Tk_3DBorder Tk_Get3DBorderFromObj(Tk_Window tkwin, + Tcl_Obj *objPtr); +/* 200 */ +EXTERN int Tk_GetAnchorFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tk_Anchor *anchorPtr); +/* 201 */ +EXTERN Pixmap Tk_GetBitmapFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +/* 202 */ +EXTERN XColor * Tk_GetColorFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +/* 203 */ +EXTERN Tk_Cursor Tk_GetCursorFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +/* 204 */ +EXTERN Tcl_Obj * Tk_GetOptionInfo(Tcl_Interp *interp, char *recordPtr, + Tk_OptionTable optionTable, Tcl_Obj *namePtr, + Tk_Window tkwin); +/* 205 */ +EXTERN Tcl_Obj * Tk_GetOptionValue(Tcl_Interp *interp, + char *recordPtr, Tk_OptionTable optionTable, + Tcl_Obj *namePtr, Tk_Window tkwin); +/* 206 */ +EXTERN int Tk_GetJustifyFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tk_Justify *justifyPtr); +/* 207 */ +EXTERN int Tk_GetMMFromObj(Tcl_Interp *interp, Tk_Window tkwin, + Tcl_Obj *objPtr, double *doublePtr); +/* 208 */ +EXTERN int Tk_GetPixelsFromObj(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, + int *intPtr); +/* 209 */ +EXTERN int Tk_GetReliefFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *resultPtr); +/* 210 */ +EXTERN int Tk_GetScrollInfoObj(Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[], double *dblPtr, + int *intPtr); +/* 211 */ +EXTERN int Tk_InitOptions(Tcl_Interp *interp, char *recordPtr, + Tk_OptionTable optionToken, Tk_Window tkwin); +/* 212 */ +EXTERN void Tk_MainEx(int argc, char **argv, + Tcl_AppInitProc *appInitProc, + Tcl_Interp *interp); +/* 213 */ +EXTERN void Tk_RestoreSavedOptions(Tk_SavedOptions *savePtr); +/* 214 */ +EXTERN int Tk_SetOptions(Tcl_Interp *interp, char *recordPtr, + Tk_OptionTable optionTable, int objc, + Tcl_Obj *const objv[], Tk_Window tkwin, + Tk_SavedOptions *savePtr, int *maskPtr); +/* 215 */ +EXTERN void Tk_InitConsoleChannels(Tcl_Interp *interp); +/* 216 */ +EXTERN int Tk_CreateConsoleWindow(Tcl_Interp *interp); +/* 217 */ +EXTERN void Tk_CreateSmoothMethod(Tcl_Interp *interp, + const Tk_SmoothMethod *method); +/* Slot 218 is reserved */ +/* Slot 219 is reserved */ +/* 220 */ +EXTERN int Tk_GetDash(Tcl_Interp *interp, const char *value, + Tk_Dash *dash); +/* 221 */ +EXTERN void Tk_CreateOutline(Tk_Outline *outline); +/* 222 */ +EXTERN void Tk_DeleteOutline(Display *display, + Tk_Outline *outline); +/* 223 */ +EXTERN int Tk_ConfigOutlineGC(XGCValues *gcValues, + Tk_Canvas canvas, Tk_Item *item, + Tk_Outline *outline); +/* 224 */ +EXTERN int Tk_ChangeOutlineGC(Tk_Canvas canvas, Tk_Item *item, + Tk_Outline *outline); +/* 225 */ +EXTERN int Tk_ResetOutlineGC(Tk_Canvas canvas, Tk_Item *item, + Tk_Outline *outline); +/* 226 */ +EXTERN int Tk_CanvasPsOutline(Tk_Canvas canvas, Tk_Item *item, + Tk_Outline *outline); +/* 227 */ +EXTERN void Tk_SetTSOrigin(Tk_Window tkwin, GC gc, int x, int y); +/* 228 */ +EXTERN int Tk_CanvasGetCoordFromObj(Tcl_Interp *interp, + Tk_Canvas canvas, Tcl_Obj *obj, + double *doublePtr); +/* 229 */ +EXTERN void Tk_CanvasSetOffset(Tk_Canvas canvas, GC gc, + Tk_TSOffset *offset); +/* 230 */ +EXTERN void Tk_DitherPhoto(Tk_PhotoHandle handle, int x, int y, + int width, int height); +/* 231 */ +EXTERN int Tk_PostscriptBitmap(Tcl_Interp *interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + Pixmap bitmap, int startX, int startY, + int width, int height); +/* 232 */ +EXTERN int Tk_PostscriptColor(Tcl_Interp *interp, + Tk_PostscriptInfo psInfo, XColor *colorPtr); +/* 233 */ +EXTERN int Tk_PostscriptFont(Tcl_Interp *interp, + Tk_PostscriptInfo psInfo, Tk_Font font); +/* 234 */ +EXTERN int Tk_PostscriptImage(Tk_Image image, + Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psinfo, int x, int y, + int width, int height, int prepass); +/* 235 */ +EXTERN void Tk_PostscriptPath(Tcl_Interp *interp, + Tk_PostscriptInfo psInfo, double *coordPtr, + int numPoints); +/* 236 */ +EXTERN int Tk_PostscriptStipple(Tcl_Interp *interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + Pixmap bitmap); +/* 237 */ +EXTERN double Tk_PostscriptY(double y, Tk_PostscriptInfo psInfo); +/* 238 */ +EXTERN int Tk_PostscriptPhoto(Tcl_Interp *interp, + Tk_PhotoImageBlock *blockPtr, + Tk_PostscriptInfo psInfo, int width, + int height); +/* 239 */ +EXTERN void Tk_CreateClientMessageHandler( + Tk_ClientMessageProc *proc); +/* 240 */ +EXTERN void Tk_DeleteClientMessageHandler( + Tk_ClientMessageProc *proc); +/* 241 */ +EXTERN Tk_Window Tk_CreateAnonymousWindow(Tcl_Interp *interp, + Tk_Window parent, const char *screenName); +/* 242 */ +EXTERN void Tk_SetClassProcs(Tk_Window tkwin, + const Tk_ClassProcs *procs, + ClientData instanceData); +/* 243 */ +EXTERN void Tk_SetInternalBorderEx(Tk_Window tkwin, int left, + int right, int top, int bottom); +/* 244 */ +EXTERN void Tk_SetMinimumRequestSize(Tk_Window tkwin, + int minWidth, int minHeight); +/* 245 */ +EXTERN void Tk_SetCaretPos(Tk_Window tkwin, int x, int y, + int height); +/* 246 */ +EXTERN void Tk_PhotoPutBlock_Panic(Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int compRule); +/* 247 */ +EXTERN void Tk_PhotoPutZoomedBlock_Panic(Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int zoomX, int zoomY, + int subsampleX, int subsampleY, int compRule); +/* 248 */ +EXTERN int Tk_CollapseMotionEvents(Display *display, + int collapse); +/* 249 */ +EXTERN Tk_StyleEngine Tk_RegisterStyleEngine(const char *name, + Tk_StyleEngine parent); +/* 250 */ +EXTERN Tk_StyleEngine Tk_GetStyleEngine(const char *name); +/* 251 */ +EXTERN int Tk_RegisterStyledElement(Tk_StyleEngine engine, + Tk_ElementSpec *templatePtr); +/* 252 */ +EXTERN int Tk_GetElementId(const char *name); +/* 253 */ +EXTERN Tk_Style Tk_CreateStyle(const char *name, + Tk_StyleEngine engine, ClientData clientData); +/* 254 */ +EXTERN Tk_Style Tk_GetStyle(Tcl_Interp *interp, const char *name); +/* 255 */ +EXTERN void Tk_FreeStyle(Tk_Style style); +/* 256 */ +EXTERN const char * Tk_NameOfStyle(Tk_Style style); +/* 257 */ +EXTERN Tk_Style Tk_AllocStyleFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 258 */ +EXTERN Tk_Style Tk_GetStyleFromObj(Tcl_Obj *objPtr); +/* 259 */ +EXTERN void Tk_FreeStyleFromObj(Tcl_Obj *objPtr); +/* 260 */ +EXTERN Tk_StyledElement Tk_GetStyledElement(Tk_Style style, int elementId, + Tk_OptionTable optionTable); +/* 261 */ +EXTERN void Tk_GetElementSize(Tk_Style style, + Tk_StyledElement element, char *recordPtr, + Tk_Window tkwin, int width, int height, + int inner, int *widthPtr, int *heightPtr); +/* 262 */ +EXTERN void Tk_GetElementBox(Tk_Style style, + Tk_StyledElement element, char *recordPtr, + Tk_Window tkwin, int x, int y, int width, + int height, int inner, int *xPtr, int *yPtr, + int *widthPtr, int *heightPtr); +/* 263 */ +EXTERN int Tk_GetElementBorderWidth(Tk_Style style, + Tk_StyledElement element, char *recordPtr, + Tk_Window tkwin); +/* 264 */ +EXTERN void Tk_DrawElement(Tk_Style style, + Tk_StyledElement element, char *recordPtr, + Tk_Window tkwin, Drawable d, int x, int y, + int width, int height, int state); +/* 265 */ +EXTERN int Tk_PhotoExpand(Tcl_Interp *interp, + Tk_PhotoHandle handle, int width, int height); +/* 266 */ +EXTERN int Tk_PhotoPutBlock(Tcl_Interp *interp, + Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int compRule); +/* 267 */ +EXTERN int Tk_PhotoPutZoomedBlock(Tcl_Interp *interp, + Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int zoomX, int zoomY, + int subsampleX, int subsampleY, int compRule); +/* 268 */ +EXTERN int Tk_PhotoSetSize(Tcl_Interp *interp, + Tk_PhotoHandle handle, int width, int height); +/* 269 */ +EXTERN long Tk_GetUserInactiveTime(Display *dpy); +/* 270 */ +EXTERN void Tk_ResetUserInactiveTime(Display *dpy); +/* 271 */ +EXTERN Tcl_Interp * Tk_Interp(Tk_Window tkwin); +/* 272 */ +EXTERN void Tk_CreateOldImageType(const Tk_ImageType *typePtr); +/* 273 */ +EXTERN void Tk_CreateOldPhotoImageFormat( + const Tk_PhotoImageFormat *formatPtr); + +typedef struct { + const struct TkPlatStubs *tkPlatStubs; + const struct TkIntStubs *tkIntStubs; + const struct TkIntPlatStubs *tkIntPlatStubs; + const struct TkIntXlibStubs *tkIntXlibStubs; +} TkStubHooks; + +typedef struct TkStubs { + int magic; + const TkStubHooks *hooks; + + void (*tk_MainLoop) (void); /* 0 */ + XColor * (*tk_3DBorderColor) (Tk_3DBorder border); /* 1 */ + GC (*tk_3DBorderGC) (Tk_Window tkwin, Tk_3DBorder border, int which); /* 2 */ + void (*tk_3DHorizontalBevel) (Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int leftIn, int rightIn, int topBevel, int relief); /* 3 */ + void (*tk_3DVerticalBevel) (Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int leftBevel, int relief); /* 4 */ + void (*tk_AddOption) (Tk_Window tkwin, const char *name, const char *value, int priority); /* 5 */ + void (*tk_BindEvent) (Tk_BindingTable bindingTable, XEvent *eventPtr, Tk_Window tkwin, int numObjects, ClientData *objectPtr); /* 6 */ + void (*tk_CanvasDrawableCoords) (Tk_Canvas canvas, double x, double y, short *drawableXPtr, short *drawableYPtr); /* 7 */ + void (*tk_CanvasEventuallyRedraw) (Tk_Canvas canvas, int x1, int y1, int x2, int y2); /* 8 */ + int (*tk_CanvasGetCoord) (Tcl_Interp *interp, Tk_Canvas canvas, const char *str, double *doublePtr); /* 9 */ + Tk_CanvasTextInfo * (*tk_CanvasGetTextInfo) (Tk_Canvas canvas); /* 10 */ + int (*tk_CanvasPsBitmap) (Tcl_Interp *interp, Tk_Canvas canvas, Pixmap bitmap, int x, int y, int width, int height); /* 11 */ + int (*tk_CanvasPsColor) (Tcl_Interp *interp, Tk_Canvas canvas, XColor *colorPtr); /* 12 */ + int (*tk_CanvasPsFont) (Tcl_Interp *interp, Tk_Canvas canvas, Tk_Font font); /* 13 */ + void (*tk_CanvasPsPath) (Tcl_Interp *interp, Tk_Canvas canvas, double *coordPtr, int numPoints); /* 14 */ + int (*tk_CanvasPsStipple) (Tcl_Interp *interp, Tk_Canvas canvas, Pixmap bitmap); /* 15 */ + double (*tk_CanvasPsY) (Tk_Canvas canvas, double y); /* 16 */ + void (*tk_CanvasSetStippleOrigin) (Tk_Canvas canvas, GC gc); /* 17 */ + int (*tk_CanvasTagsParseProc) (ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, const char *value, char *widgRec, int offset); /* 18 */ + CONST86 char * (*tk_CanvasTagsPrintProc) (ClientData clientData, Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr); /* 19 */ + Tk_Window (*tk_CanvasTkwin) (Tk_Canvas canvas); /* 20 */ + void (*tk_CanvasWindowCoords) (Tk_Canvas canvas, double x, double y, short *screenXPtr, short *screenYPtr); /* 21 */ + void (*tk_ChangeWindowAttributes) (Tk_Window tkwin, unsigned long valueMask, XSetWindowAttributes *attsPtr); /* 22 */ + int (*tk_CharBbox) (Tk_TextLayout layout, int index, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr); /* 23 */ + void (*tk_ClearSelection) (Tk_Window tkwin, Atom selection); /* 24 */ + int (*tk_ClipboardAppend) (Tcl_Interp *interp, Tk_Window tkwin, Atom target, Atom format, const char *buffer); /* 25 */ + int (*tk_ClipboardClear) (Tcl_Interp *interp, Tk_Window tkwin); /* 26 */ + int (*tk_ConfigureInfo) (Tcl_Interp *interp, Tk_Window tkwin, const Tk_ConfigSpec *specs, char *widgRec, const char *argvName, int flags); /* 27 */ + int (*tk_ConfigureValue) (Tcl_Interp *interp, Tk_Window tkwin, const Tk_ConfigSpec *specs, char *widgRec, const char *argvName, int flags); /* 28 */ + int (*tk_ConfigureWidget) (Tcl_Interp *interp, Tk_Window tkwin, const Tk_ConfigSpec *specs, int argc, CONST84 char **argv, char *widgRec, int flags); /* 29 */ + void (*tk_ConfigureWindow) (Tk_Window tkwin, unsigned int valueMask, XWindowChanges *valuePtr); /* 30 */ + Tk_TextLayout (*tk_ComputeTextLayout) (Tk_Font font, const char *str, int numChars, int wrapLength, Tk_Justify justify, int flags, int *widthPtr, int *heightPtr); /* 31 */ + Tk_Window (*tk_CoordsToWindow) (int rootX, int rootY, Tk_Window tkwin); /* 32 */ + unsigned long (*tk_CreateBinding) (Tcl_Interp *interp, Tk_BindingTable bindingTable, ClientData object, const char *eventStr, const char *script, int append); /* 33 */ + Tk_BindingTable (*tk_CreateBindingTable) (Tcl_Interp *interp); /* 34 */ + Tk_ErrorHandler (*tk_CreateErrorHandler) (Display *display, int errNum, int request, int minorCode, Tk_ErrorProc *errorProc, ClientData clientData); /* 35 */ + void (*tk_CreateEventHandler) (Tk_Window token, unsigned long mask, Tk_EventProc *proc, ClientData clientData); /* 36 */ + void (*tk_CreateGenericHandler) (Tk_GenericProc *proc, ClientData clientData); /* 37 */ + void (*tk_CreateImageType) (const Tk_ImageType *typePtr); /* 38 */ + void (*tk_CreateItemType) (Tk_ItemType *typePtr); /* 39 */ + void (*tk_CreatePhotoImageFormat) (const Tk_PhotoImageFormat *formatPtr); /* 40 */ + void (*tk_CreateSelHandler) (Tk_Window tkwin, Atom selection, Atom target, Tk_SelectionProc *proc, ClientData clientData, Atom format); /* 41 */ + Tk_Window (*tk_CreateWindow) (Tcl_Interp *interp, Tk_Window parent, const char *name, const char *screenName); /* 42 */ + Tk_Window (*tk_CreateWindowFromPath) (Tcl_Interp *interp, Tk_Window tkwin, const char *pathName, const char *screenName); /* 43 */ + int (*tk_DefineBitmap) (Tcl_Interp *interp, const char *name, const void *source, int width, int height); /* 44 */ + void (*tk_DefineCursor) (Tk_Window window, Tk_Cursor cursor); /* 45 */ + void (*tk_DeleteAllBindings) (Tk_BindingTable bindingTable, ClientData object); /* 46 */ + int (*tk_DeleteBinding) (Tcl_Interp *interp, Tk_BindingTable bindingTable, ClientData object, const char *eventStr); /* 47 */ + void (*tk_DeleteBindingTable) (Tk_BindingTable bindingTable); /* 48 */ + void (*tk_DeleteErrorHandler) (Tk_ErrorHandler handler); /* 49 */ + void (*tk_DeleteEventHandler) (Tk_Window token, unsigned long mask, Tk_EventProc *proc, ClientData clientData); /* 50 */ + void (*tk_DeleteGenericHandler) (Tk_GenericProc *proc, ClientData clientData); /* 51 */ + void (*tk_DeleteImage) (Tcl_Interp *interp, const char *name); /* 52 */ + void (*tk_DeleteSelHandler) (Tk_Window tkwin, Atom selection, Atom target); /* 53 */ + void (*tk_DestroyWindow) (Tk_Window tkwin); /* 54 */ + CONST84_RETURN char * (*tk_DisplayName) (Tk_Window tkwin); /* 55 */ + int (*tk_DistanceToTextLayout) (Tk_TextLayout layout, int x, int y); /* 56 */ + void (*tk_Draw3DPolygon) (Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, XPoint *pointPtr, int numPoints, int borderWidth, int leftRelief); /* 57 */ + void (*tk_Draw3DRectangle) (Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief); /* 58 */ + void (*tk_DrawChars) (Display *display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int numBytes, int x, int y); /* 59 */ + void (*tk_DrawFocusHighlight) (Tk_Window tkwin, GC gc, int width, Drawable drawable); /* 60 */ + void (*tk_DrawTextLayout) (Display *display, Drawable drawable, GC gc, Tk_TextLayout layout, int x, int y, int firstChar, int lastChar); /* 61 */ + void (*tk_Fill3DPolygon) (Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, XPoint *pointPtr, int numPoints, int borderWidth, int leftRelief); /* 62 */ + void (*tk_Fill3DRectangle) (Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief); /* 63 */ + Tk_PhotoHandle (*tk_FindPhoto) (Tcl_Interp *interp, const char *imageName); /* 64 */ + Font (*tk_FontId) (Tk_Font font); /* 65 */ + void (*tk_Free3DBorder) (Tk_3DBorder border); /* 66 */ + void (*tk_FreeBitmap) (Display *display, Pixmap bitmap); /* 67 */ + void (*tk_FreeColor) (XColor *colorPtr); /* 68 */ + void (*tk_FreeColormap) (Display *display, Colormap colormap); /* 69 */ + void (*tk_FreeCursor) (Display *display, Tk_Cursor cursor); /* 70 */ + void (*tk_FreeFont) (Tk_Font f); /* 71 */ + void (*tk_FreeGC) (Display *display, GC gc); /* 72 */ + void (*tk_FreeImage) (Tk_Image image); /* 73 */ + void (*tk_FreeOptions) (const Tk_ConfigSpec *specs, char *widgRec, Display *display, int needFlags); /* 74 */ + void (*tk_FreePixmap) (Display *display, Pixmap pixmap); /* 75 */ + void (*tk_FreeTextLayout) (Tk_TextLayout textLayout); /* 76 */ + void (*tk_FreeXId) (Display *display, XID xid); /* 77 */ + GC (*tk_GCForColor) (XColor *colorPtr, Drawable drawable); /* 78 */ + void (*tk_GeometryRequest) (Tk_Window tkwin, int reqWidth, int reqHeight); /* 79 */ + Tk_3DBorder (*tk_Get3DBorder) (Tcl_Interp *interp, Tk_Window tkwin, Tk_Uid colorName); /* 80 */ + void (*tk_GetAllBindings) (Tcl_Interp *interp, Tk_BindingTable bindingTable, ClientData object); /* 81 */ + int (*tk_GetAnchor) (Tcl_Interp *interp, const char *str, Tk_Anchor *anchorPtr); /* 82 */ + CONST84_RETURN char * (*tk_GetAtomName) (Tk_Window tkwin, Atom atom); /* 83 */ + CONST84_RETURN char * (*tk_GetBinding) (Tcl_Interp *interp, Tk_BindingTable bindingTable, ClientData object, const char *eventStr); /* 84 */ + Pixmap (*tk_GetBitmap) (Tcl_Interp *interp, Tk_Window tkwin, const char *str); /* 85 */ + Pixmap (*tk_GetBitmapFromData) (Tcl_Interp *interp, Tk_Window tkwin, const void *source, int width, int height); /* 86 */ + int (*tk_GetCapStyle) (Tcl_Interp *interp, const char *str, int *capPtr); /* 87 */ + XColor * (*tk_GetColor) (Tcl_Interp *interp, Tk_Window tkwin, Tk_Uid name); /* 88 */ + XColor * (*tk_GetColorByValue) (Tk_Window tkwin, XColor *colorPtr); /* 89 */ + Colormap (*tk_GetColormap) (Tcl_Interp *interp, Tk_Window tkwin, const char *str); /* 90 */ + Tk_Cursor (*tk_GetCursor) (Tcl_Interp *interp, Tk_Window tkwin, Tk_Uid str); /* 91 */ + Tk_Cursor (*tk_GetCursorFromData) (Tcl_Interp *interp, Tk_Window tkwin, const char *source, const char *mask, int width, int height, int xHot, int yHot, Tk_Uid fg, Tk_Uid bg); /* 92 */ + Tk_Font (*tk_GetFont) (Tcl_Interp *interp, Tk_Window tkwin, const char *str); /* 93 */ + Tk_Font (*tk_GetFontFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 94 */ + void (*tk_GetFontMetrics) (Tk_Font font, Tk_FontMetrics *fmPtr); /* 95 */ + GC (*tk_GetGC) (Tk_Window tkwin, unsigned long valueMask, XGCValues *valuePtr); /* 96 */ + Tk_Image (*tk_GetImage) (Tcl_Interp *interp, Tk_Window tkwin, const char *name, Tk_ImageChangedProc *changeProc, ClientData clientData); /* 97 */ + ClientData (*tk_GetImageMasterData) (Tcl_Interp *interp, const char *name, CONST86 Tk_ImageType **typePtrPtr); /* 98 */ + Tk_ItemType * (*tk_GetItemTypes) (void); /* 99 */ + int (*tk_GetJoinStyle) (Tcl_Interp *interp, const char *str, int *joinPtr); /* 100 */ + int (*tk_GetJustify) (Tcl_Interp *interp, const char *str, Tk_Justify *justifyPtr); /* 101 */ + int (*tk_GetNumMainWindows) (void); /* 102 */ + Tk_Uid (*tk_GetOption) (Tk_Window tkwin, const char *name, const char *className); /* 103 */ + int (*tk_GetPixels) (Tcl_Interp *interp, Tk_Window tkwin, const char *str, int *intPtr); /* 104 */ + Pixmap (*tk_GetPixmap) (Display *display, Drawable d, int width, int height, int depth); /* 105 */ + int (*tk_GetRelief) (Tcl_Interp *interp, const char *name, int *reliefPtr); /* 106 */ + void (*tk_GetRootCoords) (Tk_Window tkwin, int *xPtr, int *yPtr); /* 107 */ + int (*tk_GetScrollInfo) (Tcl_Interp *interp, int argc, CONST84 char **argv, double *dblPtr, int *intPtr); /* 108 */ + int (*tk_GetScreenMM) (Tcl_Interp *interp, Tk_Window tkwin, const char *str, double *doublePtr); /* 109 */ + int (*tk_GetSelection) (Tcl_Interp *interp, Tk_Window tkwin, Atom selection, Atom target, Tk_GetSelProc *proc, ClientData clientData); /* 110 */ + Tk_Uid (*tk_GetUid) (const char *str); /* 111 */ + Visual * (*tk_GetVisual) (Tcl_Interp *interp, Tk_Window tkwin, const char *str, int *depthPtr, Colormap *colormapPtr); /* 112 */ + void (*tk_GetVRootGeometry) (Tk_Window tkwin, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr); /* 113 */ + int (*tk_Grab) (Tcl_Interp *interp, Tk_Window tkwin, int grabGlobal); /* 114 */ + void (*tk_HandleEvent) (XEvent *eventPtr); /* 115 */ + Tk_Window (*tk_IdToWindow) (Display *display, Window window); /* 116 */ + void (*tk_ImageChanged) (Tk_ImageMaster master, int x, int y, int width, int height, int imageWidth, int imageHeight); /* 117 */ + int (*tk_Init) (Tcl_Interp *interp); /* 118 */ + Atom (*tk_InternAtom) (Tk_Window tkwin, const char *name); /* 119 */ + int (*tk_IntersectTextLayout) (Tk_TextLayout layout, int x, int y, int width, int height); /* 120 */ + void (*tk_MaintainGeometry) (Tk_Window slave, Tk_Window master, int x, int y, int width, int height); /* 121 */ + Tk_Window (*tk_MainWindow) (Tcl_Interp *interp); /* 122 */ + void (*tk_MakeWindowExist) (Tk_Window tkwin); /* 123 */ + void (*tk_ManageGeometry) (Tk_Window tkwin, const Tk_GeomMgr *mgrPtr, ClientData clientData); /* 124 */ + void (*tk_MapWindow) (Tk_Window tkwin); /* 125 */ + int (*tk_MeasureChars) (Tk_Font tkfont, const char *source, int numBytes, int maxPixels, int flags, int *lengthPtr); /* 126 */ + void (*tk_MoveResizeWindow) (Tk_Window tkwin, int x, int y, int width, int height); /* 127 */ + void (*tk_MoveWindow) (Tk_Window tkwin, int x, int y); /* 128 */ + void (*tk_MoveToplevelWindow) (Tk_Window tkwin, int x, int y); /* 129 */ + CONST84_RETURN char * (*tk_NameOf3DBorder) (Tk_3DBorder border); /* 130 */ + CONST84_RETURN char * (*tk_NameOfAnchor) (Tk_Anchor anchor); /* 131 */ + CONST84_RETURN char * (*tk_NameOfBitmap) (Display *display, Pixmap bitmap); /* 132 */ + CONST84_RETURN char * (*tk_NameOfCapStyle) (int cap); /* 133 */ + CONST84_RETURN char * (*tk_NameOfColor) (XColor *colorPtr); /* 134 */ + CONST84_RETURN char * (*tk_NameOfCursor) (Display *display, Tk_Cursor cursor); /* 135 */ + CONST84_RETURN char * (*tk_NameOfFont) (Tk_Font font); /* 136 */ + CONST84_RETURN char * (*tk_NameOfImage) (Tk_ImageMaster imageMaster); /* 137 */ + CONST84_RETURN char * (*tk_NameOfJoinStyle) (int join); /* 138 */ + CONST84_RETURN char * (*tk_NameOfJustify) (Tk_Justify justify); /* 139 */ + CONST84_RETURN char * (*tk_NameOfRelief) (int relief); /* 140 */ + Tk_Window (*tk_NameToWindow) (Tcl_Interp *interp, const char *pathName, Tk_Window tkwin); /* 141 */ + void (*tk_OwnSelection) (Tk_Window tkwin, Atom selection, Tk_LostSelProc *proc, ClientData clientData); /* 142 */ + int (*tk_ParseArgv) (Tcl_Interp *interp, Tk_Window tkwin, int *argcPtr, CONST84 char **argv, const Tk_ArgvInfo *argTable, int flags); /* 143 */ + void (*tk_PhotoPutBlock_NoComposite) (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height); /* 144 */ + void (*tk_PhotoPutZoomedBlock_NoComposite) (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY); /* 145 */ + int (*tk_PhotoGetImage) (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr); /* 146 */ + void (*tk_PhotoBlank) (Tk_PhotoHandle handle); /* 147 */ + void (*tk_PhotoExpand_Panic) (Tk_PhotoHandle handle, int width, int height); /* 148 */ + void (*tk_PhotoGetSize) (Tk_PhotoHandle handle, int *widthPtr, int *heightPtr); /* 149 */ + void (*tk_PhotoSetSize_Panic) (Tk_PhotoHandle handle, int width, int height); /* 150 */ + int (*tk_PointToChar) (Tk_TextLayout layout, int x, int y); /* 151 */ + int (*tk_PostscriptFontName) (Tk_Font tkfont, Tcl_DString *dsPtr); /* 152 */ + void (*tk_PreserveColormap) (Display *display, Colormap colormap); /* 153 */ + void (*tk_QueueWindowEvent) (XEvent *eventPtr, Tcl_QueuePosition position); /* 154 */ + void (*tk_RedrawImage) (Tk_Image image, int imageX, int imageY, int width, int height, Drawable drawable, int drawableX, int drawableY); /* 155 */ + void (*tk_ResizeWindow) (Tk_Window tkwin, int width, int height); /* 156 */ + int (*tk_RestackWindow) (Tk_Window tkwin, int aboveBelow, Tk_Window other); /* 157 */ + Tk_RestrictProc * (*tk_RestrictEvents) (Tk_RestrictProc *proc, ClientData arg, ClientData *prevArgPtr); /* 158 */ + int (*tk_SafeInit) (Tcl_Interp *interp); /* 159 */ + const char * (*tk_SetAppName) (Tk_Window tkwin, const char *name); /* 160 */ + void (*tk_SetBackgroundFromBorder) (Tk_Window tkwin, Tk_3DBorder border); /* 161 */ + void (*tk_SetClass) (Tk_Window tkwin, const char *className); /* 162 */ + void (*tk_SetGrid) (Tk_Window tkwin, int reqWidth, int reqHeight, int gridWidth, int gridHeight); /* 163 */ + void (*tk_SetInternalBorder) (Tk_Window tkwin, int width); /* 164 */ + void (*tk_SetWindowBackground) (Tk_Window tkwin, unsigned long pixel); /* 165 */ + void (*tk_SetWindowBackgroundPixmap) (Tk_Window tkwin, Pixmap pixmap); /* 166 */ + void (*tk_SetWindowBorder) (Tk_Window tkwin, unsigned long pixel); /* 167 */ + void (*tk_SetWindowBorderWidth) (Tk_Window tkwin, int width); /* 168 */ + void (*tk_SetWindowBorderPixmap) (Tk_Window tkwin, Pixmap pixmap); /* 169 */ + void (*tk_SetWindowColormap) (Tk_Window tkwin, Colormap colormap); /* 170 */ + int (*tk_SetWindowVisual) (Tk_Window tkwin, Visual *visual, int depth, Colormap colormap); /* 171 */ + void (*tk_SizeOfBitmap) (Display *display, Pixmap bitmap, int *widthPtr, int *heightPtr); /* 172 */ + void (*tk_SizeOfImage) (Tk_Image image, int *widthPtr, int *heightPtr); /* 173 */ + int (*tk_StrictMotif) (Tk_Window tkwin); /* 174 */ + void (*tk_TextLayoutToPostscript) (Tcl_Interp *interp, Tk_TextLayout layout); /* 175 */ + int (*tk_TextWidth) (Tk_Font font, const char *str, int numBytes); /* 176 */ + void (*tk_UndefineCursor) (Tk_Window window); /* 177 */ + void (*tk_UnderlineChars) (Display *display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int x, int y, int firstByte, int lastByte); /* 178 */ + void (*tk_UnderlineTextLayout) (Display *display, Drawable drawable, GC gc, Tk_TextLayout layout, int x, int y, int underline); /* 179 */ + void (*tk_Ungrab) (Tk_Window tkwin); /* 180 */ + void (*tk_UnmaintainGeometry) (Tk_Window slave, Tk_Window master); /* 181 */ + void (*tk_UnmapWindow) (Tk_Window tkwin); /* 182 */ + void (*tk_UnsetGrid) (Tk_Window tkwin); /* 183 */ + void (*tk_UpdatePointer) (Tk_Window tkwin, int x, int y, int state); /* 184 */ + Pixmap (*tk_AllocBitmapFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr); /* 185 */ + Tk_3DBorder (*tk_Alloc3DBorderFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr); /* 186 */ + XColor * (*tk_AllocColorFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr); /* 187 */ + Tk_Cursor (*tk_AllocCursorFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr); /* 188 */ + Tk_Font (*tk_AllocFontFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr); /* 189 */ + Tk_OptionTable (*tk_CreateOptionTable) (Tcl_Interp *interp, const Tk_OptionSpec *templatePtr); /* 190 */ + void (*tk_DeleteOptionTable) (Tk_OptionTable optionTable); /* 191 */ + void (*tk_Free3DBorderFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 192 */ + void (*tk_FreeBitmapFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 193 */ + void (*tk_FreeColorFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 194 */ + void (*tk_FreeConfigOptions) (char *recordPtr, Tk_OptionTable optionToken, Tk_Window tkwin); /* 195 */ + void (*tk_FreeSavedOptions) (Tk_SavedOptions *savePtr); /* 196 */ + void (*tk_FreeCursorFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 197 */ + void (*tk_FreeFontFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 198 */ + Tk_3DBorder (*tk_Get3DBorderFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 199 */ + int (*tk_GetAnchorFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tk_Anchor *anchorPtr); /* 200 */ + Pixmap (*tk_GetBitmapFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 201 */ + XColor * (*tk_GetColorFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 202 */ + Tk_Cursor (*tk_GetCursorFromObj) (Tk_Window tkwin, Tcl_Obj *objPtr); /* 203 */ + Tcl_Obj * (*tk_GetOptionInfo) (Tcl_Interp *interp, char *recordPtr, Tk_OptionTable optionTable, Tcl_Obj *namePtr, Tk_Window tkwin); /* 204 */ + Tcl_Obj * (*tk_GetOptionValue) (Tcl_Interp *interp, char *recordPtr, Tk_OptionTable optionTable, Tcl_Obj *namePtr, Tk_Window tkwin); /* 205 */ + int (*tk_GetJustifyFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tk_Justify *justifyPtr); /* 206 */ + int (*tk_GetMMFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, double *doublePtr); /* 207 */ + int (*tk_GetPixelsFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, int *intPtr); /* 208 */ + int (*tk_GetReliefFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *resultPtr); /* 209 */ + int (*tk_GetScrollInfoObj) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], double *dblPtr, int *intPtr); /* 210 */ + int (*tk_InitOptions) (Tcl_Interp *interp, char *recordPtr, Tk_OptionTable optionToken, Tk_Window tkwin); /* 211 */ + void (*tk_MainEx) (int argc, char **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); /* 212 */ + void (*tk_RestoreSavedOptions) (Tk_SavedOptions *savePtr); /* 213 */ + int (*tk_SetOptions) (Tcl_Interp *interp, char *recordPtr, Tk_OptionTable optionTable, int objc, Tcl_Obj *const objv[], Tk_Window tkwin, Tk_SavedOptions *savePtr, int *maskPtr); /* 214 */ + void (*tk_InitConsoleChannels) (Tcl_Interp *interp); /* 215 */ + int (*tk_CreateConsoleWindow) (Tcl_Interp *interp); /* 216 */ + void (*tk_CreateSmoothMethod) (Tcl_Interp *interp, const Tk_SmoothMethod *method); /* 217 */ + void (*reserved218)(void); + void (*reserved219)(void); + int (*tk_GetDash) (Tcl_Interp *interp, const char *value, Tk_Dash *dash); /* 220 */ + void (*tk_CreateOutline) (Tk_Outline *outline); /* 221 */ + void (*tk_DeleteOutline) (Display *display, Tk_Outline *outline); /* 222 */ + int (*tk_ConfigOutlineGC) (XGCValues *gcValues, Tk_Canvas canvas, Tk_Item *item, Tk_Outline *outline); /* 223 */ + int (*tk_ChangeOutlineGC) (Tk_Canvas canvas, Tk_Item *item, Tk_Outline *outline); /* 224 */ + int (*tk_ResetOutlineGC) (Tk_Canvas canvas, Tk_Item *item, Tk_Outline *outline); /* 225 */ + int (*tk_CanvasPsOutline) (Tk_Canvas canvas, Tk_Item *item, Tk_Outline *outline); /* 226 */ + void (*tk_SetTSOrigin) (Tk_Window tkwin, GC gc, int x, int y); /* 227 */ + int (*tk_CanvasGetCoordFromObj) (Tcl_Interp *interp, Tk_Canvas canvas, Tcl_Obj *obj, double *doublePtr); /* 228 */ + void (*tk_CanvasSetOffset) (Tk_Canvas canvas, GC gc, Tk_TSOffset *offset); /* 229 */ + void (*tk_DitherPhoto) (Tk_PhotoHandle handle, int x, int y, int width, int height); /* 230 */ + int (*tk_PostscriptBitmap) (Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psInfo, Pixmap bitmap, int startX, int startY, int width, int height); /* 231 */ + int (*tk_PostscriptColor) (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, XColor *colorPtr); /* 232 */ + int (*tk_PostscriptFont) (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, Tk_Font font); /* 233 */ + int (*tk_PostscriptImage) (Tk_Image image, Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psinfo, int x, int y, int width, int height, int prepass); /* 234 */ + void (*tk_PostscriptPath) (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, double *coordPtr, int numPoints); /* 235 */ + int (*tk_PostscriptStipple) (Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psInfo, Pixmap bitmap); /* 236 */ + double (*tk_PostscriptY) (double y, Tk_PostscriptInfo psInfo); /* 237 */ + int (*tk_PostscriptPhoto) (Tcl_Interp *interp, Tk_PhotoImageBlock *blockPtr, Tk_PostscriptInfo psInfo, int width, int height); /* 238 */ + void (*tk_CreateClientMessageHandler) (Tk_ClientMessageProc *proc); /* 239 */ + void (*tk_DeleteClientMessageHandler) (Tk_ClientMessageProc *proc); /* 240 */ + Tk_Window (*tk_CreateAnonymousWindow) (Tcl_Interp *interp, Tk_Window parent, const char *screenName); /* 241 */ + void (*tk_SetClassProcs) (Tk_Window tkwin, const Tk_ClassProcs *procs, ClientData instanceData); /* 242 */ + void (*tk_SetInternalBorderEx) (Tk_Window tkwin, int left, int right, int top, int bottom); /* 243 */ + void (*tk_SetMinimumRequestSize) (Tk_Window tkwin, int minWidth, int minHeight); /* 244 */ + void (*tk_SetCaretPos) (Tk_Window tkwin, int x, int y, int height); /* 245 */ + void (*tk_PhotoPutBlock_Panic) (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height, int compRule); /* 246 */ + void (*tk_PhotoPutZoomedBlock_Panic) (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY, int compRule); /* 247 */ + int (*tk_CollapseMotionEvents) (Display *display, int collapse); /* 248 */ + Tk_StyleEngine (*tk_RegisterStyleEngine) (const char *name, Tk_StyleEngine parent); /* 249 */ + Tk_StyleEngine (*tk_GetStyleEngine) (const char *name); /* 250 */ + int (*tk_RegisterStyledElement) (Tk_StyleEngine engine, Tk_ElementSpec *templatePtr); /* 251 */ + int (*tk_GetElementId) (const char *name); /* 252 */ + Tk_Style (*tk_CreateStyle) (const char *name, Tk_StyleEngine engine, ClientData clientData); /* 253 */ + Tk_Style (*tk_GetStyle) (Tcl_Interp *interp, const char *name); /* 254 */ + void (*tk_FreeStyle) (Tk_Style style); /* 255 */ + const char * (*tk_NameOfStyle) (Tk_Style style); /* 256 */ + Tk_Style (*tk_AllocStyleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 257 */ + Tk_Style (*tk_GetStyleFromObj) (Tcl_Obj *objPtr); /* 258 */ + void (*tk_FreeStyleFromObj) (Tcl_Obj *objPtr); /* 259 */ + Tk_StyledElement (*tk_GetStyledElement) (Tk_Style style, int elementId, Tk_OptionTable optionTable); /* 260 */ + void (*tk_GetElementSize) (Tk_Style style, Tk_StyledElement element, char *recordPtr, Tk_Window tkwin, int width, int height, int inner, int *widthPtr, int *heightPtr); /* 261 */ + void (*tk_GetElementBox) (Tk_Style style, Tk_StyledElement element, char *recordPtr, Tk_Window tkwin, int x, int y, int width, int height, int inner, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr); /* 262 */ + int (*tk_GetElementBorderWidth) (Tk_Style style, Tk_StyledElement element, char *recordPtr, Tk_Window tkwin); /* 263 */ + void (*tk_DrawElement) (Tk_Style style, Tk_StyledElement element, char *recordPtr, Tk_Window tkwin, Drawable d, int x, int y, int width, int height, int state); /* 264 */ + int (*tk_PhotoExpand) (Tcl_Interp *interp, Tk_PhotoHandle handle, int width, int height); /* 265 */ + int (*tk_PhotoPutBlock) (Tcl_Interp *interp, Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height, int compRule); /* 266 */ + int (*tk_PhotoPutZoomedBlock) (Tcl_Interp *interp, Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY, int compRule); /* 267 */ + int (*tk_PhotoSetSize) (Tcl_Interp *interp, Tk_PhotoHandle handle, int width, int height); /* 268 */ + long (*tk_GetUserInactiveTime) (Display *dpy); /* 269 */ + void (*tk_ResetUserInactiveTime) (Display *dpy); /* 270 */ + Tcl_Interp * (*tk_Interp) (Tk_Window tkwin); /* 271 */ + void (*tk_CreateOldImageType) (const Tk_ImageType *typePtr); /* 272 */ + void (*tk_CreateOldPhotoImageFormat) (const Tk_PhotoImageFormat *formatPtr); /* 273 */ +} TkStubs; + +extern const TkStubs *tkStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) + +/* + * Inline function declarations: + */ + +#define Tk_MainLoop \ + (tkStubsPtr->tk_MainLoop) /* 0 */ +#define Tk_3DBorderColor \ + (tkStubsPtr->tk_3DBorderColor) /* 1 */ +#define Tk_3DBorderGC \ + (tkStubsPtr->tk_3DBorderGC) /* 2 */ +#define Tk_3DHorizontalBevel \ + (tkStubsPtr->tk_3DHorizontalBevel) /* 3 */ +#define Tk_3DVerticalBevel \ + (tkStubsPtr->tk_3DVerticalBevel) /* 4 */ +#define Tk_AddOption \ + (tkStubsPtr->tk_AddOption) /* 5 */ +#define Tk_BindEvent \ + (tkStubsPtr->tk_BindEvent) /* 6 */ +#define Tk_CanvasDrawableCoords \ + (tkStubsPtr->tk_CanvasDrawableCoords) /* 7 */ +#define Tk_CanvasEventuallyRedraw \ + (tkStubsPtr->tk_CanvasEventuallyRedraw) /* 8 */ +#define Tk_CanvasGetCoord \ + (tkStubsPtr->tk_CanvasGetCoord) /* 9 */ +#define Tk_CanvasGetTextInfo \ + (tkStubsPtr->tk_CanvasGetTextInfo) /* 10 */ +#define Tk_CanvasPsBitmap \ + (tkStubsPtr->tk_CanvasPsBitmap) /* 11 */ +#define Tk_CanvasPsColor \ + (tkStubsPtr->tk_CanvasPsColor) /* 12 */ +#define Tk_CanvasPsFont \ + (tkStubsPtr->tk_CanvasPsFont) /* 13 */ +#define Tk_CanvasPsPath \ + (tkStubsPtr->tk_CanvasPsPath) /* 14 */ +#define Tk_CanvasPsStipple \ + (tkStubsPtr->tk_CanvasPsStipple) /* 15 */ +#define Tk_CanvasPsY \ + (tkStubsPtr->tk_CanvasPsY) /* 16 */ +#define Tk_CanvasSetStippleOrigin \ + (tkStubsPtr->tk_CanvasSetStippleOrigin) /* 17 */ +#define Tk_CanvasTagsParseProc \ + (tkStubsPtr->tk_CanvasTagsParseProc) /* 18 */ +#define Tk_CanvasTagsPrintProc \ + (tkStubsPtr->tk_CanvasTagsPrintProc) /* 19 */ +#define Tk_CanvasTkwin \ + (tkStubsPtr->tk_CanvasTkwin) /* 20 */ +#define Tk_CanvasWindowCoords \ + (tkStubsPtr->tk_CanvasWindowCoords) /* 21 */ +#define Tk_ChangeWindowAttributes \ + (tkStubsPtr->tk_ChangeWindowAttributes) /* 22 */ +#define Tk_CharBbox \ + (tkStubsPtr->tk_CharBbox) /* 23 */ +#define Tk_ClearSelection \ + (tkStubsPtr->tk_ClearSelection) /* 24 */ +#define Tk_ClipboardAppend \ + (tkStubsPtr->tk_ClipboardAppend) /* 25 */ +#define Tk_ClipboardClear \ + (tkStubsPtr->tk_ClipboardClear) /* 26 */ +#define Tk_ConfigureInfo \ + (tkStubsPtr->tk_ConfigureInfo) /* 27 */ +#define Tk_ConfigureValue \ + (tkStubsPtr->tk_ConfigureValue) /* 28 */ +#define Tk_ConfigureWidget \ + (tkStubsPtr->tk_ConfigureWidget) /* 29 */ +#define Tk_ConfigureWindow \ + (tkStubsPtr->tk_ConfigureWindow) /* 30 */ +#define Tk_ComputeTextLayout \ + (tkStubsPtr->tk_ComputeTextLayout) /* 31 */ +#define Tk_CoordsToWindow \ + (tkStubsPtr->tk_CoordsToWindow) /* 32 */ +#define Tk_CreateBinding \ + (tkStubsPtr->tk_CreateBinding) /* 33 */ +#define Tk_CreateBindingTable \ + (tkStubsPtr->tk_CreateBindingTable) /* 34 */ +#define Tk_CreateErrorHandler \ + (tkStubsPtr->tk_CreateErrorHandler) /* 35 */ +#define Tk_CreateEventHandler \ + (tkStubsPtr->tk_CreateEventHandler) /* 36 */ +#define Tk_CreateGenericHandler \ + (tkStubsPtr->tk_CreateGenericHandler) /* 37 */ +#define Tk_CreateImageType \ + (tkStubsPtr->tk_CreateImageType) /* 38 */ +#define Tk_CreateItemType \ + (tkStubsPtr->tk_CreateItemType) /* 39 */ +#define Tk_CreatePhotoImageFormat \ + (tkStubsPtr->tk_CreatePhotoImageFormat) /* 40 */ +#define Tk_CreateSelHandler \ + (tkStubsPtr->tk_CreateSelHandler) /* 41 */ +#define Tk_CreateWindow \ + (tkStubsPtr->tk_CreateWindow) /* 42 */ +#define Tk_CreateWindowFromPath \ + (tkStubsPtr->tk_CreateWindowFromPath) /* 43 */ +#define Tk_DefineBitmap \ + (tkStubsPtr->tk_DefineBitmap) /* 44 */ +#define Tk_DefineCursor \ + (tkStubsPtr->tk_DefineCursor) /* 45 */ +#define Tk_DeleteAllBindings \ + (tkStubsPtr->tk_DeleteAllBindings) /* 46 */ +#define Tk_DeleteBinding \ + (tkStubsPtr->tk_DeleteBinding) /* 47 */ +#define Tk_DeleteBindingTable \ + (tkStubsPtr->tk_DeleteBindingTable) /* 48 */ +#define Tk_DeleteErrorHandler \ + (tkStubsPtr->tk_DeleteErrorHandler) /* 49 */ +#define Tk_DeleteEventHandler \ + (tkStubsPtr->tk_DeleteEventHandler) /* 50 */ +#define Tk_DeleteGenericHandler \ + (tkStubsPtr->tk_DeleteGenericHandler) /* 51 */ +#define Tk_DeleteImage \ + (tkStubsPtr->tk_DeleteImage) /* 52 */ +#define Tk_DeleteSelHandler \ + (tkStubsPtr->tk_DeleteSelHandler) /* 53 */ +#define Tk_DestroyWindow \ + (tkStubsPtr->tk_DestroyWindow) /* 54 */ +#define Tk_DisplayName \ + (tkStubsPtr->tk_DisplayName) /* 55 */ +#define Tk_DistanceToTextLayout \ + (tkStubsPtr->tk_DistanceToTextLayout) /* 56 */ +#define Tk_Draw3DPolygon \ + (tkStubsPtr->tk_Draw3DPolygon) /* 57 */ +#define Tk_Draw3DRectangle \ + (tkStubsPtr->tk_Draw3DRectangle) /* 58 */ +#define Tk_DrawChars \ + (tkStubsPtr->tk_DrawChars) /* 59 */ +#define Tk_DrawFocusHighlight \ + (tkStubsPtr->tk_DrawFocusHighlight) /* 60 */ +#define Tk_DrawTextLayout \ + (tkStubsPtr->tk_DrawTextLayout) /* 61 */ +#define Tk_Fill3DPolygon \ + (tkStubsPtr->tk_Fill3DPolygon) /* 62 */ +#define Tk_Fill3DRectangle \ + (tkStubsPtr->tk_Fill3DRectangle) /* 63 */ +#define Tk_FindPhoto \ + (tkStubsPtr->tk_FindPhoto) /* 64 */ +#define Tk_FontId \ + (tkStubsPtr->tk_FontId) /* 65 */ +#define Tk_Free3DBorder \ + (tkStubsPtr->tk_Free3DBorder) /* 66 */ +#define Tk_FreeBitmap \ + (tkStubsPtr->tk_FreeBitmap) /* 67 */ +#define Tk_FreeColor \ + (tkStubsPtr->tk_FreeColor) /* 68 */ +#define Tk_FreeColormap \ + (tkStubsPtr->tk_FreeColormap) /* 69 */ +#define Tk_FreeCursor \ + (tkStubsPtr->tk_FreeCursor) /* 70 */ +#define Tk_FreeFont \ + (tkStubsPtr->tk_FreeFont) /* 71 */ +#define Tk_FreeGC \ + (tkStubsPtr->tk_FreeGC) /* 72 */ +#define Tk_FreeImage \ + (tkStubsPtr->tk_FreeImage) /* 73 */ +#define Tk_FreeOptions \ + (tkStubsPtr->tk_FreeOptions) /* 74 */ +#define Tk_FreePixmap \ + (tkStubsPtr->tk_FreePixmap) /* 75 */ +#define Tk_FreeTextLayout \ + (tkStubsPtr->tk_FreeTextLayout) /* 76 */ +#define Tk_FreeXId \ + (tkStubsPtr->tk_FreeXId) /* 77 */ +#define Tk_GCForColor \ + (tkStubsPtr->tk_GCForColor) /* 78 */ +#define Tk_GeometryRequest \ + (tkStubsPtr->tk_GeometryRequest) /* 79 */ +#define Tk_Get3DBorder \ + (tkStubsPtr->tk_Get3DBorder) /* 80 */ +#define Tk_GetAllBindings \ + (tkStubsPtr->tk_GetAllBindings) /* 81 */ +#define Tk_GetAnchor \ + (tkStubsPtr->tk_GetAnchor) /* 82 */ +#define Tk_GetAtomName \ + (tkStubsPtr->tk_GetAtomName) /* 83 */ +#define Tk_GetBinding \ + (tkStubsPtr->tk_GetBinding) /* 84 */ +#define Tk_GetBitmap \ + (tkStubsPtr->tk_GetBitmap) /* 85 */ +#define Tk_GetBitmapFromData \ + (tkStubsPtr->tk_GetBitmapFromData) /* 86 */ +#define Tk_GetCapStyle \ + (tkStubsPtr->tk_GetCapStyle) /* 87 */ +#define Tk_GetColor \ + (tkStubsPtr->tk_GetColor) /* 88 */ +#define Tk_GetColorByValue \ + (tkStubsPtr->tk_GetColorByValue) /* 89 */ +#define Tk_GetColormap \ + (tkStubsPtr->tk_GetColormap) /* 90 */ +#define Tk_GetCursor \ + (tkStubsPtr->tk_GetCursor) /* 91 */ +#define Tk_GetCursorFromData \ + (tkStubsPtr->tk_GetCursorFromData) /* 92 */ +#define Tk_GetFont \ + (tkStubsPtr->tk_GetFont) /* 93 */ +#define Tk_GetFontFromObj \ + (tkStubsPtr->tk_GetFontFromObj) /* 94 */ +#define Tk_GetFontMetrics \ + (tkStubsPtr->tk_GetFontMetrics) /* 95 */ +#define Tk_GetGC \ + (tkStubsPtr->tk_GetGC) /* 96 */ +#define Tk_GetImage \ + (tkStubsPtr->tk_GetImage) /* 97 */ +#define Tk_GetImageMasterData \ + (tkStubsPtr->tk_GetImageMasterData) /* 98 */ +#define Tk_GetItemTypes \ + (tkStubsPtr->tk_GetItemTypes) /* 99 */ +#define Tk_GetJoinStyle \ + (tkStubsPtr->tk_GetJoinStyle) /* 100 */ +#define Tk_GetJustify \ + (tkStubsPtr->tk_GetJustify) /* 101 */ +#define Tk_GetNumMainWindows \ + (tkStubsPtr->tk_GetNumMainWindows) /* 102 */ +#define Tk_GetOption \ + (tkStubsPtr->tk_GetOption) /* 103 */ +#define Tk_GetPixels \ + (tkStubsPtr->tk_GetPixels) /* 104 */ +#define Tk_GetPixmap \ + (tkStubsPtr->tk_GetPixmap) /* 105 */ +#define Tk_GetRelief \ + (tkStubsPtr->tk_GetRelief) /* 106 */ +#define Tk_GetRootCoords \ + (tkStubsPtr->tk_GetRootCoords) /* 107 */ +#define Tk_GetScrollInfo \ + (tkStubsPtr->tk_GetScrollInfo) /* 108 */ +#define Tk_GetScreenMM \ + (tkStubsPtr->tk_GetScreenMM) /* 109 */ +#define Tk_GetSelection \ + (tkStubsPtr->tk_GetSelection) /* 110 */ +#define Tk_GetUid \ + (tkStubsPtr->tk_GetUid) /* 111 */ +#define Tk_GetVisual \ + (tkStubsPtr->tk_GetVisual) /* 112 */ +#define Tk_GetVRootGeometry \ + (tkStubsPtr->tk_GetVRootGeometry) /* 113 */ +#define Tk_Grab \ + (tkStubsPtr->tk_Grab) /* 114 */ +#define Tk_HandleEvent \ + (tkStubsPtr->tk_HandleEvent) /* 115 */ +#define Tk_IdToWindow \ + (tkStubsPtr->tk_IdToWindow) /* 116 */ +#define Tk_ImageChanged \ + (tkStubsPtr->tk_ImageChanged) /* 117 */ +#define Tk_Init \ + (tkStubsPtr->tk_Init) /* 118 */ +#define Tk_InternAtom \ + (tkStubsPtr->tk_InternAtom) /* 119 */ +#define Tk_IntersectTextLayout \ + (tkStubsPtr->tk_IntersectTextLayout) /* 120 */ +#define Tk_MaintainGeometry \ + (tkStubsPtr->tk_MaintainGeometry) /* 121 */ +#define Tk_MainWindow \ + (tkStubsPtr->tk_MainWindow) /* 122 */ +#define Tk_MakeWindowExist \ + (tkStubsPtr->tk_MakeWindowExist) /* 123 */ +#define Tk_ManageGeometry \ + (tkStubsPtr->tk_ManageGeometry) /* 124 */ +#define Tk_MapWindow \ + (tkStubsPtr->tk_MapWindow) /* 125 */ +#define Tk_MeasureChars \ + (tkStubsPtr->tk_MeasureChars) /* 126 */ +#define Tk_MoveResizeWindow \ + (tkStubsPtr->tk_MoveResizeWindow) /* 127 */ +#define Tk_MoveWindow \ + (tkStubsPtr->tk_MoveWindow) /* 128 */ +#define Tk_MoveToplevelWindow \ + (tkStubsPtr->tk_MoveToplevelWindow) /* 129 */ +#define Tk_NameOf3DBorder \ + (tkStubsPtr->tk_NameOf3DBorder) /* 130 */ +#define Tk_NameOfAnchor \ + (tkStubsPtr->tk_NameOfAnchor) /* 131 */ +#define Tk_NameOfBitmap \ + (tkStubsPtr->tk_NameOfBitmap) /* 132 */ +#define Tk_NameOfCapStyle \ + (tkStubsPtr->tk_NameOfCapStyle) /* 133 */ +#define Tk_NameOfColor \ + (tkStubsPtr->tk_NameOfColor) /* 134 */ +#define Tk_NameOfCursor \ + (tkStubsPtr->tk_NameOfCursor) /* 135 */ +#define Tk_NameOfFont \ + (tkStubsPtr->tk_NameOfFont) /* 136 */ +#define Tk_NameOfImage \ + (tkStubsPtr->tk_NameOfImage) /* 137 */ +#define Tk_NameOfJoinStyle \ + (tkStubsPtr->tk_NameOfJoinStyle) /* 138 */ +#define Tk_NameOfJustify \ + (tkStubsPtr->tk_NameOfJustify) /* 139 */ +#define Tk_NameOfRelief \ + (tkStubsPtr->tk_NameOfRelief) /* 140 */ +#define Tk_NameToWindow \ + (tkStubsPtr->tk_NameToWindow) /* 141 */ +#define Tk_OwnSelection \ + (tkStubsPtr->tk_OwnSelection) /* 142 */ +#define Tk_ParseArgv \ + (tkStubsPtr->tk_ParseArgv) /* 143 */ +#define Tk_PhotoPutBlock_NoComposite \ + (tkStubsPtr->tk_PhotoPutBlock_NoComposite) /* 144 */ +#define Tk_PhotoPutZoomedBlock_NoComposite \ + (tkStubsPtr->tk_PhotoPutZoomedBlock_NoComposite) /* 145 */ +#define Tk_PhotoGetImage \ + (tkStubsPtr->tk_PhotoGetImage) /* 146 */ +#define Tk_PhotoBlank \ + (tkStubsPtr->tk_PhotoBlank) /* 147 */ +#define Tk_PhotoExpand_Panic \ + (tkStubsPtr->tk_PhotoExpand_Panic) /* 148 */ +#define Tk_PhotoGetSize \ + (tkStubsPtr->tk_PhotoGetSize) /* 149 */ +#define Tk_PhotoSetSize_Panic \ + (tkStubsPtr->tk_PhotoSetSize_Panic) /* 150 */ +#define Tk_PointToChar \ + (tkStubsPtr->tk_PointToChar) /* 151 */ +#define Tk_PostscriptFontName \ + (tkStubsPtr->tk_PostscriptFontName) /* 152 */ +#define Tk_PreserveColormap \ + (tkStubsPtr->tk_PreserveColormap) /* 153 */ +#define Tk_QueueWindowEvent \ + (tkStubsPtr->tk_QueueWindowEvent) /* 154 */ +#define Tk_RedrawImage \ + (tkStubsPtr->tk_RedrawImage) /* 155 */ +#define Tk_ResizeWindow \ + (tkStubsPtr->tk_ResizeWindow) /* 156 */ +#define Tk_RestackWindow \ + (tkStubsPtr->tk_RestackWindow) /* 157 */ +#define Tk_RestrictEvents \ + (tkStubsPtr->tk_RestrictEvents) /* 158 */ +#define Tk_SafeInit \ + (tkStubsPtr->tk_SafeInit) /* 159 */ +#define Tk_SetAppName \ + (tkStubsPtr->tk_SetAppName) /* 160 */ +#define Tk_SetBackgroundFromBorder \ + (tkStubsPtr->tk_SetBackgroundFromBorder) /* 161 */ +#define Tk_SetClass \ + (tkStubsPtr->tk_SetClass) /* 162 */ +#define Tk_SetGrid \ + (tkStubsPtr->tk_SetGrid) /* 163 */ +#define Tk_SetInternalBorder \ + (tkStubsPtr->tk_SetInternalBorder) /* 164 */ +#define Tk_SetWindowBackground \ + (tkStubsPtr->tk_SetWindowBackground) /* 165 */ +#define Tk_SetWindowBackgroundPixmap \ + (tkStubsPtr->tk_SetWindowBackgroundPixmap) /* 166 */ +#define Tk_SetWindowBorder \ + (tkStubsPtr->tk_SetWindowBorder) /* 167 */ +#define Tk_SetWindowBorderWidth \ + (tkStubsPtr->tk_SetWindowBorderWidth) /* 168 */ +#define Tk_SetWindowBorderPixmap \ + (tkStubsPtr->tk_SetWindowBorderPixmap) /* 169 */ +#define Tk_SetWindowColormap \ + (tkStubsPtr->tk_SetWindowColormap) /* 170 */ +#define Tk_SetWindowVisual \ + (tkStubsPtr->tk_SetWindowVisual) /* 171 */ +#define Tk_SizeOfBitmap \ + (tkStubsPtr->tk_SizeOfBitmap) /* 172 */ +#define Tk_SizeOfImage \ + (tkStubsPtr->tk_SizeOfImage) /* 173 */ +#define Tk_StrictMotif \ + (tkStubsPtr->tk_StrictMotif) /* 174 */ +#define Tk_TextLayoutToPostscript \ + (tkStubsPtr->tk_TextLayoutToPostscript) /* 175 */ +#define Tk_TextWidth \ + (tkStubsPtr->tk_TextWidth) /* 176 */ +#define Tk_UndefineCursor \ + (tkStubsPtr->tk_UndefineCursor) /* 177 */ +#define Tk_UnderlineChars \ + (tkStubsPtr->tk_UnderlineChars) /* 178 */ +#define Tk_UnderlineTextLayout \ + (tkStubsPtr->tk_UnderlineTextLayout) /* 179 */ +#define Tk_Ungrab \ + (tkStubsPtr->tk_Ungrab) /* 180 */ +#define Tk_UnmaintainGeometry \ + (tkStubsPtr->tk_UnmaintainGeometry) /* 181 */ +#define Tk_UnmapWindow \ + (tkStubsPtr->tk_UnmapWindow) /* 182 */ +#define Tk_UnsetGrid \ + (tkStubsPtr->tk_UnsetGrid) /* 183 */ +#define Tk_UpdatePointer \ + (tkStubsPtr->tk_UpdatePointer) /* 184 */ +#define Tk_AllocBitmapFromObj \ + (tkStubsPtr->tk_AllocBitmapFromObj) /* 185 */ +#define Tk_Alloc3DBorderFromObj \ + (tkStubsPtr->tk_Alloc3DBorderFromObj) /* 186 */ +#define Tk_AllocColorFromObj \ + (tkStubsPtr->tk_AllocColorFromObj) /* 187 */ +#define Tk_AllocCursorFromObj \ + (tkStubsPtr->tk_AllocCursorFromObj) /* 188 */ +#define Tk_AllocFontFromObj \ + (tkStubsPtr->tk_AllocFontFromObj) /* 189 */ +#define Tk_CreateOptionTable \ + (tkStubsPtr->tk_CreateOptionTable) /* 190 */ +#define Tk_DeleteOptionTable \ + (tkStubsPtr->tk_DeleteOptionTable) /* 191 */ +#define Tk_Free3DBorderFromObj \ + (tkStubsPtr->tk_Free3DBorderFromObj) /* 192 */ +#define Tk_FreeBitmapFromObj \ + (tkStubsPtr->tk_FreeBitmapFromObj) /* 193 */ +#define Tk_FreeColorFromObj \ + (tkStubsPtr->tk_FreeColorFromObj) /* 194 */ +#define Tk_FreeConfigOptions \ + (tkStubsPtr->tk_FreeConfigOptions) /* 195 */ +#define Tk_FreeSavedOptions \ + (tkStubsPtr->tk_FreeSavedOptions) /* 196 */ +#define Tk_FreeCursorFromObj \ + (tkStubsPtr->tk_FreeCursorFromObj) /* 197 */ +#define Tk_FreeFontFromObj \ + (tkStubsPtr->tk_FreeFontFromObj) /* 198 */ +#define Tk_Get3DBorderFromObj \ + (tkStubsPtr->tk_Get3DBorderFromObj) /* 199 */ +#define Tk_GetAnchorFromObj \ + (tkStubsPtr->tk_GetAnchorFromObj) /* 200 */ +#define Tk_GetBitmapFromObj \ + (tkStubsPtr->tk_GetBitmapFromObj) /* 201 */ +#define Tk_GetColorFromObj \ + (tkStubsPtr->tk_GetColorFromObj) /* 202 */ +#define Tk_GetCursorFromObj \ + (tkStubsPtr->tk_GetCursorFromObj) /* 203 */ +#define Tk_GetOptionInfo \ + (tkStubsPtr->tk_GetOptionInfo) /* 204 */ +#define Tk_GetOptionValue \ + (tkStubsPtr->tk_GetOptionValue) /* 205 */ +#define Tk_GetJustifyFromObj \ + (tkStubsPtr->tk_GetJustifyFromObj) /* 206 */ +#define Tk_GetMMFromObj \ + (tkStubsPtr->tk_GetMMFromObj) /* 207 */ +#define Tk_GetPixelsFromObj \ + (tkStubsPtr->tk_GetPixelsFromObj) /* 208 */ +#define Tk_GetReliefFromObj \ + (tkStubsPtr->tk_GetReliefFromObj) /* 209 */ +#define Tk_GetScrollInfoObj \ + (tkStubsPtr->tk_GetScrollInfoObj) /* 210 */ +#define Tk_InitOptions \ + (tkStubsPtr->tk_InitOptions) /* 211 */ +#define Tk_MainEx \ + (tkStubsPtr->tk_MainEx) /* 212 */ +#define Tk_RestoreSavedOptions \ + (tkStubsPtr->tk_RestoreSavedOptions) /* 213 */ +#define Tk_SetOptions \ + (tkStubsPtr->tk_SetOptions) /* 214 */ +#define Tk_InitConsoleChannels \ + (tkStubsPtr->tk_InitConsoleChannels) /* 215 */ +#define Tk_CreateConsoleWindow \ + (tkStubsPtr->tk_CreateConsoleWindow) /* 216 */ +#define Tk_CreateSmoothMethod \ + (tkStubsPtr->tk_CreateSmoothMethod) /* 217 */ +/* Slot 218 is reserved */ +/* Slot 219 is reserved */ +#define Tk_GetDash \ + (tkStubsPtr->tk_GetDash) /* 220 */ +#define Tk_CreateOutline \ + (tkStubsPtr->tk_CreateOutline) /* 221 */ +#define Tk_DeleteOutline \ + (tkStubsPtr->tk_DeleteOutline) /* 222 */ +#define Tk_ConfigOutlineGC \ + (tkStubsPtr->tk_ConfigOutlineGC) /* 223 */ +#define Tk_ChangeOutlineGC \ + (tkStubsPtr->tk_ChangeOutlineGC) /* 224 */ +#define Tk_ResetOutlineGC \ + (tkStubsPtr->tk_ResetOutlineGC) /* 225 */ +#define Tk_CanvasPsOutline \ + (tkStubsPtr->tk_CanvasPsOutline) /* 226 */ +#define Tk_SetTSOrigin \ + (tkStubsPtr->tk_SetTSOrigin) /* 227 */ +#define Tk_CanvasGetCoordFromObj \ + (tkStubsPtr->tk_CanvasGetCoordFromObj) /* 228 */ +#define Tk_CanvasSetOffset \ + (tkStubsPtr->tk_CanvasSetOffset) /* 229 */ +#define Tk_DitherPhoto \ + (tkStubsPtr->tk_DitherPhoto) /* 230 */ +#define Tk_PostscriptBitmap \ + (tkStubsPtr->tk_PostscriptBitmap) /* 231 */ +#define Tk_PostscriptColor \ + (tkStubsPtr->tk_PostscriptColor) /* 232 */ +#define Tk_PostscriptFont \ + (tkStubsPtr->tk_PostscriptFont) /* 233 */ +#define Tk_PostscriptImage \ + (tkStubsPtr->tk_PostscriptImage) /* 234 */ +#define Tk_PostscriptPath \ + (tkStubsPtr->tk_PostscriptPath) /* 235 */ +#define Tk_PostscriptStipple \ + (tkStubsPtr->tk_PostscriptStipple) /* 236 */ +#define Tk_PostscriptY \ + (tkStubsPtr->tk_PostscriptY) /* 237 */ +#define Tk_PostscriptPhoto \ + (tkStubsPtr->tk_PostscriptPhoto) /* 238 */ +#define Tk_CreateClientMessageHandler \ + (tkStubsPtr->tk_CreateClientMessageHandler) /* 239 */ +#define Tk_DeleteClientMessageHandler \ + (tkStubsPtr->tk_DeleteClientMessageHandler) /* 240 */ +#define Tk_CreateAnonymousWindow \ + (tkStubsPtr->tk_CreateAnonymousWindow) /* 241 */ +#define Tk_SetClassProcs \ + (tkStubsPtr->tk_SetClassProcs) /* 242 */ +#define Tk_SetInternalBorderEx \ + (tkStubsPtr->tk_SetInternalBorderEx) /* 243 */ +#define Tk_SetMinimumRequestSize \ + (tkStubsPtr->tk_SetMinimumRequestSize) /* 244 */ +#define Tk_SetCaretPos \ + (tkStubsPtr->tk_SetCaretPos) /* 245 */ +#define Tk_PhotoPutBlock_Panic \ + (tkStubsPtr->tk_PhotoPutBlock_Panic) /* 246 */ +#define Tk_PhotoPutZoomedBlock_Panic \ + (tkStubsPtr->tk_PhotoPutZoomedBlock_Panic) /* 247 */ +#define Tk_CollapseMotionEvents \ + (tkStubsPtr->tk_CollapseMotionEvents) /* 248 */ +#define Tk_RegisterStyleEngine \ + (tkStubsPtr->tk_RegisterStyleEngine) /* 249 */ +#define Tk_GetStyleEngine \ + (tkStubsPtr->tk_GetStyleEngine) /* 250 */ +#define Tk_RegisterStyledElement \ + (tkStubsPtr->tk_RegisterStyledElement) /* 251 */ +#define Tk_GetElementId \ + (tkStubsPtr->tk_GetElementId) /* 252 */ +#define Tk_CreateStyle \ + (tkStubsPtr->tk_CreateStyle) /* 253 */ +#define Tk_GetStyle \ + (tkStubsPtr->tk_GetStyle) /* 254 */ +#define Tk_FreeStyle \ + (tkStubsPtr->tk_FreeStyle) /* 255 */ +#define Tk_NameOfStyle \ + (tkStubsPtr->tk_NameOfStyle) /* 256 */ +#define Tk_AllocStyleFromObj \ + (tkStubsPtr->tk_AllocStyleFromObj) /* 257 */ +#define Tk_GetStyleFromObj \ + (tkStubsPtr->tk_GetStyleFromObj) /* 258 */ +#define Tk_FreeStyleFromObj \ + (tkStubsPtr->tk_FreeStyleFromObj) /* 259 */ +#define Tk_GetStyledElement \ + (tkStubsPtr->tk_GetStyledElement) /* 260 */ +#define Tk_GetElementSize \ + (tkStubsPtr->tk_GetElementSize) /* 261 */ +#define Tk_GetElementBox \ + (tkStubsPtr->tk_GetElementBox) /* 262 */ +#define Tk_GetElementBorderWidth \ + (tkStubsPtr->tk_GetElementBorderWidth) /* 263 */ +#define Tk_DrawElement \ + (tkStubsPtr->tk_DrawElement) /* 264 */ +#define Tk_PhotoExpand \ + (tkStubsPtr->tk_PhotoExpand) /* 265 */ +#define Tk_PhotoPutBlock \ + (tkStubsPtr->tk_PhotoPutBlock) /* 266 */ +#define Tk_PhotoPutZoomedBlock \ + (tkStubsPtr->tk_PhotoPutZoomedBlock) /* 267 */ +#define Tk_PhotoSetSize \ + (tkStubsPtr->tk_PhotoSetSize) /* 268 */ +#define Tk_GetUserInactiveTime \ + (tkStubsPtr->tk_GetUserInactiveTime) /* 269 */ +#define Tk_ResetUserInactiveTime \ + (tkStubsPtr->tk_ResetUserInactiveTime) /* 270 */ +#define Tk_Interp \ + (tkStubsPtr->tk_Interp) /* 271 */ +#define Tk_CreateOldImageType \ + (tkStubsPtr->tk_CreateOldImageType) /* 272 */ +#define Tk_CreateOldPhotoImageFormat \ + (tkStubsPtr->tk_CreateOldPhotoImageFormat) /* 273 */ + +#endif /* defined(USE_TK_STUBS) */ + +/* !END!: Do not edit above this line. */ + +/* Functions that don't belong in the stub table */ +#undef Tk_MainEx +#undef Tk_Init +#undef Tk_SafeInit +#undef Tk_CreateConsoleWindow + +#if defined(_WIN32) && defined(UNICODE) +# define Tk_MainEx Tk_MainExW + EXTERN void Tk_MainExW(int argc, wchar_t **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tkPlatDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tkPlatDecls.h new file mode 100644 index 00000000..1e69c883 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.6/tkPlatDecls.h @@ -0,0 +1,176 @@ +/* + * tkPlatDecls.h -- + * + * Declarations of functions in the platform-specific 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 _TKPLATDECLS +#define _TKPLATDECLS + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#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/tk.decls script. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +/* 0 */ +EXTERN Window Tk_AttachHWND(Tk_Window tkwin, HWND hwnd); +/* 1 */ +EXTERN HINSTANCE Tk_GetHINSTANCE(void); +/* 2 */ +EXTERN HWND Tk_GetHWND(Window window); +/* 3 */ +EXTERN Tk_Window Tk_HWNDToWindow(HWND hwnd); +/* 4 */ +EXTERN void Tk_PointerEvent(HWND hwnd, int x, int y); +/* 5 */ +EXTERN int Tk_TranslateWinEvent(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam, + LRESULT *result); +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ +/* 0 */ +EXTERN void Tk_MacOSXSetEmbedHandler( + Tk_MacOSXEmbedRegisterWinProc *registerWinProcPtr, + Tk_MacOSXEmbedGetGrafPortProc *getPortProcPtr, + Tk_MacOSXEmbedMakeContainerExistProc *containerExistProcPtr, + Tk_MacOSXEmbedGetClipProc *getClipProc, + Tk_MacOSXEmbedGetOffsetInParentProc *getOffsetProc); +/* 1 */ +EXTERN void Tk_MacOSXTurnOffMenus(void); +/* 2 */ +EXTERN void Tk_MacOSXTkOwnsCursor(int tkOwnsIt); +/* 3 */ +EXTERN void TkMacOSXInitMenus(Tcl_Interp *interp); +/* 4 */ +EXTERN void TkMacOSXInitAppleEvents(Tcl_Interp *interp); +/* 5 */ +EXTERN void TkGenWMConfigureEvent(Tk_Window tkwin, int x, int y, + int width, int height, int flags); +/* 6 */ +EXTERN void TkMacOSXInvalClipRgns(Tk_Window tkwin); +/* 7 */ +EXTERN void * TkMacOSXGetDrawablePort(Drawable drawable); +/* 8 */ +EXTERN void * TkMacOSXGetRootControl(Drawable drawable); +/* 9 */ +EXTERN void Tk_MacOSXSetupTkNotifier(void); +/* 10 */ +EXTERN int Tk_MacOSXIsAppInFront(void); +#endif /* AQUA */ + +typedef struct TkPlatStubs { + int magic; + void *hooks; + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ + Window (*tk_AttachHWND) (Tk_Window tkwin, HWND hwnd); /* 0 */ + HINSTANCE (*tk_GetHINSTANCE) (void); /* 1 */ + HWND (*tk_GetHWND) (Window window); /* 2 */ + Tk_Window (*tk_HWNDToWindow) (HWND hwnd); /* 3 */ + void (*tk_PointerEvent) (HWND hwnd, int x, int y); /* 4 */ + int (*tk_TranslateWinEvent) (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); /* 5 */ +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ + void (*tk_MacOSXSetEmbedHandler) (Tk_MacOSXEmbedRegisterWinProc *registerWinProcPtr, Tk_MacOSXEmbedGetGrafPortProc *getPortProcPtr, Tk_MacOSXEmbedMakeContainerExistProc *containerExistProcPtr, Tk_MacOSXEmbedGetClipProc *getClipProc, Tk_MacOSXEmbedGetOffsetInParentProc *getOffsetProc); /* 0 */ + void (*tk_MacOSXTurnOffMenus) (void); /* 1 */ + void (*tk_MacOSXTkOwnsCursor) (int tkOwnsIt); /* 2 */ + void (*tkMacOSXInitMenus) (Tcl_Interp *interp); /* 3 */ + void (*tkMacOSXInitAppleEvents) (Tcl_Interp *interp); /* 4 */ + void (*tkGenWMConfigureEvent) (Tk_Window tkwin, int x, int y, int width, int height, int flags); /* 5 */ + void (*tkMacOSXInvalClipRgns) (Tk_Window tkwin); /* 6 */ + void * (*tkMacOSXGetDrawablePort) (Drawable drawable); /* 7 */ + void * (*tkMacOSXGetRootControl) (Drawable drawable); /* 8 */ + void (*tk_MacOSXSetupTkNotifier) (void); /* 9 */ + int (*tk_MacOSXIsAppInFront) (void); /* 10 */ +#endif /* AQUA */ +} TkPlatStubs; + +extern const TkPlatStubs *tkPlatStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) + +/* + * Inline function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +#define Tk_AttachHWND \ + (tkPlatStubsPtr->tk_AttachHWND) /* 0 */ +#define Tk_GetHINSTANCE \ + (tkPlatStubsPtr->tk_GetHINSTANCE) /* 1 */ +#define Tk_GetHWND \ + (tkPlatStubsPtr->tk_GetHWND) /* 2 */ +#define Tk_HWNDToWindow \ + (tkPlatStubsPtr->tk_HWNDToWindow) /* 3 */ +#define Tk_PointerEvent \ + (tkPlatStubsPtr->tk_PointerEvent) /* 4 */ +#define Tk_TranslateWinEvent \ + (tkPlatStubsPtr->tk_TranslateWinEvent) /* 5 */ +#endif /* WIN */ +#ifdef MAC_OSX_TK /* AQUA */ +#define Tk_MacOSXSetEmbedHandler \ + (tkPlatStubsPtr->tk_MacOSXSetEmbedHandler) /* 0 */ +#define Tk_MacOSXTurnOffMenus \ + (tkPlatStubsPtr->tk_MacOSXTurnOffMenus) /* 1 */ +#define Tk_MacOSXTkOwnsCursor \ + (tkPlatStubsPtr->tk_MacOSXTkOwnsCursor) /* 2 */ +#define TkMacOSXInitMenus \ + (tkPlatStubsPtr->tkMacOSXInitMenus) /* 3 */ +#define TkMacOSXInitAppleEvents \ + (tkPlatStubsPtr->tkMacOSXInitAppleEvents) /* 4 */ +#define TkGenWMConfigureEvent \ + (tkPlatStubsPtr->tkGenWMConfigureEvent) /* 5 */ +#define TkMacOSXInvalClipRgns \ + (tkPlatStubsPtr->tkMacOSXInvalClipRgns) /* 6 */ +#define TkMacOSXGetDrawablePort \ + (tkPlatStubsPtr->tkMacOSXGetDrawablePort) /* 7 */ +#define TkMacOSXGetRootControl \ + (tkPlatStubsPtr->tkMacOSXGetRootControl) /* 8 */ +#define Tk_MacOSXSetupTkNotifier \ + (tkPlatStubsPtr->tk_MacOSXSetupTkNotifier) /* 9 */ +#define Tk_MacOSXIsAppInFront \ + (tkPlatStubsPtr->tk_MacOSXIsAppInFront) /* 10 */ +#endif /* AQUA */ + +#endif /* defined(USE_TK_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#ifdef __cplusplus +} +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKPLATDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tcl.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tcl.h new file mode 100644 index 00000000..2f1f7935 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tcl.h @@ -0,0 +1,2710 @@ +/* + * 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 (1 LOC patch) + * unix/configure.ac (2 LOC Major, 2 LOC minor, 1 LOC patch) + * win/configure.ac (as above) + * win/tcl.m4 (not patchlevel) + * README (sections 0 and 2, with and without separator) + * macosx/Tcl-Common.xcconfig (not patchlevel) 1 LOC + * win/README (not patchlevel) (sections 0 and 2) + * unix/tcl.spec (1 LOC patch) + */ + +#if !defined(TCL_MAJOR_VERSION) +# define TCL_MAJOR_VERSION 8 +#endif +#if TCL_MAJOR_VERSION != 8 +# error "This header-file is for Tcl 8 only" +#endif +#define TCL_MINOR_VERSION 7 +#define TCL_RELEASE_LEVEL TCL_ALPHA_RELEASE +#define TCL_RELEASE_SERIAL 6 + +#define TCL_VERSION "8.7" +#define TCL_PATCH_LEVEL "8.7a6" + +#if !defined(TCL_NO_DEPRECATED) || defined(RC_INVOKED) +/* + *---------------------------------------------------------------------------- + * The following definitions set up the proper options for Windows compilers. + * We use this method because there is no autoconf equivalent. + */ + +#ifdef _WIN32 +# ifndef __WIN32__ +# define __WIN32__ +# endif +# ifndef WIN32 +# define WIN32 +# endif +#endif + +/* + * 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 + +#ifndef TCL_THREADS +# define TCL_THREADS 1 +#endif +#endif /* !TCL_NO_DEPRECATED */ + +/* + * 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 function + * declarations, that occur below, so block them out. + */ + +#ifndef RC_INVOKED + +/* + * Special macro to define mutexes. + */ + +#define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name; + +/* + * Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and + * SEEK_END, all #define'd by stdio.h . + * + * Also, many extensions need stdio.h, and they've grown accustomed to tcl.h + * providing it for them rather than #include-ing it themselves as they + * should, so also for their sake, we keep the #include to be consistent with + * prior Tcl releases. + */ + +#include +#include + +/* + *---------------------------------------------------------------------------- + * Support for functions with a variable number of arguments. + * + * The following TCL_VARARGS* macros are to support old extensions + * written for older versions of Tcl where the macros permitted + * support for the varargs.h system as well as stdarg.h . + * + * New code should just directly be written to use stdarg.h conventions. + */ + +#include +#ifndef TCL_NO_DEPRECATED +# 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) +#endif /* !TCL_NO_DEPRECATED */ +#if defined(__GNUC__) && (__GNUC__ > 2) +# if defined(_WIN32) && defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO +# define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__MINGW_PRINTF_FORMAT, a, b))) +# else +# define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b))) +# endif +# define TCL_NORETURN __attribute__ ((noreturn)) +# define TCL_NOINLINE __attribute__ ((noinline)) +# if defined(BUILD_tcl) || defined(BUILD_tk) +# define TCL_NORETURN1 __attribute__ ((noreturn)) +# else +# define TCL_NORETURN1 /* nothing */ +# endif +#else +# define TCL_FORMAT_PRINTF(a,b) +# if defined(_MSC_VER) +# define TCL_NORETURN _declspec(noreturn) +# define TCL_NOINLINE __declspec(noinline) +# else +# define TCL_NORETURN /* nothing */ +# define TCL_NOINLINE /* nothing */ +# endif +# define TCL_NORETURN1 /* nothing */ +#endif + +/* + * Allow a part of Tcl's API to be explicitly marked as deprecated. + * + * Used to make TIP 330/336 generate moans even if people use the + * compatibility macros. Change your code, guys! We won't support you forever. + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) +# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__ (msg))) +# else +# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__)) +# endif +#else +# define TCL_DEPRECATED_API(msg) /* nothing portable */ +#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. + * + * Note: when building static but linking dynamically to MSVCRT we must still + * correctly decorate the C library imported function. Use CRTIMPORT + * for this purpose. _DLL is defined by the compiler when linking to + * MSVCRT. + */ + +#ifdef _WIN32 +# ifdef STATIC_BUILD +# define DLLIMPORT +# define DLLEXPORT +# ifdef _DLL +# define CRTIMPORT __declspec(dllimport) +# else +# define CRTIMPORT +# endif +# else +# define DLLIMPORT __declspec(dllimport) +# define DLLEXPORT __declspec(dllexport) +# define CRTIMPORT __declspec(dllimport) +# endif +#else +# define DLLIMPORT +# if defined(__GNUC__) && __GNUC__ > 3 +# define DLLEXPORT __attribute__ ((visibility("default"))) +# else +# define DLLEXPORT +# endif +# define CRTIMPORT +#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 being 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 + +/* + * The following _ANSI_ARGS_ macro is to support old extensions + * written for older versions of Tcl where it permitted support + * for compilers written in the pre-prototype era of C. + * + * New code should use prototypes. + */ + +#ifndef TCL_NO_DEPRECATED +# undef _ANSI_ARGS_ +# define _ANSI_ARGS_(x) x + +/* + * Definitions that allow this header file to be used either with or without + * ANSI C features. + */ + +#ifndef INLINE +# define INLINE +#endif +#ifndef CONST +# define CONST const +#endif + +#endif /* !TCL_NO_DEPRECATED */ + +#ifndef CONST86 +# define CONST86 const +#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. + */ + +#ifndef TCL_NO_DEPRECATED +#if defined(_WIN32) +#ifndef VOID +#define VOID void +typedef char CHAR; +typedef short SHORT; +typedef long LONG; +#endif +#endif /* _WIN32 */ + +/* + * 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__ +# define VOID void +#endif +#endif /* !TCL_NO_DEPRECATED */ + +/* + * Miscellaneous declarations. + */ + +typedef void *ClientData; + +/* + * Darwin specific configure overrides (to support fat compiles, where + * configure runs only once for multiple architectures): + */ + +#ifdef __APPLE__ +# ifdef __LP64__ +# define TCL_WIDE_INT_IS_LONG 1 +# define TCL_CFG_DO64BIT 1 +# else /* !__LP64__ */ +# undef TCL_WIDE_INT_IS_LONG +# undef TCL_CFG_DO64BIT +# endif /* __LP64__ */ +# undef HAVE_STRUCT_STAT64 +#endif /* __APPLE__ */ + +/* Cross-compiling 32-bit on a 64-bit platform? Then our + * configure script does the wrong thing. Correct that here. + */ +#if defined(__GNUC__) && !defined(_WIN32) && !defined(__LP64__) +# undef TCL_WIDE_INT_IS_LONG +#endif + +/* + * 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 + * LP64 system such as modern Solaris or Linux ... not including Win64) + * 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)) + */ + +#if !defined(TCL_WIDE_INT_TYPE) && !defined(TCL_WIDE_INT_IS_LONG) && !defined(_WIN32) && !defined(__GNUC__) +/* + * Don't know what platform it is and configure hasn't discovered what is + * going on for us. Try to guess... + */ +# include +# if defined(LLONG_MAX) && (LLONG_MAX == LONG_MAX) +# define TCL_WIDE_INT_IS_LONG 1 +# endif +#endif + +#ifndef TCL_WIDE_INT_TYPE +# define TCL_WIDE_INT_TYPE long long +#endif /* !TCL_WIDE_INT_TYPE */ + +typedef TCL_WIDE_INT_TYPE Tcl_WideInt; +typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; + +#ifndef TCL_LL_MODIFIER +# if defined(_WIN32) && (!defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO) +# define TCL_LL_MODIFIER "I64" +# else +# define TCL_LL_MODIFIER "ll" +# endif +#endif /* !TCL_LL_MODIFIER */ +#ifndef TCL_Z_MODIFIER +# if defined(__GNUC__) && !defined(_WIN32) +# define TCL_Z_MODIFIER "z" +# elif defined(_WIN64) +# define TCL_Z_MODIFIER TCL_LL_MODIFIER +# else +# define TCL_Z_MODIFIER "" +# endif +#endif /* !TCL_Z_MODIFIER */ +#ifndef TCL_T_MODIFIER +# if defined(__GNUC__) && !defined(_WIN32) +# define TCL_T_MODIFIER "t" +# elif defined(_WIN64) +# define TCL_T_MODIFIER TCL_LL_MODIFIER +# else +# define TCL_T_MODIFIER TCL_Z_MODIFIER +# endif +#endif /* !TCL_T_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))) + +#if TCL_MAJOR_VERSION < 9 + typedef int Tcl_Size; +# define TCL_SIZE_MAX ((int)(((unsigned int)-1)>>1)) +# define TCL_SIZE_MODIFIER "" +#else + typedef ptrdiff_t Tcl_Size; +# define TCL_SIZE_MAX ((ptrdiff_t)(((size_t)-1)>>1)) +# define TCL_SIZE_MODIFIER TCL_T_MODIFIER +#endif /* TCL_MAJOR_VERSION */ + +#ifdef _WIN32 +# if TCL_MAJOR_VERSION > 8 || defined(_WIN64) || defined(_USE_64BIT_TIME_T) + typedef struct __stat64 Tcl_StatBuf; +# elif defined(_USE_32BIT_TIME_T) + typedef struct _stati64 Tcl_StatBuf; +# else + typedef struct _stat32i64 Tcl_StatBuf; +# endif +#elif defined(__CYGWIN__) + typedef struct { + unsigned 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 */ + unsigned 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; + } Tcl_StatBuf; +#elif defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__) \ + && (!defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64) \ + && (!defined(_TIME_BITS) || _TIME_BITS != 64) + typedef struct stat64 Tcl_StatBuf; +#else + typedef struct stat Tcl_StatBuf; +#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 function 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 functions 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 +#ifndef TCL_NO_DEPRECATED +{ + /* TIP #330: Strongly discourage extensions from using the string + * result. */ + char *resultDontUse; /* Don't use in extensions! */ + void (*freeProcDontUse) (char *); /* Don't use in extensions! */ + int errorLineDontUse; /* Don't use in extensions! */ +} +#endif /* !TCL_NO_DEPRECATED */ +Tcl_Interp; + +typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler; +typedef struct Tcl_Channel_ *Tcl_Channel; +typedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion; +typedef struct Tcl_Command_ *Tcl_Command; +typedef struct Tcl_Condition_ *Tcl_Condition; +typedef struct Tcl_Dict_ *Tcl_Dict; +typedef struct Tcl_EncodingState_ *Tcl_EncodingState; +typedef struct Tcl_Encoding_ *Tcl_Encoding; +typedef struct Tcl_Event Tcl_Event; +typedef struct Tcl_InterpState_ *Tcl_InterpState; +typedef struct Tcl_LoadHandle_ *Tcl_LoadHandle; +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_ZLibStream_ *Tcl_ZlibStream; + +/* + *---------------------------------------------------------------------------- + * Definition of the interface to functions implementing threads. A function + * 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) (void *clientData); +#else +typedef void (Tcl_ThreadCreateProc) (void *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. + */ + +#if defined _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_StringCaseMatch. + */ + +#define TCL_MATCH_NOCASE (1<<0) + +/* + * 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. */ + +/* + * 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 { +#if TCL_MAJOR_VERSION > 8 + Tcl_Size start; /* Character offset of first character in + * match. */ + Tcl_Size end; /* Character offset of first character after + * the match. */ +#else + long start; + long end; +#endif +} Tcl_RegExpIndices; + +typedef struct Tcl_RegExpInfo { + Tcl_Size nsubs; /* Number of subexpressions in the compiled + * expression. */ + Tcl_RegExpIndices *matches; /* Array of nsubs match offset pairs. */ +#if TCL_MAJOR_VERSION > 8 + Tcl_Size extendStart; /* The offset at which a subsequent match + * might begin. */ +#else + long extendStart; + long reserved; /* Reserved for later use. */ +#endif +} 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 functions + * Tcl_GetObjResult() or Tcl_GetStringResult() to read the interpreter's + * result. See the SetResult man page for details. Besides this result, the + * command function 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 function return; + * the interpreter's result contains the function'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 + +#ifndef TCL_NO_DEPRECATED +#define TCL_RESULT_SIZE 200 +#endif + +/* + *---------------------------------------------------------------------------- + * 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: + */ + +#ifndef TCL_NO_DEPRECATED +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; +#else +#define Tcl_ValueType void /* Just enough to prevent compilation error in Tcl */ +#define Tcl_Value void /* Just enough to prevent compilation error in Tcl */ +#endif + +/* + * Forward declaration of Tcl_Obj to prevent an error when the forward + * reference to Tcl_Obj is encountered in the function types declared below. + */ + +struct Tcl_Obj; + +/* + *---------------------------------------------------------------------------- + * Function types defined by Tcl: + */ + +typedef int (Tcl_AppInitProc) (Tcl_Interp *interp); +typedef int (Tcl_AsyncProc) (void *clientData, Tcl_Interp *interp, + int code); +typedef void (Tcl_ChannelProc) (void *clientData, int mask); +typedef void (Tcl_CloseProc) (void *data); +typedef void (Tcl_CmdDeleteProc) (void *clientData); +typedef int (Tcl_CmdProc) (void *clientData, Tcl_Interp *interp, + int argc, const char *argv[]); +typedef void (Tcl_CmdTraceProc) (void *clientData, Tcl_Interp *interp, + int level, char *command, Tcl_CmdProc *proc, + void *cmdClientData, int argc, const char *argv[]); +typedef int (Tcl_CmdObjTraceProc) (void *clientData, Tcl_Interp *interp, + int level, const char *command, Tcl_Command commandInfo, int objc, + struct Tcl_Obj *const *objv); +#define Tcl_CmdObjTraceProc2 Tcl_CmdObjTraceProc +typedef void (Tcl_CmdObjTraceDeleteProc) (void *clientData); +typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, + struct Tcl_Obj *dupPtr); +typedef int (Tcl_EncodingConvertProc) (void *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) (void *clientData); +typedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags); +typedef void (Tcl_EventCheckProc) (void *clientData, int flags); +typedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, void *clientData); +typedef void (Tcl_EventSetupProc) (void *clientData, int flags); +typedef void (Tcl_ExitProc) (void *clientData); +typedef void (Tcl_FileProc) (void *clientData, int mask); +typedef void (Tcl_FileFreeProc) (void *clientData); +typedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr); +typedef void (Tcl_FreeProc) (char *blockPtr); +typedef void (Tcl_IdleProc) (void *clientData); +typedef void (Tcl_InterpDeleteProc) (void *clientData, + Tcl_Interp *interp); +typedef int (Tcl_MathProc) (void *clientData, Tcl_Interp *interp, + Tcl_Value *args, Tcl_Value *resultPtr); +typedef void (Tcl_NamespaceDeleteProc) (void *clientData); +typedef int (Tcl_ObjCmdProc) (void *clientData, Tcl_Interp *interp, + int objc, struct Tcl_Obj *const *objv); +#define Tcl_ObjCmdProc2 Tcl_ObjCmdProc +typedef int (Tcl_LibraryInitProc) (Tcl_Interp *interp); +typedef int (Tcl_LibraryUnloadProc) (Tcl_Interp *interp, int flags); +typedef void (Tcl_PanicProc) (const char *format, ...); +typedef void (Tcl_TcpAcceptProc) (void *callbackData, Tcl_Channel chan, + char *address, int port); +typedef void (Tcl_TimerProc) (void *clientData); +typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr); +typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr); +typedef char * (Tcl_VarTraceProc) (void *clientData, Tcl_Interp *interp, + const char *part1, const char *part2, int flags); +typedef void (Tcl_CommandTraceProc) (void *clientData, Tcl_Interp *interp, + const char *oldName, const char *newName, int flags); +typedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc, + void *clientData); +typedef void (Tcl_DeleteFileHandlerProc) (int fd); +typedef void (Tcl_AlertNotifierProc) (void *clientData); +typedef void (Tcl_ServiceModeHookProc) (int mode); +typedef void *(Tcl_InitNotifierProc) (void); +typedef void (Tcl_FinalizeNotifierProc) (void *clientData); +typedef void (Tcl_MainLoopProc) (void); + +#ifndef TCL_NO_DEPRECATED +# define Tcl_PackageInitProc Tcl_LibraryInitProc +# define Tcl_PackageUnloadProc Tcl_LibraryUnloadProc +#endif + +/* + *---------------------------------------------------------------------------- + * The following structure represents a type of object, which is a particular + * internal representation for an object plus a set of functions that provide + * standard operations on objects of that type. + */ + +typedef struct Tcl_ObjType { + const 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; +#define TCL_OBJTYPE_V0 /* just empty */ + +/* + * The following structure stores an internal representation (internalrep) for + * a Tcl value. An internalrep is associated with an Tcl_ObjType when both + * are stored in the same Tcl_Obj. The routines of the Tcl_ObjType govern + * the handling of the internalrep. + */ + +typedef union Tcl_ObjInternalRep { /* The internal representation: */ + long longValue; /* - an long integer value. */ + double doubleValue; /* - a double-precision floating value. */ + void *otherValuePtr; /* - another, type-specific value, */ + /* not used internally any more. */ + Tcl_WideInt wideValue; /* - an integer value >= 64bits */ + struct { /* - internal rep as two pointers. */ + void *ptr1; + void *ptr2; + } twoPtrValue; + struct { /* - internal rep as a pointer and a long, */ + void *ptr; /* not used internally any more. */ + unsigned long value; + } ptrAndLongRep; +} Tcl_ObjInternalRep; + +/* + * 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 { + Tcl_Size 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. */ + Tcl_Size length; /* The number of bytes at *bytes, not + * including the terminating null. */ + const 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). */ + Tcl_ObjInternalRep internalRep; /* The internal representation: */ +} Tcl_Obj; + + +/* + *---------------------------------------------------------------------------- + * 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. + */ + +#ifndef TCL_NO_DEPRECATED +typedef struct Tcl_SavedResult { + char *result; + Tcl_FreeProc *freeProc; + Tcl_Obj *objResultPtr; + char *appendResult; + int appendAvl; + int appendUsed; + char resultSpace[200+1]; +} Tcl_SavedResult; +#endif + +/* + *---------------------------------------------------------------------------- + * 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 ::. */ + void *clientData; /* Arbitrary value associated with this + * namespace. */ + Tcl_NamespaceDeleteProc *deleteProc; + /* Function 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; + Tcl_Size dummy2; + void *dummy3; + void *dummy4; + void *dummy5; + Tcl_Size dummy6; + void *dummy7; + void *dummy8; + Tcl_Size 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 + * function while proc is a traditional Tcl argc/argv string-based function. + * 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 function was registered by + * Tcl_CreateObjCommand, and to 0 if a string-based function was registered by + * Tcl_CreateCommand. The other function is typically set to a compatibility + * wrapper that does string-to-object or object-to-string argument conversions + * then calls the other function. + */ + +typedef struct Tcl_CmdInfo { + int isNativeObjectProc; /* 1 if objProc was registered by a call to + * Tcl_CreateObjCommand; 2 if objProc was registered by + * a call to Tcl_CreateObjCommand2; 0 otherwise. + * Tcl_SetCmdInfo does not modify this field. */ + Tcl_ObjCmdProc *objProc; /* Command's object-based function. */ + void *objClientData; /* ClientData for object proc. */ + Tcl_CmdProc *proc; /* Command's string-based function. */ + void *clientData; /* ClientData for string proc. */ + Tcl_CmdDeleteProc *deleteProc; + /* Function to call when command is + * deleted. */ + void *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 + * TclRenameCommand or Tcl_Eval (of 'rename') + * to do that. */ + Tcl_ObjCmdProc2 *objProc2; /* Not used in Tcl 8.7. */ + void *objClientData2; /* Not used in Tcl 8.7. */ +} Tcl_CmdInfo; + +/* + *---------------------------------------------------------------------------- + * The structure defined below is used to hold dynamic strings. The only + * fields that clients should use are string and length, accessible via the + * macros Tcl_DStringValue and Tcl_DStringLength. + */ + +#define TCL_DSTRING_STATIC_SIZE 200 +typedef struct Tcl_DString { + char *string; /* Points to beginning of string: either + * staticSpace below or a malloced array. */ + Tcl_Size length; /* Number of non-NULL characters in the + * string. */ + Tcl_Size 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) +#ifndef TCL_NO_DEPRECATED +# define Tcl_DStringTrunc Tcl_DStringSetLength +#endif + +/* + * Definitions for the maximum number of digits of precision that may be + * produced by Tcl_PrintDouble, 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 (3*(int)sizeof(Tcl_WideInt)) + +/* + *---------------------------------------------------------------------------- + * Type values returned by Tcl_GetNumberFromObj + * TCL_NUMBER_INT Representation is a Tcl_WideInt + * TCL_NUMBER_BIG Representation is an mp_int + * TCL_NUMBER_DOUBLE Representation is a double + * TCL_NUMBER_NAN Value is NaN. + */ + +#define TCL_NUMBER_INT 2 +#define TCL_NUMBER_BIG 3 +#define TCL_NUMBER_DOUBLE 4 +#define TCL_NUMBER_NAN 5 + +/* + * Flag values passed to Tcl_ConvertElement. + * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to + * use backslash quoting instead. + * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It + * is safe to leave the hash unquoted when the element is not the first + * element of a list, and this flag can be used by the caller to indicate + * that condition. + */ + +#define TCL_DONT_USE_BRACES 1 +#define TCL_DONT_QUOTE_HASH 8 + +/* + * Flags that may be passed to Tcl_GetIndexFromObj. + * TCL_EXACT disallows abbreviated strings. + * TCL_NULL_OK allows the empty string or NULL to return TCL_OK. + * The returned value will be -1; + * TCL_INDEX_TEMP_TABLE disallows caching of lookups. A possible use case is + * a table that will not live long enough to make it worthwhile. + */ + +#define TCL_EXACT 1 +#define TCL_NULL_OK 32 +#define TCL_INDEX_TEMP_TABLE 64 + +/* + * Flags that may be passed to Tcl_UniCharToUtf. + * TCL_COMBINE Combine surrogates (default in Tcl 8.x) + */ + +#if TCL_MAJOR_VERSION > 8 +# define TCL_COMBINE 0x1000000 +#else +# define TCL_COMBINE 0 +#endif +/* + *---------------------------------------------------------------------------- + * Flag values passed to Tcl_RecordAndEval, Tcl_EvalObj, Tcl_EvalObjv. + * WARNING: these bit choices must not conflict with the bit choices for + * evalFlag bits in tclInt.h! + * + * Meanings: + * TCL_NO_EVAL: Just record this command + * TCL_EVAL_GLOBAL: Execute script in global namespace + * TCL_EVAL_DIRECT: Do not compile this script + * TCL_EVAL_INVOKE: Magical Tcl_EvalObjv mode for aliases/ensembles + * o Run in iPtr->lookupNsPtr or global namespace + * o Cut out of error traces + * o Don't reset the flags controlling ensemble + * error message rewriting. + * TCL_CANCEL_UNWIND: Magical Tcl_CancelEval mode that causes the + * stack for the script in progress to be + * completely unwound. + * TCL_EVAL_NOERR: Do no exception reporting at all, just return + * as the caller will report. + */ + +#define TCL_NO_EVAL 0x010000 +#define TCL_EVAL_GLOBAL 0x020000 +#define TCL_EVAL_DIRECT 0x040000 +#define TCL_EVAL_INVOKE 0x080000 +#define TCL_CANCEL_UNWIND 0x100000 +#define TCL_EVAL_NOERR 0x200000 + +/* + * 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 functions. + * WARNING: these bit choices must not conflict with the bit choice for + * TCL_CANCEL_UNWIND, above. + */ + +#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 + +#ifndef TCL_NO_DEPRECATED +#define TCL_INTERP_DESTROYED 0x100 +#endif + +#define TCL_LEAVE_ERR_MSG 0x200 +#define TCL_TRACE_ARRAY 0x800 +#ifndef TCL_NO_DEPRECATED +/* 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 for ensemble commands. + */ + +#define TCL_ENSEMBLE_PREFIX 0x02/* Flag value to say whether to allow + * unambiguous prefixes of commands or to + * require exact matches for command names. */ + +/* + * Flag values passed to command-related functions. + */ + +#define TCL_TRACE_RENAME 0x2000 +#define TCL_TRACE_DELETE 0x4000 + +#define TCL_ALLOW_INLINE_COMPILATION 0x20000 + +/* + * 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_CHAR 6 +#define TCL_LINK_UCHAR 7 +#define TCL_LINK_SHORT 8 +#define TCL_LINK_USHORT 9 +#define TCL_LINK_UINT 10 +#if defined(TCL_WIDE_INT_IS_LONG) || defined(_WIN32) || defined(__CYGWIN__) +#define TCL_LINK_LONG ((sizeof(long) != sizeof(int)) ? TCL_LINK_WIDE_INT : TCL_LINK_INT) +#define TCL_LINK_ULONG ((sizeof(long) != sizeof(int)) ? TCL_LINK_WIDE_UINT : TCL_LINK_UINT) +#else +#define TCL_LINK_LONG 11 +#define TCL_LINK_ULONG 12 +#endif +#define TCL_LINK_FLOAT 13 +#define TCL_LINK_WIDE_UINT 14 +#define TCL_LINK_CHARS 15 +#define TCL_LINK_BINARY 16 +#define TCL_LINK_READ_ONLY 0x80 + +/* + *---------------------------------------------------------------------------- + * Forward declarations of Tcl_HashTable and related types. + */ + +#ifndef TCL_HASH_TYPE +#if TCL_MAJOR_VERSION > 8 +# define TCL_HASH_TYPE size_t +#else +# define TCL_HASH_TYPE unsigned +#endif +#endif + +typedef struct Tcl_HashKeyType Tcl_HashKeyType; +typedef struct Tcl_HashTable Tcl_HashTable; +typedef struct Tcl_HashEntry Tcl_HashEntry; + +typedef TCL_HASH_TYPE (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr); +typedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr); +typedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr, + void *keyPtr); +typedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *hPtr); + +/* + * 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. */ + void *hash; /* Hash value, stored as pointer to ensure + * that the offsets of the fields in this + * structure are not changed. */ + void *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[1]; /* 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. + * TCL_HASH_KEY_SYSTEM_HASH - If this flag is set then all memory internally + * allocated for the hash table that is not for an + * entry will use the system heap. + */ + +#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1 +#define TCL_HASH_KEY_SYSTEM_HASH 0x2 + +/* + * 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. */ + Tcl_HashKeyProc *hashKeyProc; + /* Calculates a hash value for the key. If + * this is NULL then the pointer itself is + * used as a hash value. */ + Tcl_CompareHashKeysProc *compareKeysProc; + /* 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_AllocHashEntryProc *allocEntryProc; + /* 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_FreeHashEntryProc *freeEntryProc; + /* 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. */ +}; + +/* + * 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). */ + Tcl_Size numBuckets; /* Total number of buckets allocated at + * **bucketPtr. */ + Tcl_Size numEntries; /* Total number of entries present in + * table. */ + Tcl_Size rebuildSize; /* Enlarge table when numEntries gets to be + * this large. */ +#if TCL_MAJOR_VERSION > 8 + size_t mask; /* Mask value used in hashing function. */ +#endif + int downShift; /* Shift count used in hashing function. + * Designed to use high-order bits of + * randomized keys. */ +#if TCL_MAJOR_VERSION < 9 + int mask; /* Mask value used in hashing function. */ +#endif + 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. */ + Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key); + Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key, + int *newPtr); + const 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. */ + Tcl_Size nextIndex; /* Index of next bucket to be enumerated after + * present one. */ + Tcl_HashEntry *nextEntryPtr;/* Next entry to be enumerated in 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 compatibility 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 compatibility + * 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) +#define TCL_CUSTOM_TYPE_KEYS (-2) +#define TCL_CUSTOM_PTR_KEYS (-1) + +/* + * Structure definition for information used to keep track of searches through + * dictionaries. These fields should not be accessed by code outside + * tclDictObj.c + */ + +typedef struct { + void *next; /* Search position for underlying hash + * table. */ + TCL_HASH_TYPE epoch; /* Epoch marker for dictionary being searched, + * or 0 if search has terminated. */ + Tcl_Dict dictionaryPtr; /* Reference to dictionary being searched. */ +} Tcl_DictSearch; + +/* + *---------------------------------------------------------------------------- + * 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; /* Function to call to service this event. */ + struct Tcl_Event *nextPtr; /* Next in list of pending events, or NULL. */ +}; + +/* + * Positions to pass to Tcl_QueueEvent/Tcl_ThreadQueueEvent: + */ + +typedef enum { + TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK, + TCL_QUEUE_ALERT_IF_EMPTY=4 +} 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) (CONST86 Tcl_Time *timePtr); +typedef int (Tcl_WaitForEventProc) (CONST86 Tcl_Time *timePtr); + +/* + * TIP #233 (Virtualized Time) + */ + +typedef void (Tcl_GetTimeProc) (Tcl_Time *timebuf, void *clientData); +typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, void *clientData); + +/* + *---------------------------------------------------------------------------- + * 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. + */ + +#if TCL_MAJOR_VERSION > 8 +# define TCL_CLOSE2PROC NULL +#else +# define TCL_CLOSE2PROC ((Tcl_DriverCloseProc *)(void *)(size_t)1) +#endif + +/* + * Channel version tag. This was introduced in 8.3.2/8.4. + */ + +#ifndef TCL_NO_DEPRECATED +#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) +#endif +#define TCL_CHANNEL_VERSION_5 ((Tcl_ChannelTypeVersion) 0x5) + +/* + * 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) (void *instanceData, int mode); +typedef int (Tcl_DriverCloseProc) (void *instanceData, + Tcl_Interp *interp); +typedef int (Tcl_DriverClose2Proc) (void *instanceData, + Tcl_Interp *interp, int flags); +typedef int (Tcl_DriverInputProc) (void *instanceData, char *buf, + int toRead, int *errorCodePtr); +typedef int (Tcl_DriverOutputProc) (void *instanceData, + const char *buf, int toWrite, int *errorCodePtr); +typedef int (Tcl_DriverSeekProc) (void *instanceData, long offset, + int mode, int *errorCodePtr); +typedef int (Tcl_DriverSetOptionProc) (void *instanceData, + Tcl_Interp *interp, const char *optionName, + const char *value); +typedef int (Tcl_DriverGetOptionProc) (void *instanceData, + Tcl_Interp *interp, const char *optionName, + Tcl_DString *dsPtr); +typedef void (Tcl_DriverWatchProc) (void *instanceData, int mask); +typedef int (Tcl_DriverGetHandleProc) (void *instanceData, + int direction, void **handlePtr); +typedef int (Tcl_DriverFlushProc) (void *instanceData); +typedef int (Tcl_DriverHandlerProc) (void *instanceData, + int interestMask); +typedef long long (Tcl_DriverWideSeekProc) (void *instanceData, + long long offset, int mode, int *errorCodePtr); +/* + * TIP #218, Channel Thread Actions + */ +typedef void (Tcl_DriverThreadActionProc) (void *instanceData, + int action); +/* + * TIP #208, File Truncation (etc.) + */ +typedef int (Tcl_DriverTruncateProc) (void *instanceData, + long long length); + +/* + * 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 { + const 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; + /* Function to call to close the channel, or + * NULL or TCL_CLOSE2PROC if the close2Proc should be + * used instead. */ + Tcl_DriverInputProc *inputProc; + /* Function to call for input on channel. */ + Tcl_DriverOutputProc *outputProc; + /* Function to call for output on channel. */ + Tcl_DriverSeekProc *seekProc; + /* Function 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; + /* Function 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; + /* Function to call to flush a channel. May be + * NULL. */ + Tcl_DriverHandlerProc *handlerProc; + /* Function 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; + /* Function 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; + /* Function to call to notify the driver of + * thread specific activity for a channel. May + * be NULL. */ + /* + * Only valid in TCL_CHANNEL_VERSION_5 channels or later. + * TIP #208, File Truncation. + */ + Tcl_DriverTruncateProc *truncateProc; + /* Function to call to truncate the underlying + * file to a particular length. May be NULL if + * the channel does not support truncation. */ +} 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 function 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 { + int type; /* Corresponds to bcdpfls as in 'find -t'. */ + int perm; /* Corresponds to file permissions. */ + Tcl_Obj *macType; /* Acceptable Mac type. */ + Tcl_Obj *macCreator; /* Acceptable Mac creator. */ +} 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) + +/* + * Flags for the unload callback function. + */ + +#define TCL_UNLOAD_DETACH_FROM_INTERPRETER (1<<0) +#define TCL_UNLOAD_DETACH_FROM_PROCESS (1<<1) + +/* + * Typedefs for the various filesystem operations: + */ + +typedef int (Tcl_FSStatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +typedef int (Tcl_FSAccessProc) (Tcl_Obj *pathPtr, int mode); +typedef Tcl_Channel (Tcl_FSOpenFileChannelProc) (Tcl_Interp *interp, + Tcl_Obj *pathPtr, int mode, int permissions); +typedef int (Tcl_FSMatchInDirectoryProc) (Tcl_Interp *interp, Tcl_Obj *result, + Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); +typedef Tcl_Obj * (Tcl_FSGetCwdProc) (Tcl_Interp *interp); +typedef int (Tcl_FSChdirProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSLstatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +typedef int (Tcl_FSCreateDirectoryProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSDeleteFileProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSCopyDirectoryProc) (Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); +typedef int (Tcl_FSCopyFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); +typedef int (Tcl_FSRemoveDirectoryProc) (Tcl_Obj *pathPtr, int recursive, + Tcl_Obj **errorPtr); +typedef int (Tcl_FSRenameFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); +typedef void (Tcl_FSUnloadFileProc) (Tcl_LoadHandle loadHandle); +typedef Tcl_Obj * (Tcl_FSListVolumesProc) (void); +/* We have to declare the utime structure here. */ +struct utimbuf; +typedef int (Tcl_FSUtimeProc) (Tcl_Obj *pathPtr, struct utimbuf *tval); +typedef int (Tcl_FSNormalizePathProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + int nextCheckpoint); +typedef int (Tcl_FSFileAttrsGetProc) (Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); +typedef const char *CONST86 * (Tcl_FSFileAttrStringsProc) (Tcl_Obj *pathPtr, + Tcl_Obj **objPtrRef); +typedef int (Tcl_FSFileAttrsSetProc) (Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj *objPtr); +typedef Tcl_Obj * (Tcl_FSLinkProc) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, + int linkType); +typedef int (Tcl_FSLoadFileProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); +typedef int (Tcl_FSPathInFilesystemProc) (Tcl_Obj *pathPtr, + void **clientDataPtr); +typedef Tcl_Obj * (Tcl_FSFilesystemPathTypeProc) (Tcl_Obj *pathPtr); +typedef Tcl_Obj * (Tcl_FSFilesystemSeparatorProc) (Tcl_Obj *pathPtr); +typedef void (Tcl_FSFreeInternalRepProc) (void *clientData); +typedef void *(Tcl_FSDupInternalRepProc) (void *clientData); +typedef Tcl_Obj * (Tcl_FSInternalToNormalizedProc) (void *clientData); +typedef void *(Tcl_FSCreateInternalRepProc) (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 the functions that form the interface for a particulr the + * 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. */ + Tcl_Size structureLength; /* Length of this structure, so future binary + * compatibility can be assured. */ + Tcl_FSVersion version; /* Version of the filesystem type. */ + Tcl_FSPathInFilesystemProc *pathInFilesystemProc; + /* Determines whether the pathname is in this + * filesystem. This is the most important + * filesystem function. */ + Tcl_FSDupInternalRepProc *dupInternalRepProc; + /* Duplicates the internal handle of the node. + * If it is NULL, the filesystem is less + * performant. */ + Tcl_FSFreeInternalRepProc *freeInternalRepProc; + /* Frees the internal handle of the node. NULL + * only if there is no need to free resources + * used for the internal handle. */ + Tcl_FSInternalToNormalizedProc *internalToNormalizedProc; + /* Converts the internal handle to a normalized + * path. NULL if the filesystem creates nodes + * having no pathname. */ + Tcl_FSCreateInternalRepProc *createInternalRepProc; + /* Creates an internal handle for a pathname. + * May be NULL if pathnames have no internal + * handle or if pathInFilesystemProc always + * immediately creates an internal + * representation for pathnames in the + * filesystem. */ + Tcl_FSNormalizePathProc *normalizePathProc; + /* Normalizes a path. Should be implemented if + * the filesystems supports multiple paths to + * the same node. */ + Tcl_FSFilesystemPathTypeProc *filesystemPathTypeProc; + /* Determines the type of a path in this + * filesystem. May be NULL. */ + Tcl_FSFilesystemSeparatorProc *filesystemSeparatorProc; + /* Produces the separator character(s) for this + * filesystem. Must not be NULL. */ + Tcl_FSStatProc *statProc; /* Called by 'Tcl_FSStat()'. Provided by any + * reasonable filesystem. */ + Tcl_FSAccessProc *accessProc; + /* Called by 'Tcl_FSAccess()'. Implemented by + * any reasonable filesystem. */ + Tcl_FSOpenFileChannelProc *openFileChannelProc; + /* Called by 'Tcl_FSOpenFileChannel()'. + * Provided by any reasonable filesystem. */ + Tcl_FSMatchInDirectoryProc *matchInDirectoryProc; + /* Called by 'Tcl_FSMatchInDirectory()'. NULL + * if the filesystem does not support glob or + * recursive copy. */ + Tcl_FSUtimeProc *utimeProc; /* Called by 'Tcl_FSUtime()', by 'file + * mtime' to set (not read) times, 'file + * atime', and the open-r/open-w/fcopy variant + * of 'file copy'. */ + Tcl_FSLinkProc *linkProc; /* Called by 'Tcl_FSLink()'. NULL if reading or + * creating links is not supported. */ + Tcl_FSListVolumesProc *listVolumesProc; + /* Lists filesystem volumes added by this + * filesystem. NULL if the filesystem does not + * use volumes. */ + Tcl_FSFileAttrStringsProc *fileAttrStringsProc; + /* List all valid attributes strings. NULL if + * the filesystem does not support the 'file + * attributes' command. Can be used to attach + * arbitrary additional data to files in a + * filesystem. */ + Tcl_FSFileAttrsGetProc *fileAttrsGetProc; + /* Called by 'Tcl_FSFileAttrsGet()' and by + * 'file attributes'. */ + Tcl_FSFileAttrsSetProc *fileAttrsSetProc; + /* Called by 'Tcl_FSFileAttrsSet()' and by + * 'file attributes'. */ + Tcl_FSCreateDirectoryProc *createDirectoryProc; + /* Called by 'Tcl_FSCreateDirectory()'. May be + * NULL if the filesystem is read-only. */ + Tcl_FSRemoveDirectoryProc *removeDirectoryProc; + /* Called by 'Tcl_FSRemoveDirectory()'. May be + * NULL if the filesystem is read-only. */ + Tcl_FSDeleteFileProc *deleteFileProc; + /* Called by 'Tcl_FSDeleteFile()' May be NULL + * if the filesystem is is read-only. */ + Tcl_FSCopyFileProc *copyFileProc; + /* Called by 'Tcl_FSCopyFile()'. If NULL, for + * a copy operation at the script level (not + * C) Tcl uses open-r, open-w and fcopy. */ + Tcl_FSRenameFileProc *renameFileProc; + /* Called by 'Tcl_FSRenameFile()'. If NULL, for + * a rename operation at the script level (not + * C) Tcl performs a copy operation followed + * by a delete operation. */ + Tcl_FSCopyDirectoryProc *copyDirectoryProc; + /* Called by 'Tcl_FSCopyDirectory()'. If NULL, + * for a copy operation at the script level + * (not C) Tcl recursively creates directories + * and copies files. */ + Tcl_FSLstatProc *lstatProc; /* Called by 'Tcl_FSLstat()'. If NULL, Tcl + * attempts to use 'statProc' instead. */ + Tcl_FSLoadFileProc *loadFileProc; + /* Called by 'Tcl_FSLoadFile()'. If NULL, Tcl + * performs a copy to a temporary file in the + * native filesystem and then calls + * Tcl_FSLoadFile() on that temporary copy. */ + Tcl_FSGetCwdProc *getCwdProc; + /* Called by 'Tcl_FSGetCwd()'. Normally NULL. + * Usually only called once: If 'getcwd' is + * called before 'chdir' is ever called. */ + Tcl_FSChdirProc *chdirProc; /* Called by 'Tcl_FSChdir()'. For a virtual + * filesystem, chdirProc just returns zero + * (success) if the pathname is a valid + * directory, and some other value otherwise. + * For A real filesystem, chdirProc performs + * the correct action, e.g. calls the system + * 'chdir' function. If not implemented, then + * 'cd' and 'pwd' fail for a pathname in this + * filesystem. On success Tcl stores the + * pathname for use by GetCwd. If NULL, Tcl + * performs records the pathname as the new + * current directory if it passes a series of + * directory access checks. */ +} 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 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. */ + Tcl_Size size; /* Number of bytes in token. */ + Tcl_Size 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 an + * 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 preceded 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. + * TCL_TOKEN_EXPAND_WORD - This token is just like TCL_TOKEN_WORD except + * that it marks a word that began with the + * literal character prefix "{*}". This word is + * marked to be expanded - that is, broken into + * words after substitution is complete. + */ + +#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 +#define TCL_TOKEN_EXPAND_WORD 256 + +/* + * 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. */ + Tcl_Size 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. */ + Tcl_Size commandSize; /* Number of bytes in command, including first + * character of first word, up through the + * terminating newline, close bracket, or + * semicolon. */ + Tcl_Size 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. */ + Tcl_Size numTokens; /* Total number of tokens in command. */ + Tcl_Size tokensAvailable; /* Total number of tokens available at + * *tokenPtr. */ + int errorType; /* One of the parsing error types defined + * above. */ +#if TCL_MAJOR_VERSION > 8 + 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. */ +#endif + + /* + * The fields below are intended only for the private use of the parser. + * They should not be used by functions 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). */ +#if TCL_MAJOR_VERSION < 9 + int incomplete; +#endif + 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 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; + /* Function to convert from external encoding + * into UTF-8. */ + Tcl_EncodingConvertProc *fromUtfProc; + /* Function to convert from UTF-8 into + * external encoding. */ + Tcl_EncodingFreeProc *freeProc; + /* If non-NULL, function to call when this + * encoding is deleted. */ + void *clientData; /* Arbitrary value associated with encoding + * type. Passed to conversion functions. */ + Tcl_Size 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, 2, or 4. */ +} 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 function 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, the converter returns immediately upon + * encountering an invalid byte sequence or a + * source character that has no mapping in the + * target encoding. If clear, the converter + * substitutes the problematic character(s) with + * one or more "close" characters in the + * destination buffer and then continues to + * convert the source. Only for Tcl 8.x. + * TCL_ENCODING_NO_TERMINATE - If set, Tcl_ExternalToUtf does not append a + * terminating NUL byte. Since it does not need + * an extra byte for a terminating NUL, it fills + * all dstLen bytes with encoded UTF-8 content if + * needed. If clear, a byte is reserved in the + * dst space for NUL termination, and a + * terminating NUL is appended. + * TCL_ENCODING_CHAR_LIMIT - If set and dstCharsPtr is not NULL, then + * Tcl_ExternalToUtf takes the initial value of + * *dstCharsPtr as a limit of the maximum number + * of chars to produce in the encoded UTF-8 + * content. Otherwise, the number of chars + * produced is controlled only by other limiting + * factors. + * TCL_ENCODING_PROFILE_* - Mutually exclusive encoding profile ids. Note + * these are bit masks. + * + * NOTE: THESE BIT DEFINITIONS SHOULD NOT OVERLAP WITH INTERNAL USE BITS + * DEFINED IN tclEncoding.c (ENCODING_INPUT et al). Be cognizant of this + * when adding bits. + */ + +#define TCL_ENCODING_START 0x01 +#define TCL_ENCODING_END 0x02 +#define TCL_ENCODING_STOPONERROR 0x04 +#define TCL_ENCODING_NO_TERMINATE 0x08 +#define TCL_ENCODING_CHAR_LIMIT 0x10 +/* Internal use bits, do not define bits in this space. See above comment */ +#define TCL_ENCODING_INTERNAL_USE_MASK 0xFF00 +/* + * Reserve top byte for profile values (disjoint, not a mask). In case of + * changes, ensure ENCODING_PROFILE_* macros in tclInt.h are modified if + * necessary. + */ +#define TCL_ENCODING_PROFILE_TCL8 0x01000000 +#define TCL_ENCODING_PROFILE_STRICT 0x02000000 +#define TCL_ENCODING_PROFILE_REPLACE 0x03000000 +#define TCL_ENCODING_PROFILE_DEFAULT TCL_ENCODING_PROFILE_TCL8 + +/* + * 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 are 3 and 4. If > 3, + * then Tcl_UniChar must be 4-bytes in size (UCS-4) (the default for the + * Tcl core). If == 3, then Tcl_UniChar must be 2-bytes in size (UTF-16). + */ + +#ifndef TCL_UTF_MAX +# ifdef BUILD_tcl +# define TCL_UTF_MAX 4 +# else +# define TCL_UTF_MAX 3 +# endif +#endif + +/* + * This represents a Unicode character. Any changes to this should also be + * reflected in regcustom.h. + */ + +#if TCL_UTF_MAX == 4 + /* + * int isn't 100% accurate as it should be a strict 4-byte value + * (perhaps int32_t). ILP64/SILP64 systems may have troubles. The + * size of this value must be reflected correctly in regcustom.h. + */ +typedef int Tcl_UniChar; +#elif TCL_UTF_MAX == 3 && !defined(BUILD_tcl) +typedef unsigned short Tcl_UniChar; +#else +# error "This TCL_UTF_MAX value is not supported" +#endif + +/* + *---------------------------------------------------------------------------- + * TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to + * provide the system with the embedded configuration data. + */ + +typedef struct Tcl_Config { + const char *key; /* Configuration key to register. ASCII + * encoded, thus UTF-8. */ + const char *value; /* The value associated with the key. System + * encoding. */ +} Tcl_Config; + +/* + *---------------------------------------------------------------------------- + * Flags for TIP#143 limits, detailing which limits are active in an + * interpreter. Used for Tcl_{Add,Remove}LimitHandler type argument. + */ + +#define TCL_LIMIT_COMMANDS 0x01 +#define TCL_LIMIT_TIME 0x02 + +/* + * Structure containing information about a limit handler to be called when a + * command- or time-limit is exceeded by an interpreter. + */ + +typedef void (Tcl_LimitHandlerProc) (void *clientData, Tcl_Interp *interp); +typedef void (Tcl_LimitHandlerDeleteProc) (void *clientData); + +#if 0 +/* + *---------------------------------------------------------------------------- + * We would like to provide an anonymous structure "mp_int" here, which is + * compatible with libtommath's "mp_int", but without duplicating anything + * from or including here. But the libtommath project + * didn't honor our request. See: + * + * That's why this part is commented out, and we are using (void *) in + * various API's in stead of the more correct (mp_int *). + */ + +#ifndef MP_INT_DECLARED +#define MP_INT_DECLARED +typedef struct mp_int mp_int; +#endif + +#endif + +/* + *---------------------------------------------------------------------------- + * Definitions needed for Tcl_ParseArgvObj routines. + * Based on tkArgv.c. + * Modifications from the original are copyright (c) Sam Bromley 2006 + */ + +typedef struct { + int type; /* Indicates the option type; see below. */ + const char *keyStr; /* The key string that flags the option in the + * argv array. */ + void *srcPtr; /* Value to be used in setting dst; usage + * depends on type.*/ + void *dstPtr; /* Address of value to be modified; usage + * depends on type.*/ + const char *helpStr; /* Documentation message describing this + * option. */ + void *clientData; /* Word to pass to function callbacks. */ +} Tcl_ArgvInfo; + +/* + * Legal values for the type field of a Tcl_ArgInfo: see the user + * documentation for details. + */ + +#define TCL_ARGV_CONSTANT 15 +#define TCL_ARGV_INT 16 +#define TCL_ARGV_STRING 17 +#define TCL_ARGV_REST 18 +#define TCL_ARGV_FLOAT 19 +#define TCL_ARGV_FUNC 20 +#define TCL_ARGV_GENFUNC 21 +#define TCL_ARGV_HELP 22 +#define TCL_ARGV_END 23 + +/* + * Types of callback functions for the TCL_ARGV_FUNC and TCL_ARGV_GENFUNC + * argument types: + */ + +typedef int (Tcl_ArgvFuncProc)(void *clientData, Tcl_Obj *objPtr, + void *dstPtr); +typedef int (Tcl_ArgvGenFuncProc)(void *clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv, void *dstPtr); + +/* + * Shorthand for commonly used argTable entries. + */ + +#define TCL_ARGV_AUTO_HELP \ + {TCL_ARGV_HELP, "-help", NULL, NULL, \ + "Print summary of command-line options and abort", NULL} +#define TCL_ARGV_AUTO_REST \ + {TCL_ARGV_REST, "--", NULL, NULL, \ + "Marks the end of the options", NULL} +#define TCL_ARGV_TABLE_END \ + {TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL} + +/* + *---------------------------------------------------------------------------- + * Definitions needed for Tcl_Zlib routines. [TIP #234] + * + * Constants for the format flags describing what sort of data format is + * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and + * Tcl_ZlibStreamInit functions. + */ + +#define TCL_ZLIB_FORMAT_RAW 1 +#define TCL_ZLIB_FORMAT_ZLIB 2 +#define TCL_ZLIB_FORMAT_GZIP 4 +#define TCL_ZLIB_FORMAT_AUTO 8 + +/* + * Constants that describe whether the stream is to operate in compressing or + * decompressing mode. + */ + +#define TCL_ZLIB_STREAM_DEFLATE 16 +#define TCL_ZLIB_STREAM_INFLATE 32 + +/* + * Constants giving compression levels. Use of TCL_ZLIB_COMPRESS_DEFAULT is + * recommended. + */ + +#define TCL_ZLIB_COMPRESS_NONE 0 +#define TCL_ZLIB_COMPRESS_FAST 1 +#define TCL_ZLIB_COMPRESS_BEST 9 +#define TCL_ZLIB_COMPRESS_DEFAULT (-1) + +/* + * Constants for types of flushing, used with Tcl_ZlibFlush. + */ + +#define TCL_ZLIB_NO_FLUSH 0 +#define TCL_ZLIB_FLUSH 2 +#define TCL_ZLIB_FULLFLUSH 3 +#define TCL_ZLIB_FINALIZE 4 + +/* + *---------------------------------------------------------------------------- + * Definitions needed for the Tcl_LoadFile function. [TIP #416] + */ + +#define TCL_LOAD_GLOBAL 1 +#define TCL_LOAD_LAZY 2 + +/* + *---------------------------------------------------------------------------- + * Definitions needed for the Tcl_OpenTcpServerEx function. [TIP #456] + */ +#define TCL_TCPSERVER_REUSEADDR (1<<0) +#define TCL_TCPSERVER_REUSEPORT (1<<1) + +/* + * Constants for special Tcl_Size-typed values, see TIP #494 + */ + +#define TCL_IO_FAILURE ((Tcl_Size)-1) +#define TCL_AUTO_LENGTH ((Tcl_Size)-1) +#define TCL_INDEX_NONE ((Tcl_Size)-1) + +/* + *---------------------------------------------------------------------------- + * Single public declaration for NRE. + */ + +typedef int (Tcl_NRPostProc) (void *data[], Tcl_Interp *interp, + int result); + +/* + *---------------------------------------------------------------------------- + * The following constant is used to test for older versions of Tcl in the + * stubs tables. + */ + +#if TCL_MAJOR_VERSION > 8 +# define TCL_STUB_MAGIC ((int) 0xFCA3BACB + (int) sizeof(void *)) +#else +# define TCL_STUB_MAGIC ((int) 0xFCA3BACF) +#endif + +/* + * 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. + */ + +const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version, + int exact, int magic); +const char * TclTomMathInitializeStubs(Tcl_Interp *interp, + const char *version, int epoch, int revision); +#if defined(_WIN32) + TCL_NORETURN void Tcl_ConsolePanic(const char *format, ...); +#else +# define Tcl_ConsolePanic ((Tcl_PanicProc *)NULL) +#endif + +#ifdef USE_TCL_STUBS +# if TCL_UTF_MAX < 4 +# define Tcl_InitStubs(interp, version, exact) \ + (Tcl_InitStubs)(interp, version, \ + (exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), \ + TCL_STUB_MAGIC) +# else +# define Tcl_InitStubs(interp, version, exact) \ + (Tcl_InitStubs)(interp, TCL_PATCH_LEVEL, \ + (exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), \ + TCL_STUB_MAGIC) +# endif +#else +# define Tcl_InitStubs(interp, version, exact) \ + Tcl_PkgInitStubsCheck(interp, version, \ + (exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16)) +#endif + +/* + * Public functions that are not accessible via the stubs table. + * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171] + */ + +#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ + ((Tcl_SetPanicProc(Tcl_ConsolePanic), Tcl_CreateInterp)())) +EXTERN void Tcl_MainEx(Tcl_Size argc, char **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, + const char *version, int exact); +EXTERN const char * Tcl_InitSubsystems(void); +EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); +EXTERN const char * Tcl_SetPreInitScript(const char *string); +#ifndef TCL_NO_DEPRECATED +# define Tcl_StaticPackage Tcl_StaticLibrary +#endif +#ifdef _WIN32 +EXTERN const char *TclZipfs_AppHook(int *argc, wchar_t ***argv); +#else +EXTERN const char *TclZipfs_AppHook(int *argc, char ***argv); +#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. Make all TclOO symbols MODULE_SCOPE (which only + * has effect on building it as a shared library). See ticket [3010352]. + */ + +#if defined(BUILD_tcl) +# undef TCLAPI +# define TCLAPI MODULE_SCOPE +#endif + +#include "tclPlatDecls.h" + +/* + *---------------------------------------------------------------------------- + * The following declarations either map ckalloc and ckfree to malloc and + * free, or they map them to functions with all sorts of debugging hooks + * defined in tclCkalloc.c. + */ + +#ifdef TCL_MEM_DEBUG + +# define ckalloc(x) \ + ((void *) Tcl_DbCkalloc((unsigned)(x), __FILE__, __LINE__)) +# define ckfree(x) \ + Tcl_DbCkfree((char *)(x), __FILE__, __LINE__) +# define ckrealloc(x,y) \ + ((void *) Tcl_DbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__)) +# define attemptckalloc(x) \ + ((void *) Tcl_AttemptDbCkalloc((unsigned)(x), __FILE__, __LINE__)) +# define attemptckrealloc(x,y) \ + ((void *) Tcl_AttemptDbCkrealloc((char *)(x), (unsigned)(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) \ + ((void *) Tcl_Alloc((unsigned)(x))) +# define ckfree(x) \ + Tcl_Free((char *)(x)) +# define ckrealloc(x,y) \ + ((void *) Tcl_Realloc((char *)(x), (unsigned)(y))) +# define attemptckalloc(x) \ + ((void *) Tcl_AttemptAlloc((unsigned)(x))) +# define attemptckrealloc(x,y) \ + ((void *) Tcl_AttemptRealloc((char *)(x), (unsigned)(y))) +# undef Tcl_InitMemory +# define Tcl_InitMemory(x) +# undef Tcl_DumpActiveMemory +# define Tcl_DumpActiveMemory(x) +# undef Tcl_ValidateAllMemory +# define Tcl_ValidateAllMemory(x,y) + +#endif /* !TCL_MEM_DEBUG */ + +#ifdef TCL_MEM_DEBUG +# undef Tcl_IncrRefCount +# define Tcl_IncrRefCount(objPtr) \ + Tcl_DbIncrRefCount(objPtr, __FILE__, __LINE__) +# undef Tcl_DecrRefCount +# define Tcl_DecrRefCount(objPtr) \ + Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__) +# undef Tcl_IsShared +# define Tcl_IsShared(objPtr) \ + Tcl_DbIsShared(objPtr, __FILE__, __LINE__) +#else +# undef Tcl_IncrRefCount +# define Tcl_IncrRefCount(objPtr) \ + ++(objPtr)->refCount + /* + * Use do/while0 idiom for optimum correctness without compiler warnings. + * https://wiki.c2.com/?TrivialDoWhileLoop + */ +# undef Tcl_DecrRefCount +# define Tcl_DecrRefCount(objPtr) \ + do { \ + Tcl_Obj *_objPtr = (objPtr); \ + if (_objPtr->refCount-- <= 1) { \ + TclFreeObj(_objPtr); \ + } \ + } while(0) +# undef Tcl_IsShared +# 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 functions. + */ + +#ifdef TCL_MEM_DEBUG +# undef Tcl_NewBignumObj +# define Tcl_NewBignumObj(val) \ + Tcl_DbNewBignumObj(val, __FILE__, __LINE__) +# undef Tcl_NewBooleanObj +# define Tcl_NewBooleanObj(val) \ + Tcl_DbNewWideIntObj((val)!=0, __FILE__, __LINE__) +# undef Tcl_NewByteArrayObj +# define Tcl_NewByteArrayObj(bytes, len) \ + Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__) +# undef Tcl_NewDoubleObj +# define Tcl_NewDoubleObj(val) \ + Tcl_DbNewDoubleObj(val, __FILE__, __LINE__) +# undef Tcl_NewListObj +# define Tcl_NewListObj(objc, objv) \ + Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__) +# undef Tcl_NewObj +# define Tcl_NewObj() \ + Tcl_DbNewObj(__FILE__, __LINE__) +# undef Tcl_NewStringObj +# define Tcl_NewStringObj(bytes, len) \ + Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__) +# undef Tcl_NewWideIntObj +# define Tcl_NewWideIntObj(val) \ + Tcl_DbNewWideIntObj(val, __FILE__, __LINE__) +#endif /* TCL_MEM_DEBUG */ + +/* + *---------------------------------------------------------------------------- + * Macros for clients to use to access fields of hash entries: + */ + +#define Tcl_GetHashValue(h) ((h)->clientData) +#define Tcl_SetHashValue(h, value) ((h)->clientData = (void *)(value)) +#define Tcl_GetHashKey(tablePtr, h) \ + ((void *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \ + (tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \ + ? (h)->key.oneWordValue \ + : (h)->key.string)) + +/* + * Macros to use for clients to use to invoke find and create functions for + * hash tables: + */ + +#undef Tcl_FindHashEntry +#define Tcl_FindHashEntry(tablePtr, key) \ + (*((tablePtr)->findProc))(tablePtr, (const char *)(key)) +#undef Tcl_CreateHashEntry +#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ + (*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr) + +/* + *---------------------------------------------------------------------------- + * Deprecated Tcl functions: + */ + +#ifndef TCL_NO_DEPRECATED +/* + * These function have been renamed. The old names are deprecated, but we + * define these macros for backwards compatibility. + */ + +# 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 +#if !defined(__APPLE__) /* On OSX, there is a conflict with "mach/mach.h" */ +# define panic Tcl_Panic +#endif +# define panicVA Tcl_PanicVA + +/* + *---------------------------------------------------------------------------- + * 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. + */ + +extern Tcl_AppInitProc Tcl_AppInit; + +#endif /* !TCL_NO_DEPRECATED */ + +#endif /* RC_INVOKED */ + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TCL */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tclDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tclDecls.h new file mode 100644 index 00000000..0fe582ee --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tclDecls.h @@ -0,0 +1,4460 @@ +/* + * 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 + +#include /* for size_t */ + +#ifdef TCL_NO_DEPRECATED +# define Tcl_SavedResult void +#endif /* TCL_NO_DEPRECATED */ + +#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 + +#if !defined(BUILD_tcl) +# define TCL_DEPRECATED(msg) EXTERN TCL_DEPRECATED_API(msg) +#elif defined(TCL_NO_DEPRECATED) +# define TCL_DEPRECATED(msg) MODULE_SCOPE +#else +# define TCL_DEPRECATED(msg) EXTERN +#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/tcl.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +/* 0 */ +EXTERN int Tcl_PkgProvideEx(Tcl_Interp *interp, + const char *name, const char *version, + const void *clientData); +/* 1 */ +EXTERN const char * Tcl_PkgRequireEx(Tcl_Interp *interp, + const char *name, const char *version, + int exact, void *clientDataPtr); +/* 2 */ +EXTERN TCL_NORETURN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); +/* 3 */ +EXTERN char * Tcl_Alloc(TCL_HASH_TYPE size); +/* 4 */ +EXTERN void Tcl_Free(char *ptr); +/* 5 */ +EXTERN char * Tcl_Realloc(char *ptr, TCL_HASH_TYPE size); +/* 6 */ +EXTERN char * Tcl_DbCkalloc(TCL_HASH_TYPE size, const char *file, + int line); +/* 7 */ +EXTERN void Tcl_DbCkfree(char *ptr, const char *file, int line); +/* 8 */ +EXTERN char * Tcl_DbCkrealloc(char *ptr, TCL_HASH_TYPE size, + const char *file, int line); +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +/* 9 */ +EXTERN void Tcl_CreateFileHandler(int fd, int mask, + Tcl_FileProc *proc, void *clientData); +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 9 */ +EXTERN void Tcl_CreateFileHandler(int fd, int mask, + Tcl_FileProc *proc, void *clientData); +#endif /* MACOSX */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +/* 10 */ +EXTERN void Tcl_DeleteFileHandler(int fd); +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 10 */ +EXTERN void Tcl_DeleteFileHandler(int fd); +#endif /* MACOSX */ +/* 11 */ +EXTERN void Tcl_SetTimer(const Tcl_Time *timePtr); +/* 12 */ +EXTERN void Tcl_Sleep(int ms); +/* 13 */ +EXTERN int Tcl_WaitForEvent(const Tcl_Time *timePtr); +/* 14 */ +EXTERN int Tcl_AppendAllObjTypes(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 15 */ +EXTERN void Tcl_AppendStringsToObj(Tcl_Obj *objPtr, ...); +/* 16 */ +EXTERN void Tcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes, + Tcl_Size length); +/* 17 */ +EXTERN Tcl_Obj * Tcl_ConcatObj(Tcl_Size objc, Tcl_Obj *const objv[]); +/* 18 */ +EXTERN int Tcl_ConvertToType(Tcl_Interp *interp, + Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); +/* 19 */ +EXTERN void Tcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file, + int line); +/* 20 */ +EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file, + int line); +/* 21 */ +EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, + int line); +/* 22 */ +TCL_DEPRECATED("No longer in use, changed to macro") +Tcl_Obj * Tcl_DbNewBooleanObj(int intValue, const char *file, + int line); +/* 23 */ +EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes, + Tcl_Size numBytes, const char *file, + int line); +/* 24 */ +EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue, + const char *file, int line); +/* 25 */ +EXTERN Tcl_Obj * Tcl_DbNewListObj(Tcl_Size objc, Tcl_Obj *const *objv, + const char *file, int line); +/* 26 */ +TCL_DEPRECATED("No longer in use, changed to macro") +Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file, + int line); +/* 27 */ +EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line); +/* 28 */ +EXTERN Tcl_Obj * Tcl_DbNewStringObj(const char *bytes, + Tcl_Size length, const char *file, int line); +/* 29 */ +EXTERN Tcl_Obj * Tcl_DuplicateObj(Tcl_Obj *objPtr); +/* 30 */ +EXTERN void TclFreeObj(Tcl_Obj *objPtr); +/* 31 */ +EXTERN int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, + int *intPtr); +/* 32 */ +EXTERN int Tcl_GetBooleanFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *intPtr); +/* 33 */ +EXTERN unsigned char * Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, + Tcl_Size *numBytesPtr); +/* 34 */ +EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src, + double *doublePtr); +/* 35 */ +EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, double *doublePtr); +/* 36 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_GetIndexFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, const char *const *tablePtr, + const char *msg, int flags, int *indexPtr); +/* 37 */ +EXTERN int Tcl_GetInt(Tcl_Interp *interp, const char *src, + int *intPtr); +/* 38 */ +EXTERN int Tcl_GetIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *intPtr); +/* 39 */ +EXTERN int Tcl_GetLongFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, long *longPtr); +/* 40 */ +EXTERN CONST86 Tcl_ObjType * Tcl_GetObjType(const char *typeName); +/* 41 */ +EXTERN char * Tcl_GetStringFromObj(Tcl_Obj *objPtr, int *lengthPtr); +/* 42 */ +EXTERN void Tcl_InvalidateStringRep(Tcl_Obj *objPtr); +/* 43 */ +EXTERN int Tcl_ListObjAppendList(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); +/* 44 */ +EXTERN int Tcl_ListObjAppendElement(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Obj *objPtr); +/* 45 */ +EXTERN int Tcl_ListObjGetElements(Tcl_Interp *interp, + Tcl_Obj *listPtr, int *objcPtr, + Tcl_Obj ***objvPtr); +/* 46 */ +EXTERN int Tcl_ListObjIndex(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Size index, + Tcl_Obj **objPtrPtr); +/* 47 */ +EXTERN int Tcl_ListObjLength(Tcl_Interp *interp, + Tcl_Obj *listPtr, int *lengthPtr); +/* 48 */ +EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Size first, + Tcl_Size count, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* 49 */ +TCL_DEPRECATED("No longer in use, changed to macro") +Tcl_Obj * Tcl_NewBooleanObj(int intValue); +/* 50 */ +EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes, + Tcl_Size numBytes); +/* 51 */ +EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue); +/* 52 */ +TCL_DEPRECATED("No longer in use, changed to macro") +Tcl_Obj * Tcl_NewIntObj(int intValue); +/* 53 */ +EXTERN Tcl_Obj * Tcl_NewListObj(Tcl_Size objc, Tcl_Obj *const objv[]); +/* 54 */ +TCL_DEPRECATED("No longer in use, changed to macro") +Tcl_Obj * Tcl_NewLongObj(long longValue); +/* 55 */ +EXTERN Tcl_Obj * Tcl_NewObj(void); +/* 56 */ +EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, Tcl_Size length); +/* 57 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int intValue); +/* 58 */ +EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, + Tcl_Size numBytes); +/* 59 */ +EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr, + const unsigned char *bytes, + Tcl_Size numBytes); +/* 60 */ +EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue); +/* 61 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue); +/* 62 */ +EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* 63 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue); +/* 64 */ +EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, Tcl_Size length); +/* 65 */ +EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, + Tcl_Size length); +/* 66 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_AddErrorInfo(Tcl_Interp *interp, + const char *message); +/* 67 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_AddObjErrorInfo(Tcl_Interp *interp, + const char *message, Tcl_Size length); +/* 68 */ +EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp); +/* 69 */ +EXTERN void Tcl_AppendElement(Tcl_Interp *interp, + const char *element); +/* 70 */ +EXTERN void Tcl_AppendResult(Tcl_Interp *interp, ...); +/* 71 */ +EXTERN Tcl_AsyncHandler Tcl_AsyncCreate(Tcl_AsyncProc *proc, + void *clientData); +/* 72 */ +EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async); +/* 73 */ +EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code); +/* 74 */ +EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async); +/* 75 */ +EXTERN int Tcl_AsyncReady(void); +/* 76 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_BackgroundError(Tcl_Interp *interp); +/* 77 */ +TCL_DEPRECATED("Use Tcl_UtfBackslash") +char Tcl_Backslash(const char *src, int *readPtr); +/* 78 */ +EXTERN int Tcl_BadChannelOption(Tcl_Interp *interp, + const char *optionName, + const char *optionList); +/* 79 */ +EXTERN void Tcl_CallWhenDeleted(Tcl_Interp *interp, + Tcl_InterpDeleteProc *proc, void *clientData); +/* 80 */ +EXTERN void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, + void *clientData); +/* 81 */ +EXTERN int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan); +/* 82 */ +EXTERN int Tcl_CommandComplete(const char *cmd); +/* 83 */ +EXTERN char * Tcl_Concat(Tcl_Size argc, const char *const *argv); +/* 84 */ +EXTERN Tcl_Size Tcl_ConvertElement(const char *src, char *dst, + int flags); +/* 85 */ +EXTERN Tcl_Size Tcl_ConvertCountedElement(const char *src, + Tcl_Size length, char *dst, int flags); +/* 86 */ +EXTERN int Tcl_CreateAlias(Tcl_Interp *childInterp, + const char *childCmd, Tcl_Interp *target, + const char *targetCmd, Tcl_Size argc, + const char *const *argv); +/* 87 */ +EXTERN int Tcl_CreateAliasObj(Tcl_Interp *childInterp, + const char *childCmd, Tcl_Interp *target, + const char *targetCmd, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* 88 */ +EXTERN Tcl_Channel Tcl_CreateChannel(const Tcl_ChannelType *typePtr, + const char *chanName, void *instanceData, + int mask); +/* 89 */ +EXTERN void Tcl_CreateChannelHandler(Tcl_Channel chan, int mask, + Tcl_ChannelProc *proc, void *clientData); +/* 90 */ +EXTERN void Tcl_CreateCloseHandler(Tcl_Channel chan, + Tcl_CloseProc *proc, void *clientData); +/* 91 */ +EXTERN Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdProc *proc, + void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 92 */ +EXTERN void Tcl_CreateEventSource(Tcl_EventSetupProc *setupProc, + Tcl_EventCheckProc *checkProc, + void *clientData); +/* 93 */ +EXTERN void Tcl_CreateExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 94 */ +EXTERN Tcl_Interp * Tcl_CreateInterp(void); +/* 95 */ +TCL_DEPRECATED("") +void Tcl_CreateMathFunc(Tcl_Interp *interp, + const char *name, int numArgs, + Tcl_ValueType *argTypes, Tcl_MathProc *proc, + void *clientData); +/* 96 */ +EXTERN Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc *proc, + void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 97 */ +EXTERN Tcl_Interp * Tcl_CreateChild(Tcl_Interp *interp, const char *name, + int isSafe); +/* 98 */ +EXTERN Tcl_TimerToken Tcl_CreateTimerHandler(int milliseconds, + Tcl_TimerProc *proc, void *clientData); +/* 99 */ +EXTERN Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, Tcl_Size level, + Tcl_CmdTraceProc *proc, void *clientData); +/* 100 */ +EXTERN void Tcl_DeleteAssocData(Tcl_Interp *interp, + const char *name); +/* 101 */ +EXTERN void Tcl_DeleteChannelHandler(Tcl_Channel chan, + Tcl_ChannelProc *proc, void *clientData); +/* 102 */ +EXTERN void Tcl_DeleteCloseHandler(Tcl_Channel chan, + Tcl_CloseProc *proc, void *clientData); +/* 103 */ +EXTERN int Tcl_DeleteCommand(Tcl_Interp *interp, + const char *cmdName); +/* 104 */ +EXTERN int Tcl_DeleteCommandFromToken(Tcl_Interp *interp, + Tcl_Command command); +/* 105 */ +EXTERN void Tcl_DeleteEvents(Tcl_EventDeleteProc *proc, + void *clientData); +/* 106 */ +EXTERN void Tcl_DeleteEventSource(Tcl_EventSetupProc *setupProc, + Tcl_EventCheckProc *checkProc, + void *clientData); +/* 107 */ +EXTERN void Tcl_DeleteExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 108 */ +EXTERN void Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr); +/* 109 */ +EXTERN void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr); +/* 110 */ +EXTERN void Tcl_DeleteInterp(Tcl_Interp *interp); +/* 111 */ +EXTERN void Tcl_DetachPids(Tcl_Size numPids, Tcl_Pid *pidPtr); +/* 112 */ +EXTERN void Tcl_DeleteTimerHandler(Tcl_TimerToken token); +/* 113 */ +EXTERN void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace); +/* 114 */ +EXTERN void Tcl_DontCallWhenDeleted(Tcl_Interp *interp, + Tcl_InterpDeleteProc *proc, void *clientData); +/* 115 */ +EXTERN int Tcl_DoOneEvent(int flags); +/* 116 */ +EXTERN void Tcl_DoWhenIdle(Tcl_IdleProc *proc, void *clientData); +/* 117 */ +EXTERN char * Tcl_DStringAppend(Tcl_DString *dsPtr, + const char *bytes, Tcl_Size length); +/* 118 */ +EXTERN char * Tcl_DStringAppendElement(Tcl_DString *dsPtr, + const char *element); +/* 119 */ +EXTERN void Tcl_DStringEndSublist(Tcl_DString *dsPtr); +/* 120 */ +EXTERN void Tcl_DStringFree(Tcl_DString *dsPtr); +/* 121 */ +EXTERN void Tcl_DStringGetResult(Tcl_Interp *interp, + Tcl_DString *dsPtr); +/* 122 */ +EXTERN void Tcl_DStringInit(Tcl_DString *dsPtr); +/* 123 */ +EXTERN void Tcl_DStringResult(Tcl_Interp *interp, + Tcl_DString *dsPtr); +/* 124 */ +EXTERN void Tcl_DStringSetLength(Tcl_DString *dsPtr, + Tcl_Size length); +/* 125 */ +EXTERN void Tcl_DStringStartSublist(Tcl_DString *dsPtr); +/* 126 */ +EXTERN int Tcl_Eof(Tcl_Channel chan); +/* 127 */ +EXTERN const char * Tcl_ErrnoId(void); +/* 128 */ +EXTERN const char * Tcl_ErrnoMsg(int err); +/* 129 */ +EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *script); +/* 130 */ +EXTERN int Tcl_EvalFile(Tcl_Interp *interp, + const char *fileName); +/* 131 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr); +/* 132 */ +EXTERN void Tcl_EventuallyFree(void *clientData, + Tcl_FreeProc *freeProc); +/* 133 */ +EXTERN TCL_NORETURN void Tcl_Exit(int status); +/* 134 */ +EXTERN int Tcl_ExposeCommand(Tcl_Interp *interp, + const char *hiddenCmdToken, + const char *cmdName); +/* 135 */ +EXTERN int Tcl_ExprBoolean(Tcl_Interp *interp, const char *expr, + int *ptr); +/* 136 */ +EXTERN int Tcl_ExprBooleanObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *ptr); +/* 137 */ +EXTERN int Tcl_ExprDouble(Tcl_Interp *interp, const char *expr, + double *ptr); +/* 138 */ +EXTERN int Tcl_ExprDoubleObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, double *ptr); +/* 139 */ +EXTERN int Tcl_ExprLong(Tcl_Interp *interp, const char *expr, + long *ptr); +/* 140 */ +EXTERN int Tcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + long *ptr); +/* 141 */ +EXTERN int Tcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + Tcl_Obj **resultPtrPtr); +/* 142 */ +EXTERN int Tcl_ExprString(Tcl_Interp *interp, const char *expr); +/* 143 */ +EXTERN void Tcl_Finalize(void); +/* 144 */ +EXTERN const char * Tcl_FindExecutable(const char *argv0); +/* 145 */ +EXTERN Tcl_HashEntry * Tcl_FirstHashEntry(Tcl_HashTable *tablePtr, + Tcl_HashSearch *searchPtr); +/* 146 */ +EXTERN int Tcl_Flush(Tcl_Channel chan); +/* 147 */ +TCL_DEPRECATED("see TIP #559. Use Tcl_ResetResult") +void Tcl_FreeResult(Tcl_Interp *interp); +/* 148 */ +EXTERN int Tcl_GetAlias(Tcl_Interp *interp, + const char *childCmd, + Tcl_Interp **targetInterpPtr, + const char **targetCmdPtr, int *argcPtr, + const char ***argvPtr); +/* 149 */ +EXTERN int Tcl_GetAliasObj(Tcl_Interp *interp, + const char *childCmd, + Tcl_Interp **targetInterpPtr, + const char **targetCmdPtr, int *objcPtr, + Tcl_Obj ***objv); +/* 150 */ +EXTERN void * Tcl_GetAssocData(Tcl_Interp *interp, + const char *name, + Tcl_InterpDeleteProc **procPtr); +/* 151 */ +EXTERN Tcl_Channel Tcl_GetChannel(Tcl_Interp *interp, + const char *chanName, int *modePtr); +/* 152 */ +EXTERN Tcl_Size Tcl_GetChannelBufferSize(Tcl_Channel chan); +/* 153 */ +EXTERN int Tcl_GetChannelHandle(Tcl_Channel chan, int direction, + void **handlePtr); +/* 154 */ +EXTERN void * Tcl_GetChannelInstanceData(Tcl_Channel chan); +/* 155 */ +EXTERN int Tcl_GetChannelMode(Tcl_Channel chan); +/* 156 */ +EXTERN const char * Tcl_GetChannelName(Tcl_Channel chan); +/* 157 */ +EXTERN int Tcl_GetChannelOption(Tcl_Interp *interp, + Tcl_Channel chan, const char *optionName, + Tcl_DString *dsPtr); +/* 158 */ +EXTERN CONST86 Tcl_ChannelType * Tcl_GetChannelType(Tcl_Channel chan); +/* 159 */ +EXTERN int Tcl_GetCommandInfo(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdInfo *infoPtr); +/* 160 */ +EXTERN const char * Tcl_GetCommandName(Tcl_Interp *interp, + Tcl_Command command); +/* 161 */ +EXTERN int Tcl_GetErrno(void); +/* 162 */ +EXTERN const char * Tcl_GetHostName(void); +/* 163 */ +EXTERN int Tcl_GetInterpPath(Tcl_Interp *interp, + Tcl_Interp *childInterp); +/* 164 */ +EXTERN Tcl_Interp * Tcl_GetParent(Tcl_Interp *interp); +/* 165 */ +EXTERN const char * Tcl_GetNameOfExecutable(void); +/* 166 */ +EXTERN Tcl_Obj * Tcl_GetObjResult(Tcl_Interp *interp); +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +/* 167 */ +EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, + const char *chanID, int forWriting, + int checkUsage, void **filePtr); +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 167 */ +EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, + const char *chanID, int forWriting, + int checkUsage, void **filePtr); +#endif /* MACOSX */ +/* 168 */ +EXTERN Tcl_PathType Tcl_GetPathType(const char *path); +/* 169 */ +EXTERN Tcl_Size Tcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr); +/* 170 */ +EXTERN Tcl_Size Tcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr); +/* 171 */ +EXTERN int Tcl_GetServiceMode(void); +/* 172 */ +EXTERN Tcl_Interp * Tcl_GetChild(Tcl_Interp *interp, const char *name); +/* 173 */ +EXTERN Tcl_Channel Tcl_GetStdChannel(int type); +/* 174 */ +EXTERN const char * Tcl_GetStringResult(Tcl_Interp *interp); +/* 175 */ +TCL_DEPRECATED("No longer in use, changed to macro") +const char * Tcl_GetVar(Tcl_Interp *interp, const char *varName, + int flags); +/* 176 */ +EXTERN const char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* 177 */ +EXTERN int Tcl_GlobalEval(Tcl_Interp *interp, + const char *command); +/* 178 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_GlobalEvalObj(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 179 */ +EXTERN int Tcl_HideCommand(Tcl_Interp *interp, + const char *cmdName, + const char *hiddenCmdToken); +/* 180 */ +EXTERN int Tcl_Init(Tcl_Interp *interp); +/* 181 */ +EXTERN void Tcl_InitHashTable(Tcl_HashTable *tablePtr, + int keyType); +/* 182 */ +EXTERN int Tcl_InputBlocked(Tcl_Channel chan); +/* 183 */ +EXTERN int Tcl_InputBuffered(Tcl_Channel chan); +/* 184 */ +EXTERN int Tcl_InterpDeleted(Tcl_Interp *interp); +/* 185 */ +EXTERN int Tcl_IsSafe(Tcl_Interp *interp); +/* 186 */ +EXTERN char * Tcl_JoinPath(Tcl_Size argc, const char *const *argv, + Tcl_DString *resultPtr); +/* 187 */ +EXTERN int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, + void *addr, int type); +/* Slot 188 is reserved */ +/* 189 */ +EXTERN Tcl_Channel Tcl_MakeFileChannel(void *handle, int mode); +/* 190 */ +TCL_DEPRECATED("") +int Tcl_MakeSafe(Tcl_Interp *interp); +/* 191 */ +EXTERN Tcl_Channel Tcl_MakeTcpClientChannel(void *tcpSocket); +/* 192 */ +EXTERN char * Tcl_Merge(Tcl_Size argc, const char *const *argv); +/* 193 */ +EXTERN Tcl_HashEntry * Tcl_NextHashEntry(Tcl_HashSearch *searchPtr); +/* 194 */ +EXTERN void Tcl_NotifyChannel(Tcl_Channel channel, int mask); +/* 195 */ +EXTERN Tcl_Obj * Tcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, + Tcl_Obj *part2Ptr, int flags); +/* 196 */ +EXTERN Tcl_Obj * Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, + Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, + int flags); +/* 197 */ +EXTERN Tcl_Channel Tcl_OpenCommandChannel(Tcl_Interp *interp, + Tcl_Size argc, const char **argv, int flags); +/* 198 */ +EXTERN Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp, + const char *fileName, const char *modeString, + int permissions); +/* 199 */ +EXTERN Tcl_Channel Tcl_OpenTcpClient(Tcl_Interp *interp, int port, + const char *address, const char *myaddr, + int myport, int flags); +/* 200 */ +EXTERN Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port, + const char *host, + Tcl_TcpAcceptProc *acceptProc, + void *callbackData); +/* 201 */ +EXTERN void Tcl_Preserve(void *data); +/* 202 */ +EXTERN void Tcl_PrintDouble(Tcl_Interp *interp, double value, + char *dst); +/* 203 */ +EXTERN int Tcl_PutEnv(const char *assignment); +/* 204 */ +EXTERN const char * Tcl_PosixError(Tcl_Interp *interp); +/* 205 */ +EXTERN void Tcl_QueueEvent(Tcl_Event *evPtr, int position); +/* 206 */ +EXTERN Tcl_Size Tcl_Read(Tcl_Channel chan, char *bufPtr, + Tcl_Size toRead); +/* 207 */ +EXTERN void Tcl_ReapDetachedProcs(void); +/* 208 */ +EXTERN int Tcl_RecordAndEval(Tcl_Interp *interp, + const char *cmd, int flags); +/* 209 */ +EXTERN int Tcl_RecordAndEvalObj(Tcl_Interp *interp, + Tcl_Obj *cmdPtr, int flags); +/* 210 */ +EXTERN void Tcl_RegisterChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 211 */ +EXTERN void Tcl_RegisterObjType(const Tcl_ObjType *typePtr); +/* 212 */ +EXTERN Tcl_RegExp Tcl_RegExpCompile(Tcl_Interp *interp, + const char *pattern); +/* 213 */ +EXTERN int Tcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp, + const char *text, const char *start); +/* 214 */ +EXTERN int Tcl_RegExpMatch(Tcl_Interp *interp, const char *text, + const char *pattern); +/* 215 */ +EXTERN void Tcl_RegExpRange(Tcl_RegExp regexp, Tcl_Size index, + const char **startPtr, const char **endPtr); +/* 216 */ +EXTERN void Tcl_Release(void *clientData); +/* 217 */ +EXTERN void Tcl_ResetResult(Tcl_Interp *interp); +/* 218 */ +EXTERN Tcl_Size Tcl_ScanElement(const char *src, int *flagPtr); +/* 219 */ +EXTERN Tcl_Size Tcl_ScanCountedElement(const char *src, + Tcl_Size length, int *flagPtr); +/* 220 */ +TCL_DEPRECATED("") +int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode); +/* 221 */ +EXTERN int Tcl_ServiceAll(void); +/* 222 */ +EXTERN int Tcl_ServiceEvent(int flags); +/* 223 */ +EXTERN void Tcl_SetAssocData(Tcl_Interp *interp, + const char *name, Tcl_InterpDeleteProc *proc, + void *clientData); +/* 224 */ +EXTERN void Tcl_SetChannelBufferSize(Tcl_Channel chan, + Tcl_Size sz); +/* 225 */ +EXTERN int Tcl_SetChannelOption(Tcl_Interp *interp, + Tcl_Channel chan, const char *optionName, + const char *newValue); +/* 226 */ +EXTERN int Tcl_SetCommandInfo(Tcl_Interp *interp, + const char *cmdName, + const Tcl_CmdInfo *infoPtr); +/* 227 */ +EXTERN void Tcl_SetErrno(int err); +/* 228 */ +EXTERN void Tcl_SetErrorCode(Tcl_Interp *interp, ...); +/* 229 */ +EXTERN void Tcl_SetMaxBlockTime(const Tcl_Time *timePtr); +/* 230 */ +EXTERN const char * Tcl_SetPanicProc( + TCL_NORETURN1 Tcl_PanicProc *panicProc); +/* 231 */ +EXTERN Tcl_Size Tcl_SetRecursionLimit(Tcl_Interp *interp, + Tcl_Size depth); +/* 232 */ +EXTERN void Tcl_SetResult(Tcl_Interp *interp, char *result, + Tcl_FreeProc *freeProc); +/* 233 */ +EXTERN int Tcl_SetServiceMode(int mode); +/* 234 */ +EXTERN void Tcl_SetObjErrorCode(Tcl_Interp *interp, + Tcl_Obj *errorObjPtr); +/* 235 */ +EXTERN void Tcl_SetObjResult(Tcl_Interp *interp, + Tcl_Obj *resultObjPtr); +/* 236 */ +EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type); +/* 237 */ +TCL_DEPRECATED("No longer in use, changed to macro") +const char * Tcl_SetVar(Tcl_Interp *interp, const char *varName, + const char *newValue, int flags); +/* 238 */ +EXTERN const char * Tcl_SetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, const char *newValue, + int flags); +/* 239 */ +EXTERN const char * Tcl_SignalId(int sig); +/* 240 */ +EXTERN const char * Tcl_SignalMsg(int sig); +/* 241 */ +EXTERN void Tcl_SourceRCFile(Tcl_Interp *interp); +/* 242 */ +EXTERN int Tcl_SplitList(Tcl_Interp *interp, + const char *listStr, int *argcPtr, + const char ***argvPtr); +/* 243 */ +EXTERN void Tcl_SplitPath(const char *path, int *argcPtr, + const char ***argvPtr); +/* 244 */ +EXTERN void Tcl_StaticLibrary(Tcl_Interp *interp, + const char *prefix, + Tcl_LibraryInitProc *initProc, + Tcl_LibraryInitProc *safeInitProc); +/* 245 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_StringMatch(const char *str, const char *pattern); +/* 246 */ +TCL_DEPRECATED("") +int Tcl_TellOld(Tcl_Channel chan); +/* 247 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_TraceVar(Tcl_Interp *interp, const char *varName, + int flags, Tcl_VarTraceProc *proc, + void *clientData); +/* 248 */ +EXTERN int Tcl_TraceVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags, + Tcl_VarTraceProc *proc, void *clientData); +/* 249 */ +EXTERN char * Tcl_TranslateFileName(Tcl_Interp *interp, + const char *name, Tcl_DString *bufferPtr); +/* 250 */ +EXTERN Tcl_Size Tcl_Ungets(Tcl_Channel chan, const char *str, + Tcl_Size len, int atHead); +/* 251 */ +EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp, + const char *varName); +/* 252 */ +EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 253 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName, + int flags); +/* 254 */ +EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* 255 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void Tcl_UntraceVar(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_VarTraceProc *proc, void *clientData); +/* 256 */ +EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags, Tcl_VarTraceProc *proc, + void *clientData); +/* 257 */ +EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp, + const char *varName); +/* 258 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_UpVar(Tcl_Interp *interp, const char *frameName, + const char *varName, const char *localName, + int flags); +/* 259 */ +EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName, + const char *part1, const char *part2, + const char *localName, int flags); +/* 260 */ +EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...); +/* 261 */ +TCL_DEPRECATED("No longer in use, changed to macro") +void * Tcl_VarTraceInfo(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_VarTraceProc *procPtr, + void *prevClientData); +/* 262 */ +EXTERN void * Tcl_VarTraceInfo2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags, Tcl_VarTraceProc *procPtr, + void *prevClientData); +/* 263 */ +EXTERN Tcl_Size Tcl_Write(Tcl_Channel chan, const char *s, + Tcl_Size slen); +/* 264 */ +EXTERN void Tcl_WrongNumArgs(Tcl_Interp *interp, Tcl_Size objc, + Tcl_Obj *const objv[], const char *message); +/* 265 */ +EXTERN int Tcl_DumpActiveMemory(const char *fileName); +/* 266 */ +EXTERN void Tcl_ValidateAllMemory(const char *file, int line); +/* 267 */ +TCL_DEPRECATED("see TIP #422") +void Tcl_AppendResultVA(Tcl_Interp *interp, + va_list argList); +/* 268 */ +TCL_DEPRECATED("see TIP #422") +void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, + va_list argList); +/* 269 */ +EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr); +/* 270 */ +EXTERN const char * Tcl_ParseVar(Tcl_Interp *interp, const char *start, + const char **termPtr); +/* 271 */ +TCL_DEPRECATED("No longer in use, changed to macro") +const char * Tcl_PkgPresent(Tcl_Interp *interp, const char *name, + const char *version, int exact); +/* 272 */ +EXTERN const char * Tcl_PkgPresentEx(Tcl_Interp *interp, + const char *name, const char *version, + int exact, void *clientDataPtr); +/* 273 */ +TCL_DEPRECATED("No longer in use, changed to macro") +int Tcl_PkgProvide(Tcl_Interp *interp, const char *name, + const char *version); +/* 274 */ +TCL_DEPRECATED("No longer in use, changed to macro") +const char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name, + const char *version, int exact); +/* 275 */ +TCL_DEPRECATED("see TIP #422") +void Tcl_SetErrorCodeVA(Tcl_Interp *interp, + va_list argList); +/* 276 */ +TCL_DEPRECATED("see TIP #422") +int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList); +/* 277 */ +EXTERN Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options); +/* 278 */ +TCL_DEPRECATED("see TIP #422") +TCL_NORETURN void Tcl_PanicVA(const char *format, va_list argList); +/* 279 */ +EXTERN void Tcl_GetVersion(int *major, int *minor, + int *patchLevel, int *type); +/* 280 */ +EXTERN void Tcl_InitMemory(Tcl_Interp *interp); +/* 281 */ +EXTERN Tcl_Channel Tcl_StackChannel(Tcl_Interp *interp, + const Tcl_ChannelType *typePtr, + void *instanceData, int mask, + Tcl_Channel prevChan); +/* 282 */ +EXTERN int Tcl_UnstackChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 283 */ +EXTERN Tcl_Channel Tcl_GetStackedChannel(Tcl_Channel chan); +/* 284 */ +EXTERN void Tcl_SetMainLoop(Tcl_MainLoopProc *proc); +/* Slot 285 is reserved */ +/* 286 */ +EXTERN void Tcl_AppendObjToObj(Tcl_Obj *objPtr, + Tcl_Obj *appendObjPtr); +/* 287 */ +EXTERN Tcl_Encoding Tcl_CreateEncoding(const Tcl_EncodingType *typePtr); +/* 288 */ +EXTERN void Tcl_CreateThreadExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 289 */ +EXTERN void Tcl_DeleteThreadExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 290 */ +TCL_DEPRECATED("Use Tcl_DiscardInterpState") +void Tcl_DiscardResult(Tcl_SavedResult *statePtr); +/* 291 */ +EXTERN int Tcl_EvalEx(Tcl_Interp *interp, const char *script, + Tcl_Size numBytes, int flags); +/* 292 */ +EXTERN int Tcl_EvalObjv(Tcl_Interp *interp, Tcl_Size objc, + Tcl_Obj *const objv[], int flags); +/* 293 */ +EXTERN int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 294 */ +EXTERN TCL_NORETURN void Tcl_ExitThread(int status); +/* 295 */ +EXTERN int Tcl_ExternalToUtf(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, + Tcl_Size dstLen, int *srcReadPtr, + int *dstWrotePtr, int *dstCharsPtr); +/* 296 */ +EXTERN char * Tcl_ExternalToUtfDString(Tcl_Encoding encoding, + const char *src, Tcl_Size srcLen, + Tcl_DString *dsPtr); +/* 297 */ +EXTERN void Tcl_FinalizeThread(void); +/* 298 */ +EXTERN void Tcl_FinalizeNotifier(void *clientData); +/* 299 */ +EXTERN void Tcl_FreeEncoding(Tcl_Encoding encoding); +/* 300 */ +EXTERN Tcl_ThreadId Tcl_GetCurrentThread(void); +/* 301 */ +EXTERN Tcl_Encoding Tcl_GetEncoding(Tcl_Interp *interp, const char *name); +/* 302 */ +EXTERN const char * Tcl_GetEncodingName(Tcl_Encoding encoding); +/* 303 */ +EXTERN void Tcl_GetEncodingNames(Tcl_Interp *interp); +/* 304 */ +EXTERN int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp, + Tcl_Obj *objPtr, const void *tablePtr, + Tcl_Size offset, const char *msg, int flags, + void *indexPtr); +/* 305 */ +EXTERN void * Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, + Tcl_Size size); +/* 306 */ +EXTERN Tcl_Obj * Tcl_GetVar2Ex(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* 307 */ +EXTERN void * Tcl_InitNotifier(void); +/* 308 */ +EXTERN void Tcl_MutexLock(Tcl_Mutex *mutexPtr); +/* 309 */ +EXTERN void Tcl_MutexUnlock(Tcl_Mutex *mutexPtr); +/* 310 */ +EXTERN void Tcl_ConditionNotify(Tcl_Condition *condPtr); +/* 311 */ +EXTERN void Tcl_ConditionWait(Tcl_Condition *condPtr, + Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); +/* 312 */ +EXTERN Tcl_Size Tcl_NumUtfChars(const char *src, Tcl_Size length); +/* 313 */ +EXTERN Tcl_Size Tcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr, + Tcl_Size charsToRead, int appendFlag); +/* 314 */ +TCL_DEPRECATED("Use Tcl_RestoreInterpState") +void Tcl_RestoreResult(Tcl_Interp *interp, + Tcl_SavedResult *statePtr); +/* 315 */ +TCL_DEPRECATED("Use Tcl_SaveInterpState") +void Tcl_SaveResult(Tcl_Interp *interp, + Tcl_SavedResult *statePtr); +/* 316 */ +EXTERN int Tcl_SetSystemEncoding(Tcl_Interp *interp, + const char *name); +/* 317 */ +EXTERN Tcl_Obj * Tcl_SetVar2Ex(Tcl_Interp *interp, const char *part1, + const char *part2, Tcl_Obj *newValuePtr, + int flags); +/* 318 */ +EXTERN void Tcl_ThreadAlert(Tcl_ThreadId threadId); +/* 319 */ +EXTERN void Tcl_ThreadQueueEvent(Tcl_ThreadId threadId, + Tcl_Event *evPtr, int position); +/* 320 */ +EXTERN int Tcl_UniCharAtIndex(const char *src, Tcl_Size index); +/* 321 */ +EXTERN int Tcl_UniCharToLower(int ch); +/* 322 */ +EXTERN int Tcl_UniCharToTitle(int ch); +/* 323 */ +EXTERN int Tcl_UniCharToUpper(int ch); +/* 324 */ +EXTERN Tcl_Size Tcl_UniCharToUtf(int ch, char *buf); +/* 325 */ +EXTERN const char * Tcl_UtfAtIndex(const char *src, Tcl_Size index); +/* 326 */ +EXTERN int TclUtfCharComplete(const char *src, Tcl_Size length); +/* 327 */ +EXTERN Tcl_Size Tcl_UtfBackslash(const char *src, int *readPtr, + char *dst); +/* 328 */ +EXTERN const char * Tcl_UtfFindFirst(const char *src, int ch); +/* 329 */ +EXTERN const char * Tcl_UtfFindLast(const char *src, int ch); +/* 330 */ +EXTERN const char * TclUtfNext(const char *src); +/* 331 */ +EXTERN const char * TclUtfPrev(const char *src, const char *start); +/* 332 */ +EXTERN int Tcl_UtfToExternal(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, + Tcl_Size dstLen, int *srcReadPtr, + int *dstWrotePtr, int *dstCharsPtr); +/* 333 */ +EXTERN char * Tcl_UtfToExternalDString(Tcl_Encoding encoding, + const char *src, Tcl_Size srcLen, + Tcl_DString *dsPtr); +/* 334 */ +EXTERN Tcl_Size Tcl_UtfToLower(char *src); +/* 335 */ +EXTERN Tcl_Size Tcl_UtfToTitle(char *src); +/* 336 */ +EXTERN Tcl_Size Tcl_UtfToChar16(const char *src, + unsigned short *chPtr); +/* 337 */ +EXTERN Tcl_Size Tcl_UtfToUpper(char *src); +/* 338 */ +EXTERN Tcl_Size Tcl_WriteChars(Tcl_Channel chan, const char *src, + Tcl_Size srcLen); +/* 339 */ +EXTERN Tcl_Size Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr); +/* 340 */ +EXTERN char * Tcl_GetString(Tcl_Obj *objPtr); +/* 341 */ +TCL_DEPRECATED("Use Tcl_GetEncodingSearchPath") +const char * Tcl_GetDefaultEncodingDir(void); +/* 342 */ +TCL_DEPRECATED("Use Tcl_SetEncodingSearchPath") +void Tcl_SetDefaultEncodingDir(const char *path); +/* 343 */ +EXTERN void Tcl_AlertNotifier(void *clientData); +/* 344 */ +EXTERN void Tcl_ServiceModeHook(int mode); +/* 345 */ +EXTERN int Tcl_UniCharIsAlnum(int ch); +/* 346 */ +EXTERN int Tcl_UniCharIsAlpha(int ch); +/* 347 */ +EXTERN int Tcl_UniCharIsDigit(int ch); +/* 348 */ +EXTERN int Tcl_UniCharIsLower(int ch); +/* 349 */ +EXTERN int Tcl_UniCharIsSpace(int ch); +/* 350 */ +EXTERN int Tcl_UniCharIsUpper(int ch); +/* 351 */ +EXTERN int Tcl_UniCharIsWordChar(int ch); +/* 352 */ +EXTERN Tcl_Size Tcl_Char16Len(const unsigned short *uniStr); +/* 353 */ +TCL_DEPRECATED("Use Tcl_UtfNcmp") +int Tcl_UniCharNcmp(const unsigned short *ucs, + const unsigned short *uct, + unsigned long numChars); +/* 354 */ +EXTERN char * Tcl_Char16ToUtfDString(const unsigned short *uniStr, + Tcl_Size uniLength, Tcl_DString *dsPtr); +/* 355 */ +EXTERN unsigned short * Tcl_UtfToChar16DString(const char *src, + Tcl_Size length, Tcl_DString *dsPtr); +/* 356 */ +EXTERN Tcl_RegExp Tcl_GetRegExpFromObj(Tcl_Interp *interp, + Tcl_Obj *patObj, int flags); +/* 357 */ +TCL_DEPRECATED("Use Tcl_EvalTokensStandard") +Tcl_Obj * Tcl_EvalTokens(Tcl_Interp *interp, + Tcl_Token *tokenPtr, Tcl_Size count); +/* 358 */ +EXTERN void Tcl_FreeParse(Tcl_Parse *parsePtr); +/* 359 */ +EXTERN void Tcl_LogCommandInfo(Tcl_Interp *interp, + const char *script, const char *command, + Tcl_Size length); +/* 360 */ +EXTERN int Tcl_ParseBraces(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + Tcl_Parse *parsePtr, int append, + const char **termPtr); +/* 361 */ +EXTERN int Tcl_ParseCommand(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + int nested, Tcl_Parse *parsePtr); +/* 362 */ +EXTERN int Tcl_ParseExpr(Tcl_Interp *interp, const char *start, + Tcl_Size numBytes, Tcl_Parse *parsePtr); +/* 363 */ +EXTERN int Tcl_ParseQuotedString(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + Tcl_Parse *parsePtr, int append, + const char **termPtr); +/* 364 */ +EXTERN int Tcl_ParseVarName(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + Tcl_Parse *parsePtr, int append); +/* 365 */ +EXTERN char * Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr); +/* 366 */ +EXTERN int Tcl_Chdir(const char *dirName); +/* 367 */ +EXTERN int Tcl_Access(const char *path, int mode); +/* 368 */ +EXTERN int Tcl_Stat(const char *path, struct stat *bufPtr); +/* 369 */ +EXTERN int Tcl_UtfNcmp(const char *s1, const char *s2, + unsigned long n); +/* 370 */ +EXTERN int Tcl_UtfNcasecmp(const char *s1, const char *s2, + unsigned long n); +/* 371 */ +EXTERN int Tcl_StringCaseMatch(const char *str, + const char *pattern, int nocase); +/* 372 */ +EXTERN int Tcl_UniCharIsControl(int ch); +/* 373 */ +EXTERN int Tcl_UniCharIsGraph(int ch); +/* 374 */ +EXTERN int Tcl_UniCharIsPrint(int ch); +/* 375 */ +EXTERN int Tcl_UniCharIsPunct(int ch); +/* 376 */ +EXTERN int Tcl_RegExpExecObj(Tcl_Interp *interp, + Tcl_RegExp regexp, Tcl_Obj *textObj, + Tcl_Size offset, Tcl_Size nmatches, + int flags); +/* 377 */ +EXTERN void Tcl_RegExpGetInfo(Tcl_RegExp regexp, + Tcl_RegExpInfo *infoPtr); +/* 378 */ +EXTERN Tcl_Obj * Tcl_NewUnicodeObj(const unsigned short *unicode, + Tcl_Size numChars); +/* 379 */ +EXTERN void Tcl_SetUnicodeObj(Tcl_Obj *objPtr, + const unsigned short *unicode, + Tcl_Size numChars); +/* 380 */ +EXTERN Tcl_Size Tcl_GetCharLength(Tcl_Obj *objPtr); +/* 381 */ +EXTERN int Tcl_GetUniChar(Tcl_Obj *objPtr, Tcl_Size index); +/* 382 */ +TCL_DEPRECATED("No longer in use, changed to macro") +unsigned short * Tcl_GetUnicode(Tcl_Obj *objPtr); +/* 383 */ +EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, Tcl_Size first, + Tcl_Size last); +/* 384 */ +EXTERN void Tcl_AppendUnicodeToObj(Tcl_Obj *objPtr, + const unsigned short *unicode, + Tcl_Size length); +/* 385 */ +EXTERN int Tcl_RegExpMatchObj(Tcl_Interp *interp, + Tcl_Obj *textObj, Tcl_Obj *patternObj); +/* 386 */ +EXTERN void Tcl_SetNotifier( + const Tcl_NotifierProcs *notifierProcPtr); +/* 387 */ +EXTERN Tcl_Mutex * Tcl_GetAllocMutex(void); +/* 388 */ +EXTERN int Tcl_GetChannelNames(Tcl_Interp *interp); +/* 389 */ +EXTERN int Tcl_GetChannelNamesEx(Tcl_Interp *interp, + const char *pattern); +/* 390 */ +EXTERN int Tcl_ProcObjCmd(void *clientData, Tcl_Interp *interp, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 391 */ +EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr); +/* 392 */ +EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex); +/* 393 */ +EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr, + Tcl_ThreadCreateProc *proc, void *clientData, + TCL_HASH_TYPE stackSize, int flags); +/* 394 */ +EXTERN Tcl_Size Tcl_ReadRaw(Tcl_Channel chan, char *dst, + Tcl_Size bytesToRead); +/* 395 */ +EXTERN Tcl_Size Tcl_WriteRaw(Tcl_Channel chan, const char *src, + Tcl_Size srcLen); +/* 396 */ +EXTERN Tcl_Channel Tcl_GetTopChannel(Tcl_Channel chan); +/* 397 */ +EXTERN int Tcl_ChannelBuffered(Tcl_Channel chan); +/* 398 */ +EXTERN const char * Tcl_ChannelName(const Tcl_ChannelType *chanTypePtr); +/* 399 */ +EXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion( + const Tcl_ChannelType *chanTypePtr); +/* 400 */ +EXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc( + const Tcl_ChannelType *chanTypePtr); +/* 401 */ +TCL_DEPRECATED("Use Tcl_ChannelClose2Proc") +Tcl_DriverCloseProc * Tcl_ChannelCloseProc( + const Tcl_ChannelType *chanTypePtr); +/* 402 */ +EXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc( + const Tcl_ChannelType *chanTypePtr); +/* 403 */ +EXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc( + const Tcl_ChannelType *chanTypePtr); +/* 404 */ +EXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc( + const Tcl_ChannelType *chanTypePtr); +/* 405 */ +TCL_DEPRECATED("Use Tcl_ChannelWideSeekProc") +Tcl_DriverSeekProc * Tcl_ChannelSeekProc( + const Tcl_ChannelType *chanTypePtr); +/* 406 */ +EXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc( + const Tcl_ChannelType *chanTypePtr); +/* 407 */ +EXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc( + const Tcl_ChannelType *chanTypePtr); +/* 408 */ +EXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc( + const Tcl_ChannelType *chanTypePtr); +/* 409 */ +EXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc( + const Tcl_ChannelType *chanTypePtr); +/* 410 */ +EXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc( + const Tcl_ChannelType *chanTypePtr); +/* 411 */ +EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc( + const Tcl_ChannelType *chanTypePtr); +/* 412 */ +EXTERN int Tcl_JoinThread(Tcl_ThreadId threadId, int *result); +/* 413 */ +EXTERN int Tcl_IsChannelShared(Tcl_Channel channel); +/* 414 */ +EXTERN int Tcl_IsChannelRegistered(Tcl_Interp *interp, + Tcl_Channel channel); +/* 415 */ +EXTERN void Tcl_CutChannel(Tcl_Channel channel); +/* 416 */ +EXTERN void Tcl_SpliceChannel(Tcl_Channel channel); +/* 417 */ +EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel); +/* 418 */ +EXTERN int Tcl_IsChannelExisting(const char *channelName); +/* 419 */ +TCL_DEPRECATED("Use Tcl_UtfNcasecmp") +int Tcl_UniCharNcasecmp(const unsigned short *ucs, + const unsigned short *uct, + unsigned long numChars); +/* 420 */ +TCL_DEPRECATED("Use Tcl_StringCaseMatch") +int Tcl_UniCharCaseMatch(const unsigned short *uniStr, + const unsigned short *uniPattern, int nocase); +/* 421 */ +EXTERN Tcl_HashEntry * Tcl_FindHashEntry(Tcl_HashTable *tablePtr, + const void *key); +/* 422 */ +EXTERN Tcl_HashEntry * Tcl_CreateHashEntry(Tcl_HashTable *tablePtr, + const void *key, int *newPtr); +/* 423 */ +EXTERN void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, + int keyType, const Tcl_HashKeyType *typePtr); +/* 424 */ +EXTERN void Tcl_InitObjHashTable(Tcl_HashTable *tablePtr); +/* 425 */ +EXTERN void * Tcl_CommandTraceInfo(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *procPtr, + void *prevClientData); +/* 426 */ +EXTERN int Tcl_TraceCommand(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *proc, void *clientData); +/* 427 */ +EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *proc, void *clientData); +/* 428 */ +EXTERN char * Tcl_AttemptAlloc(TCL_HASH_TYPE size); +/* 429 */ +EXTERN char * Tcl_AttemptDbCkalloc(TCL_HASH_TYPE size, + const char *file, int line); +/* 430 */ +EXTERN char * Tcl_AttemptRealloc(char *ptr, TCL_HASH_TYPE size); +/* 431 */ +EXTERN char * Tcl_AttemptDbCkrealloc(char *ptr, TCL_HASH_TYPE size, + const char *file, int line); +/* 432 */ +EXTERN int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, + Tcl_Size length); +/* 433 */ +EXTERN Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel); +/* 434 */ +EXTERN unsigned short * Tcl_GetUnicodeFromObj(Tcl_Obj *objPtr, + int *lengthPtr); +/* 435 */ +TCL_DEPRECATED("") +int Tcl_GetMathFuncInfo(Tcl_Interp *interp, + const char *name, int *numArgsPtr, + Tcl_ValueType **argTypesPtr, + Tcl_MathProc **procPtr, void **clientDataPtr); +/* 436 */ +TCL_DEPRECATED("") +Tcl_Obj * Tcl_ListMathFuncs(Tcl_Interp *interp, + const char *pattern); +/* 437 */ +EXTERN Tcl_Obj * Tcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 438 */ +EXTERN int Tcl_DetachChannel(Tcl_Interp *interp, + Tcl_Channel channel); +/* 439 */ +EXTERN int Tcl_IsStandardChannel(Tcl_Channel channel); +/* 440 */ +EXTERN int Tcl_FSCopyFile(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr); +/* 441 */ +EXTERN int Tcl_FSCopyDirectory(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); +/* 442 */ +EXTERN int Tcl_FSCreateDirectory(Tcl_Obj *pathPtr); +/* 443 */ +EXTERN int Tcl_FSDeleteFile(Tcl_Obj *pathPtr); +/* 444 */ +EXTERN int Tcl_FSLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, + const char *sym1, const char *sym2, + Tcl_LibraryInitProc **proc1Ptr, + Tcl_LibraryInitProc **proc2Ptr, + Tcl_LoadHandle *handlePtr, + Tcl_FSUnloadFileProc **unloadProcPtr); +/* 445 */ +EXTERN int Tcl_FSMatchInDirectory(Tcl_Interp *interp, + Tcl_Obj *result, Tcl_Obj *pathPtr, + const char *pattern, Tcl_GlobTypeData *types); +/* 446 */ +EXTERN Tcl_Obj * Tcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr, + int linkAction); +/* 447 */ +EXTERN int Tcl_FSRemoveDirectory(Tcl_Obj *pathPtr, + int recursive, Tcl_Obj **errorPtr); +/* 448 */ +EXTERN int Tcl_FSRenameFile(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr); +/* 449 */ +EXTERN int Tcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +/* 450 */ +EXTERN int Tcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval); +/* 451 */ +EXTERN int Tcl_FSFileAttrsGet(Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); +/* 452 */ +EXTERN int Tcl_FSFileAttrsSet(Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj *objPtr); +/* 453 */ +EXTERN const char *CONST86 * Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr, + Tcl_Obj **objPtrRef); +/* 454 */ +EXTERN int Tcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +/* 455 */ +EXTERN int Tcl_FSAccess(Tcl_Obj *pathPtr, int mode); +/* 456 */ +EXTERN Tcl_Channel Tcl_FSOpenFileChannel(Tcl_Interp *interp, + Tcl_Obj *pathPtr, const char *modeString, + int permissions); +/* 457 */ +EXTERN Tcl_Obj * Tcl_FSGetCwd(Tcl_Interp *interp); +/* 458 */ +EXTERN int Tcl_FSChdir(Tcl_Obj *pathPtr); +/* 459 */ +EXTERN int Tcl_FSConvertToPathType(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 460 */ +EXTERN Tcl_Obj * Tcl_FSJoinPath(Tcl_Obj *listObj, Tcl_Size elements); +/* 461 */ +EXTERN Tcl_Obj * Tcl_FSSplitPath(Tcl_Obj *pathPtr, int *lenPtr); +/* 462 */ +EXTERN int Tcl_FSEqualPaths(Tcl_Obj *firstPtr, + Tcl_Obj *secondPtr); +/* 463 */ +EXTERN Tcl_Obj * Tcl_FSGetNormalizedPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 464 */ +EXTERN Tcl_Obj * Tcl_FSJoinToPath(Tcl_Obj *pathPtr, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* 465 */ +EXTERN void * Tcl_FSGetInternalRep(Tcl_Obj *pathPtr, + const Tcl_Filesystem *fsPtr); +/* 466 */ +EXTERN Tcl_Obj * Tcl_FSGetTranslatedPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 467 */ +EXTERN int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName); +/* 468 */ +EXTERN Tcl_Obj * Tcl_FSNewNativePath( + const Tcl_Filesystem *fromFilesystem, + void *clientData); +/* 469 */ +EXTERN const void * Tcl_FSGetNativePath(Tcl_Obj *pathPtr); +/* 470 */ +EXTERN Tcl_Obj * Tcl_FSFileSystemInfo(Tcl_Obj *pathPtr); +/* 471 */ +EXTERN Tcl_Obj * Tcl_FSPathSeparator(Tcl_Obj *pathPtr); +/* 472 */ +EXTERN Tcl_Obj * Tcl_FSListVolumes(void); +/* 473 */ +EXTERN int Tcl_FSRegister(void *clientData, + const Tcl_Filesystem *fsPtr); +/* 474 */ +EXTERN int Tcl_FSUnregister(const Tcl_Filesystem *fsPtr); +/* 475 */ +EXTERN void * Tcl_FSData(const Tcl_Filesystem *fsPtr); +/* 476 */ +EXTERN const char * Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 477 */ +EXTERN CONST86 Tcl_Filesystem * Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr); +/* 478 */ +EXTERN Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr); +/* 479 */ +EXTERN int Tcl_OutputBuffered(Tcl_Channel chan); +/* 480 */ +EXTERN void Tcl_FSMountsChanged(const Tcl_Filesystem *fsPtr); +/* 481 */ +EXTERN int Tcl_EvalTokensStandard(Tcl_Interp *interp, + Tcl_Token *tokenPtr, Tcl_Size count); +/* 482 */ +EXTERN void Tcl_GetTime(Tcl_Time *timeBuf); +/* 483 */ +EXTERN Tcl_Trace Tcl_CreateObjTrace(Tcl_Interp *interp, + Tcl_Size level, int flags, + Tcl_CmdObjTraceProc *objProc, + void *clientData, + Tcl_CmdObjTraceDeleteProc *delProc); +/* 484 */ +EXTERN int Tcl_GetCommandInfoFromToken(Tcl_Command token, + Tcl_CmdInfo *infoPtr); +/* 485 */ +EXTERN int Tcl_SetCommandInfoFromToken(Tcl_Command token, + const Tcl_CmdInfo *infoPtr); +/* 486 */ +EXTERN Tcl_Obj * Tcl_DbNewWideIntObj(Tcl_WideInt wideValue, + const char *file, int line); +/* 487 */ +EXTERN int Tcl_GetWideIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_WideInt *widePtr); +/* 488 */ +EXTERN Tcl_Obj * Tcl_NewWideIntObj(Tcl_WideInt wideValue); +/* 489 */ +EXTERN void Tcl_SetWideIntObj(Tcl_Obj *objPtr, + Tcl_WideInt wideValue); +/* 490 */ +EXTERN Tcl_StatBuf * Tcl_AllocStatBuf(void); +/* 491 */ +EXTERN long long Tcl_Seek(Tcl_Channel chan, long long offset, + int mode); +/* 492 */ +EXTERN long long Tcl_Tell(Tcl_Channel chan); +/* 493 */ +EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc( + const Tcl_ChannelType *chanTypePtr); +/* 494 */ +EXTERN int Tcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); +/* 495 */ +EXTERN int Tcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); +/* 496 */ +EXTERN int Tcl_DictObjRemove(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); +/* 497 */ +EXTERN int Tcl_DictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr, + int *sizePtr); +/* 498 */ +EXTERN int Tcl_DictObjFirst(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, + Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, + int *donePtr); +/* 499 */ +EXTERN void Tcl_DictObjNext(Tcl_DictSearch *searchPtr, + Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, + int *donePtr); +/* 500 */ +EXTERN void Tcl_DictObjDone(Tcl_DictSearch *searchPtr); +/* 501 */ +EXTERN int Tcl_DictObjPutKeyList(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Size keyc, + Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); +/* 502 */ +EXTERN int Tcl_DictObjRemoveKeyList(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Size keyc, + Tcl_Obj *const *keyv); +/* 503 */ +EXTERN Tcl_Obj * Tcl_NewDictObj(void); +/* 504 */ +EXTERN Tcl_Obj * Tcl_DbNewDictObj(const char *file, int line); +/* 505 */ +EXTERN void Tcl_RegisterConfig(Tcl_Interp *interp, + const char *pkgName, + const Tcl_Config *configuration, + const char *valEncoding); +/* 506 */ +EXTERN Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp, + const char *name, void *clientData, + Tcl_NamespaceDeleteProc *deleteProc); +/* 507 */ +EXTERN void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr); +/* 508 */ +EXTERN int Tcl_AppendExportList(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); +/* 509 */ +EXTERN int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr, + const char *pattern, int resetListFirst); +/* 510 */ +EXTERN int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr, + const char *pattern, int allowOverwrite); +/* 511 */ +EXTERN int Tcl_ForgetImport(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, const char *pattern); +/* 512 */ +EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp); +/* 513 */ +EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp); +/* 514 */ +EXTERN Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp, + const char *name, + Tcl_Namespace *contextNsPtr, int flags); +/* 515 */ +EXTERN Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, const char *name, + Tcl_Namespace *contextNsPtr, int flags); +/* 516 */ +EXTERN Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 517 */ +EXTERN void Tcl_GetCommandFullName(Tcl_Interp *interp, + Tcl_Command command, Tcl_Obj *objPtr); +/* 518 */ +EXTERN int Tcl_FSEvalFileEx(Tcl_Interp *interp, + Tcl_Obj *fileName, const char *encodingName); +/* 519 */ +EXTERN Tcl_ExitProc * Tcl_SetExitProc(TCL_NORETURN1 Tcl_ExitProc *proc); +/* 520 */ +EXTERN void Tcl_LimitAddHandler(Tcl_Interp *interp, int type, + Tcl_LimitHandlerProc *handlerProc, + void *clientData, + Tcl_LimitHandlerDeleteProc *deleteProc); +/* 521 */ +EXTERN void Tcl_LimitRemoveHandler(Tcl_Interp *interp, int type, + Tcl_LimitHandlerProc *handlerProc, + void *clientData); +/* 522 */ +EXTERN int Tcl_LimitReady(Tcl_Interp *interp); +/* 523 */ +EXTERN int Tcl_LimitCheck(Tcl_Interp *interp); +/* 524 */ +EXTERN int Tcl_LimitExceeded(Tcl_Interp *interp); +/* 525 */ +EXTERN void Tcl_LimitSetCommands(Tcl_Interp *interp, + Tcl_Size commandLimit); +/* 526 */ +EXTERN void Tcl_LimitSetTime(Tcl_Interp *interp, + Tcl_Time *timeLimitPtr); +/* 527 */ +EXTERN void Tcl_LimitSetGranularity(Tcl_Interp *interp, int type, + int granularity); +/* 528 */ +EXTERN int Tcl_LimitTypeEnabled(Tcl_Interp *interp, int type); +/* 529 */ +EXTERN int Tcl_LimitTypeExceeded(Tcl_Interp *interp, int type); +/* 530 */ +EXTERN void Tcl_LimitTypeSet(Tcl_Interp *interp, int type); +/* 531 */ +EXTERN void Tcl_LimitTypeReset(Tcl_Interp *interp, int type); +/* 532 */ +EXTERN int Tcl_LimitGetCommands(Tcl_Interp *interp); +/* 533 */ +EXTERN void Tcl_LimitGetTime(Tcl_Interp *interp, + Tcl_Time *timeLimitPtr); +/* 534 */ +EXTERN int Tcl_LimitGetGranularity(Tcl_Interp *interp, int type); +/* 535 */ +EXTERN Tcl_InterpState Tcl_SaveInterpState(Tcl_Interp *interp, int status); +/* 536 */ +EXTERN int Tcl_RestoreInterpState(Tcl_Interp *interp, + Tcl_InterpState state); +/* 537 */ +EXTERN void Tcl_DiscardInterpState(Tcl_InterpState state); +/* 538 */ +EXTERN int Tcl_SetReturnOptions(Tcl_Interp *interp, + Tcl_Obj *options); +/* 539 */ +EXTERN Tcl_Obj * Tcl_GetReturnOptions(Tcl_Interp *interp, int result); +/* 540 */ +EXTERN int Tcl_IsEnsemble(Tcl_Command token); +/* 541 */ +EXTERN Tcl_Command Tcl_CreateEnsemble(Tcl_Interp *interp, + const char *name, + Tcl_Namespace *namespacePtr, int flags); +/* 542 */ +EXTERN Tcl_Command Tcl_FindEnsemble(Tcl_Interp *interp, + Tcl_Obj *cmdNameObj, int flags); +/* 543 */ +EXTERN int Tcl_SetEnsembleSubcommandList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *subcmdList); +/* 544 */ +EXTERN int Tcl_SetEnsembleMappingDict(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *mapDict); +/* 545 */ +EXTERN int Tcl_SetEnsembleUnknownHandler(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *unknownList); +/* 546 */ +EXTERN int Tcl_SetEnsembleFlags(Tcl_Interp *interp, + Tcl_Command token, int flags); +/* 547 */ +EXTERN int Tcl_GetEnsembleSubcommandList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **subcmdListPtr); +/* 548 */ +EXTERN int Tcl_GetEnsembleMappingDict(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **mapDictPtr); +/* 549 */ +EXTERN int Tcl_GetEnsembleUnknownHandler(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **unknownListPtr); +/* 550 */ +EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp, + Tcl_Command token, int *flagsPtr); +/* 551 */ +EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, + Tcl_Command token, + Tcl_Namespace **namespacePtrPtr); +/* 552 */ +EXTERN void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc, + Tcl_ScaleTimeProc *scaleProc, + void *clientData); +/* 553 */ +EXTERN void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc, + Tcl_ScaleTimeProc **scaleProc, + void **clientData); +/* 554 */ +EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc( + const Tcl_ChannelType *chanTypePtr); +/* 555 */ +EXTERN Tcl_Obj * Tcl_NewBignumObj(void *value); +/* 556 */ +EXTERN Tcl_Obj * Tcl_DbNewBignumObj(void *value, const char *file, + int line); +/* 557 */ +EXTERN void Tcl_SetBignumObj(Tcl_Obj *obj, void *value); +/* 558 */ +EXTERN int Tcl_GetBignumFromObj(Tcl_Interp *interp, + Tcl_Obj *obj, void *value); +/* 559 */ +EXTERN int Tcl_TakeBignumFromObj(Tcl_Interp *interp, + Tcl_Obj *obj, void *value); +/* 560 */ +EXTERN int Tcl_TruncateChannel(Tcl_Channel chan, + long long length); +/* 561 */ +EXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc( + const Tcl_ChannelType *chanTypePtr); +/* 562 */ +EXTERN void Tcl_SetChannelErrorInterp(Tcl_Interp *interp, + Tcl_Obj *msg); +/* 563 */ +EXTERN void Tcl_GetChannelErrorInterp(Tcl_Interp *interp, + Tcl_Obj **msg); +/* 564 */ +EXTERN void Tcl_SetChannelError(Tcl_Channel chan, Tcl_Obj *msg); +/* 565 */ +EXTERN void Tcl_GetChannelError(Tcl_Channel chan, Tcl_Obj **msg); +/* 566 */ +EXTERN int Tcl_InitBignumFromDouble(Tcl_Interp *interp, + double initval, void *toInit); +/* 567 */ +EXTERN Tcl_Obj * Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp, + Tcl_Namespace *nsPtr); +/* 568 */ +EXTERN int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); +/* 569 */ +EXTERN int Tcl_GetEncodingFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); +/* 570 */ +EXTERN Tcl_Obj * Tcl_GetEncodingSearchPath(void); +/* 571 */ +EXTERN int Tcl_SetEncodingSearchPath(Tcl_Obj *searchPath); +/* 572 */ +EXTERN const char * Tcl_GetEncodingNameFromEnvironment( + Tcl_DString *bufPtr); +/* 573 */ +EXTERN int Tcl_PkgRequireProc(Tcl_Interp *interp, + const char *name, Tcl_Size objc, + Tcl_Obj *const objv[], void *clientDataPtr); +/* 574 */ +EXTERN void Tcl_AppendObjToErrorInfo(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 575 */ +EXTERN void Tcl_AppendLimitedToObj(Tcl_Obj *objPtr, + const char *bytes, Tcl_Size length, + Tcl_Size limit, const char *ellipsis); +/* 576 */ +EXTERN Tcl_Obj * Tcl_Format(Tcl_Interp *interp, const char *format, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 577 */ +EXTERN int Tcl_AppendFormatToObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, const char *format, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 578 */ +EXTERN Tcl_Obj * Tcl_ObjPrintf(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); +/* 579 */ +EXTERN void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr, + const char *format, ...) TCL_FORMAT_PRINTF(2, 3); +/* 580 */ +EXTERN int Tcl_CancelEval(Tcl_Interp *interp, + Tcl_Obj *resultObjPtr, void *clientData, + int flags); +/* 581 */ +EXTERN int Tcl_Canceled(Tcl_Interp *interp, int flags); +/* 582 */ +EXTERN int Tcl_CreatePipe(Tcl_Interp *interp, + Tcl_Channel *rchan, Tcl_Channel *wchan, + int flags); +/* 583 */ +EXTERN Tcl_Command Tcl_NRCreateCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc *proc, + Tcl_ObjCmdProc *nreProc, void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 584 */ +EXTERN int Tcl_NREvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 585 */ +EXTERN int Tcl_NREvalObjv(Tcl_Interp *interp, Tcl_Size objc, + Tcl_Obj *const objv[], int flags); +/* 586 */ +EXTERN int Tcl_NRCmdSwap(Tcl_Interp *interp, Tcl_Command cmd, + Tcl_Size objc, Tcl_Obj *const objv[], + int flags); +/* 587 */ +EXTERN void Tcl_NRAddCallback(Tcl_Interp *interp, + Tcl_NRPostProc *postProcPtr, void *data0, + void *data1, void *data2, void *data3); +/* 588 */ +EXTERN int Tcl_NRCallObjProc(Tcl_Interp *interp, + Tcl_ObjCmdProc *objProc, void *clientData, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 589 */ +EXTERN unsigned Tcl_GetFSDeviceFromStat(const Tcl_StatBuf *statPtr); +/* 590 */ +EXTERN unsigned Tcl_GetFSInodeFromStat(const Tcl_StatBuf *statPtr); +/* 591 */ +EXTERN unsigned Tcl_GetModeFromStat(const Tcl_StatBuf *statPtr); +/* 592 */ +EXTERN int Tcl_GetLinkCountFromStat(const Tcl_StatBuf *statPtr); +/* 593 */ +EXTERN int Tcl_GetUserIdFromStat(const Tcl_StatBuf *statPtr); +/* 594 */ +EXTERN int Tcl_GetGroupIdFromStat(const Tcl_StatBuf *statPtr); +/* 595 */ +EXTERN int Tcl_GetDeviceTypeFromStat(const Tcl_StatBuf *statPtr); +/* 596 */ +EXTERN long long Tcl_GetAccessTimeFromStat(const Tcl_StatBuf *statPtr); +/* 597 */ +EXTERN long long Tcl_GetModificationTimeFromStat( + const Tcl_StatBuf *statPtr); +/* 598 */ +EXTERN long long Tcl_GetChangeTimeFromStat(const Tcl_StatBuf *statPtr); +/* 599 */ +EXTERN unsigned long long Tcl_GetSizeFromStat(const Tcl_StatBuf *statPtr); +/* 600 */ +EXTERN unsigned long long Tcl_GetBlocksFromStat(const Tcl_StatBuf *statPtr); +/* 601 */ +EXTERN unsigned Tcl_GetBlockSizeFromStat(const Tcl_StatBuf *statPtr); +/* 602 */ +EXTERN int Tcl_SetEnsembleParameterList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *paramList); +/* 603 */ +EXTERN int Tcl_GetEnsembleParameterList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **paramListPtr); +/* 604 */ +EXTERN int Tcl_ParseArgsObjv(Tcl_Interp *interp, + const Tcl_ArgvInfo *argTable, int *objcPtr, + Tcl_Obj *const *objv, Tcl_Obj ***remObjv); +/* 605 */ +EXTERN int Tcl_GetErrorLine(Tcl_Interp *interp); +/* 606 */ +EXTERN void Tcl_SetErrorLine(Tcl_Interp *interp, int lineNum); +/* 607 */ +EXTERN void Tcl_TransferResult(Tcl_Interp *sourceInterp, + int code, Tcl_Interp *targetInterp); +/* 608 */ +EXTERN int Tcl_InterpActive(Tcl_Interp *interp); +/* 609 */ +EXTERN void Tcl_BackgroundException(Tcl_Interp *interp, int code); +/* 610 */ +EXTERN int Tcl_ZlibDeflate(Tcl_Interp *interp, int format, + Tcl_Obj *data, int level, + Tcl_Obj *gzipHeaderDictObj); +/* 611 */ +EXTERN int Tcl_ZlibInflate(Tcl_Interp *interp, int format, + Tcl_Obj *data, Tcl_Size buffersize, + Tcl_Obj *gzipHeaderDictObj); +/* 612 */ +EXTERN unsigned int Tcl_ZlibCRC32(unsigned int crc, + const unsigned char *buf, Tcl_Size len); +/* 613 */ +EXTERN unsigned int Tcl_ZlibAdler32(unsigned int adler, + const unsigned char *buf, Tcl_Size len); +/* 614 */ +EXTERN int Tcl_ZlibStreamInit(Tcl_Interp *interp, int mode, + int format, int level, Tcl_Obj *dictObj, + Tcl_ZlibStream *zshandle); +/* 615 */ +EXTERN Tcl_Obj * Tcl_ZlibStreamGetCommandName(Tcl_ZlibStream zshandle); +/* 616 */ +EXTERN int Tcl_ZlibStreamEof(Tcl_ZlibStream zshandle); +/* 617 */ +EXTERN int Tcl_ZlibStreamChecksum(Tcl_ZlibStream zshandle); +/* 618 */ +EXTERN int Tcl_ZlibStreamPut(Tcl_ZlibStream zshandle, + Tcl_Obj *data, int flush); +/* 619 */ +EXTERN int Tcl_ZlibStreamGet(Tcl_ZlibStream zshandle, + Tcl_Obj *data, Tcl_Size count); +/* 620 */ +EXTERN int Tcl_ZlibStreamClose(Tcl_ZlibStream zshandle); +/* 621 */ +EXTERN int Tcl_ZlibStreamReset(Tcl_ZlibStream zshandle); +/* 622 */ +EXTERN void Tcl_SetStartupScript(Tcl_Obj *path, + const char *encoding); +/* 623 */ +EXTERN Tcl_Obj * Tcl_GetStartupScript(const char **encodingPtr); +/* 624 */ +EXTERN int Tcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan, + int flags); +/* 625 */ +EXTERN int Tcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + Tcl_Obj *resultPtr); +/* 626 */ +EXTERN int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 627 */ +EXTERN int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, + const char *const symv[], int flags, + void *procPtrs, Tcl_LoadHandle *handlePtr); +/* 628 */ +EXTERN void * Tcl_FindSymbol(Tcl_Interp *interp, + Tcl_LoadHandle handle, const char *symbol); +/* 629 */ +EXTERN int Tcl_FSUnloadFile(Tcl_Interp *interp, + Tcl_LoadHandle handlePtr); +/* 630 */ +EXTERN void Tcl_ZlibStreamSetCompressionDictionary( + Tcl_ZlibStream zhandle, + Tcl_Obj *compressionDictionaryObj); +/* 631 */ +EXTERN Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp, + const char *service, const char *host, + unsigned int flags, int backlog, + Tcl_TcpAcceptProc *acceptProc, + void *callbackData); +/* 632 */ +EXTERN int TclZipfs_Mount(Tcl_Interp *interp, + const char *zipname, const char *mountPoint, + const char *passwd); +/* 633 */ +EXTERN int TclZipfs_Unmount(Tcl_Interp *interp, + const char *mountPoint); +/* 634 */ +EXTERN Tcl_Obj * TclZipfs_TclLibrary(void); +/* 635 */ +EXTERN int TclZipfs_MountBuffer(Tcl_Interp *interp, + const void *data, size_t datalen, + const char *mountPoint, int copy); +/* 636 */ +EXTERN void Tcl_FreeInternalRep(Tcl_Obj *objPtr); +/* 637 */ +EXTERN char * Tcl_InitStringRep(Tcl_Obj *objPtr, const char *bytes, + TCL_HASH_TYPE numBytes); +/* 638 */ +EXTERN Tcl_ObjInternalRep * Tcl_FetchInternalRep(Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr); +/* 639 */ +EXTERN void Tcl_StoreInternalRep(Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr, + const Tcl_ObjInternalRep *irPtr); +/* 640 */ +EXTERN int Tcl_HasStringRep(Tcl_Obj *objPtr); +/* 641 */ +EXTERN void Tcl_IncrRefCount(Tcl_Obj *objPtr); +/* 642 */ +EXTERN void Tcl_DecrRefCount(Tcl_Obj *objPtr); +/* 643 */ +EXTERN int Tcl_IsShared(Tcl_Obj *objPtr); +/* 644 */ +EXTERN int Tcl_LinkArray(Tcl_Interp *interp, + const char *varName, void *addr, int type, + Tcl_Size size); +/* 645 */ +EXTERN int Tcl_GetIntForIndex(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Size endValue, + Tcl_Size *indexPtr); +/* 646 */ +EXTERN Tcl_Size Tcl_UtfToUniChar(const char *src, int *chPtr); +/* 647 */ +EXTERN char * Tcl_UniCharToUtfDString(const int *uniStr, + Tcl_Size uniLength, Tcl_DString *dsPtr); +/* 648 */ +EXTERN int * Tcl_UtfToUniCharDString(const char *src, + Tcl_Size length, Tcl_DString *dsPtr); +/* 649 */ +EXTERN unsigned char * Tcl_GetBytesFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *numBytesPtr); +/* Slot 650 is reserved */ +/* Slot 651 is reserved */ +/* Slot 652 is reserved */ +/* Slot 653 is reserved */ +/* 654 */ +EXTERN int Tcl_UtfCharComplete(const char *src, Tcl_Size length); +/* 655 */ +EXTERN const char * Tcl_UtfNext(const char *src); +/* 656 */ +EXTERN const char * Tcl_UtfPrev(const char *src, const char *start); +/* 657 */ +EXTERN int Tcl_UniCharIsUnicode(int ch); +/* 658 */ +EXTERN int Tcl_ExternalToUtfDStringEx(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_DString *dsPtr, + Tcl_Size *errorLocationPtr); +/* 659 */ +EXTERN int Tcl_UtfToExternalDStringEx(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_DString *dsPtr, + Tcl_Size *errorLocationPtr); +/* 660 */ +EXTERN int Tcl_AsyncMarkFromSignal(Tcl_AsyncHandler async, + int sigNumber); +/* Slot 661 is reserved */ +/* Slot 662 is reserved */ +/* Slot 663 is reserved */ +/* Slot 664 is reserved */ +/* Slot 665 is reserved */ +/* Slot 666 is reserved */ +/* Slot 667 is reserved */ +/* 668 */ +EXTERN Tcl_Size Tcl_UniCharLen(const int *uniStr); +/* 669 */ +EXTERN Tcl_Size TclNumUtfChars(const char *src, Tcl_Size length); +/* 670 */ +EXTERN Tcl_Size TclGetCharLength(Tcl_Obj *objPtr); +/* 671 */ +EXTERN const char * TclUtfAtIndex(const char *src, Tcl_Size index); +/* 672 */ +EXTERN Tcl_Obj * TclGetRange(Tcl_Obj *objPtr, Tcl_Size first, + Tcl_Size last); +/* 673 */ +EXTERN int TclGetUniChar(Tcl_Obj *objPtr, Tcl_Size index); +/* 674 */ +EXTERN int Tcl_GetBool(Tcl_Interp *interp, const char *src, + int flags, char *charPtr); +/* 675 */ +EXTERN int Tcl_GetBoolFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int flags, char *charPtr); +/* Slot 676 is reserved */ +/* Slot 677 is reserved */ +/* Slot 678 is reserved */ +/* Slot 679 is reserved */ +/* 680 */ +EXTERN int Tcl_GetNumberFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, void **clientDataPtr, + int *typePtr); +/* 681 */ +EXTERN int Tcl_GetNumber(Tcl_Interp *interp, const char *bytes, + Tcl_Size numBytes, void **clientDataPtr, + int *typePtr); +/* 682 */ +EXTERN int Tcl_RemoveChannelMode(Tcl_Interp *interp, + Tcl_Channel chan, int mode); +/* 683 */ +EXTERN Tcl_Size Tcl_GetEncodingNulLength(Tcl_Encoding encoding); +/* 684 */ +EXTERN int Tcl_GetWideUIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr); +/* 685 */ +EXTERN Tcl_Obj * Tcl_DStringToObj(Tcl_DString *dsPtr); +/* Slot 686 is reserved */ +/* Slot 687 is reserved */ +/* 688 */ +EXTERN void TclUnusedStubEntry(void); + +typedef struct { + const struct TclPlatStubs *tclPlatStubs; + const struct TclIntStubs *tclIntStubs; + const struct TclIntPlatStubs *tclIntPlatStubs; +} TclStubHooks; + +typedef struct TclStubs { + int magic; + const TclStubHooks *hooks; + + int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */ + const char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */ + TCL_NORETURN1 void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */ + char * (*tcl_Alloc) (TCL_HASH_TYPE size); /* 3 */ + void (*tcl_Free) (char *ptr); /* 4 */ + char * (*tcl_Realloc) (char *ptr, TCL_HASH_TYPE size); /* 5 */ + char * (*tcl_DbCkalloc) (TCL_HASH_TYPE size, const char *file, int line); /* 6 */ + void (*tcl_DbCkfree) (char *ptr, const char *file, int line); /* 7 */ + char * (*tcl_DbCkrealloc) (char *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 8 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ + void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, void *clientData); /* 9 */ +#endif /* UNIX */ +#if defined(_WIN32) /* WIN */ + void (*reserved9)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, void *clientData); /* 9 */ +#endif /* MACOSX */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ + void (*tcl_DeleteFileHandler) (int fd); /* 10 */ +#endif /* UNIX */ +#if defined(_WIN32) /* WIN */ + void (*reserved10)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + void (*tcl_DeleteFileHandler) (int fd); /* 10 */ +#endif /* MACOSX */ + void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */ + void (*tcl_Sleep) (int ms); /* 12 */ + int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */ + int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */ + void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */ + void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* 16 */ + Tcl_Obj * (*tcl_ConcatObj) (Tcl_Size objc, Tcl_Obj *const objv[]); /* 17 */ + int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */ + void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */ + void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */ + int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_DbNewBooleanObj) (int intValue, const char *file, int line); /* 22 */ + Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, Tcl_Size numBytes, const char *file, int line); /* 23 */ + Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */ + Tcl_Obj * (*tcl_DbNewListObj) (Tcl_Size objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */ + Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */ + Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, Tcl_Size length, const char *file, int line); /* 28 */ + Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */ + void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */ + int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *intPtr); /* 31 */ + int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 32 */ + unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, Tcl_Size *numBytesPtr); /* 33 */ + int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */ + int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */ + int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */ + int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */ + int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */ + CONST86 Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */ + char * (*tcl_GetStringFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 41 */ + void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */ + int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */ + int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */ + int (*tcl_ListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr); /* 45 */ + int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size index, Tcl_Obj **objPtrPtr); /* 46 */ + int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */ + int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first, Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[]); /* 48 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewBooleanObj) (int intValue); /* 49 */ + Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, Tcl_Size numBytes); /* 50 */ + Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */ + Tcl_Obj * (*tcl_NewListObj) (Tcl_Size objc, Tcl_Obj *const objv[]); /* 53 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */ + Tcl_Obj * (*tcl_NewObj) (void); /* 55 */ + Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, Tcl_Size length); /* 56 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int intValue); /* 57 */ + unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, Tcl_Size numBytes); /* 58 */ + void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, Tcl_Size numBytes); /* 59 */ + void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */ + void (*tcl_SetListObj) (Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[]); /* 62 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */ + void (*tcl_SetObjLength) (Tcl_Obj *objPtr, Tcl_Size length); /* 64 */ + void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* 65 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, Tcl_Size length); /* 67 */ + void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */ + void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */ + void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */ + Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, void *clientData); /* 71 */ + void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */ + int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */ + void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */ + int (*tcl_AsyncReady) (void); /* 75 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_BackgroundError) (Tcl_Interp *interp); /* 76 */ + TCL_DEPRECATED_API("Use Tcl_UtfBackslash") char (*tcl_Backslash) (const char *src, int *readPtr); /* 77 */ + int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */ + void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, void *clientData); /* 79 */ + void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, void *clientData); /* 80 */ + int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */ + int (*tcl_CommandComplete) (const char *cmd); /* 82 */ + char * (*tcl_Concat) (Tcl_Size argc, const char *const *argv); /* 83 */ + Tcl_Size (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */ + Tcl_Size (*tcl_ConvertCountedElement) (const char *src, Tcl_Size length, char *dst, int flags); /* 85 */ + int (*tcl_CreateAlias) (Tcl_Interp *childInterp, const char *childCmd, Tcl_Interp *target, const char *targetCmd, Tcl_Size argc, const char *const *argv); /* 86 */ + int (*tcl_CreateAliasObj) (Tcl_Interp *childInterp, const char *childCmd, Tcl_Interp *target, const char *targetCmd, Tcl_Size objc, Tcl_Obj *const objv[]); /* 87 */ + Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, void *instanceData, int mask); /* 88 */ + void (*tcl_CreateChannelHandler) (Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, void *clientData); /* 89 */ + void (*tcl_CreateCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, void *clientData); /* 90 */ + Tcl_Command (*tcl_CreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 91 */ + void (*tcl_CreateEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, void *clientData); /* 92 */ + void (*tcl_CreateExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 93 */ + Tcl_Interp * (*tcl_CreateInterp) (void); /* 94 */ + TCL_DEPRECATED_API("") void (*tcl_CreateMathFunc) (Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, void *clientData); /* 95 */ + Tcl_Command (*tcl_CreateObjCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 96 */ + Tcl_Interp * (*tcl_CreateChild) (Tcl_Interp *interp, const char *name, int isSafe); /* 97 */ + Tcl_TimerToken (*tcl_CreateTimerHandler) (int milliseconds, Tcl_TimerProc *proc, void *clientData); /* 98 */ + Tcl_Trace (*tcl_CreateTrace) (Tcl_Interp *interp, Tcl_Size level, Tcl_CmdTraceProc *proc, void *clientData); /* 99 */ + void (*tcl_DeleteAssocData) (Tcl_Interp *interp, const char *name); /* 100 */ + void (*tcl_DeleteChannelHandler) (Tcl_Channel chan, Tcl_ChannelProc *proc, void *clientData); /* 101 */ + void (*tcl_DeleteCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, void *clientData); /* 102 */ + int (*tcl_DeleteCommand) (Tcl_Interp *interp, const char *cmdName); /* 103 */ + int (*tcl_DeleteCommandFromToken) (Tcl_Interp *interp, Tcl_Command command); /* 104 */ + void (*tcl_DeleteEvents) (Tcl_EventDeleteProc *proc, void *clientData); /* 105 */ + void (*tcl_DeleteEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, void *clientData); /* 106 */ + void (*tcl_DeleteExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 107 */ + void (*tcl_DeleteHashEntry) (Tcl_HashEntry *entryPtr); /* 108 */ + void (*tcl_DeleteHashTable) (Tcl_HashTable *tablePtr); /* 109 */ + void (*tcl_DeleteInterp) (Tcl_Interp *interp); /* 110 */ + void (*tcl_DetachPids) (Tcl_Size numPids, Tcl_Pid *pidPtr); /* 111 */ + void (*tcl_DeleteTimerHandler) (Tcl_TimerToken token); /* 112 */ + void (*tcl_DeleteTrace) (Tcl_Interp *interp, Tcl_Trace trace); /* 113 */ + void (*tcl_DontCallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, void *clientData); /* 114 */ + int (*tcl_DoOneEvent) (int flags); /* 115 */ + void (*tcl_DoWhenIdle) (Tcl_IdleProc *proc, void *clientData); /* 116 */ + char * (*tcl_DStringAppend) (Tcl_DString *dsPtr, const char *bytes, Tcl_Size length); /* 117 */ + char * (*tcl_DStringAppendElement) (Tcl_DString *dsPtr, const char *element); /* 118 */ + void (*tcl_DStringEndSublist) (Tcl_DString *dsPtr); /* 119 */ + void (*tcl_DStringFree) (Tcl_DString *dsPtr); /* 120 */ + void (*tcl_DStringGetResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 121 */ + void (*tcl_DStringInit) (Tcl_DString *dsPtr); /* 122 */ + void (*tcl_DStringResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 123 */ + void (*tcl_DStringSetLength) (Tcl_DString *dsPtr, Tcl_Size length); /* 124 */ + void (*tcl_DStringStartSublist) (Tcl_DString *dsPtr); /* 125 */ + int (*tcl_Eof) (Tcl_Channel chan); /* 126 */ + const char * (*tcl_ErrnoId) (void); /* 127 */ + const char * (*tcl_ErrnoMsg) (int err); /* 128 */ + int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */ + int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */ + void (*tcl_EventuallyFree) (void *clientData, Tcl_FreeProc *freeProc); /* 132 */ + TCL_NORETURN1 void (*tcl_Exit) (int status); /* 133 */ + int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */ + int (*tcl_ExprBoolean) (Tcl_Interp *interp, const char *expr, int *ptr); /* 135 */ + int (*tcl_ExprBooleanObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 136 */ + int (*tcl_ExprDouble) (Tcl_Interp *interp, const char *expr, double *ptr); /* 137 */ + int (*tcl_ExprDoubleObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 138 */ + int (*tcl_ExprLong) (Tcl_Interp *interp, const char *expr, long *ptr); /* 139 */ + int (*tcl_ExprLongObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 140 */ + int (*tcl_ExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 141 */ + int (*tcl_ExprString) (Tcl_Interp *interp, const char *expr); /* 142 */ + void (*tcl_Finalize) (void); /* 143 */ + TCL_DEPRECATED_API("Don't use this function in a stub-enabled extension") const char * (*tcl_FindExecutable) (const char *argv0); /* 144 */ + Tcl_HashEntry * (*tcl_FirstHashEntry) (Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 145 */ + int (*tcl_Flush) (Tcl_Channel chan); /* 146 */ + TCL_DEPRECATED_API("see TIP #559. Use Tcl_ResetResult") void (*tcl_FreeResult) (Tcl_Interp *interp); /* 147 */ + int (*tcl_GetAlias) (Tcl_Interp *interp, const char *childCmd, Tcl_Interp **targetInterpPtr, const char **targetCmdPtr, int *argcPtr, const char ***argvPtr); /* 148 */ + int (*tcl_GetAliasObj) (Tcl_Interp *interp, const char *childCmd, Tcl_Interp **targetInterpPtr, const char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 149 */ + void * (*tcl_GetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 150 */ + Tcl_Channel (*tcl_GetChannel) (Tcl_Interp *interp, const char *chanName, int *modePtr); /* 151 */ + Tcl_Size (*tcl_GetChannelBufferSize) (Tcl_Channel chan); /* 152 */ + int (*tcl_GetChannelHandle) (Tcl_Channel chan, int direction, void **handlePtr); /* 153 */ + void * (*tcl_GetChannelInstanceData) (Tcl_Channel chan); /* 154 */ + int (*tcl_GetChannelMode) (Tcl_Channel chan); /* 155 */ + const char * (*tcl_GetChannelName) (Tcl_Channel chan); /* 156 */ + int (*tcl_GetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 157 */ + CONST86 Tcl_ChannelType * (*tcl_GetChannelType) (Tcl_Channel chan); /* 158 */ + int (*tcl_GetCommandInfo) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 159 */ + const char * (*tcl_GetCommandName) (Tcl_Interp *interp, Tcl_Command command); /* 160 */ + int (*tcl_GetErrno) (void); /* 161 */ + const char * (*tcl_GetHostName) (void); /* 162 */ + int (*tcl_GetInterpPath) (Tcl_Interp *interp, Tcl_Interp *childInterp); /* 163 */ + Tcl_Interp * (*tcl_GetParent) (Tcl_Interp *interp); /* 164 */ + const char * (*tcl_GetNameOfExecutable) (void); /* 165 */ + Tcl_Obj * (*tcl_GetObjResult) (Tcl_Interp *interp); /* 166 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ + int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, void **filePtr); /* 167 */ +#endif /* UNIX */ +#if defined(_WIN32) /* WIN */ + void (*reserved167)(void); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, void **filePtr); /* 167 */ +#endif /* MACOSX */ + Tcl_PathType (*tcl_GetPathType) (const char *path); /* 168 */ + Tcl_Size (*tcl_Gets) (Tcl_Channel chan, Tcl_DString *dsPtr); /* 169 */ + Tcl_Size (*tcl_GetsObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 170 */ + int (*tcl_GetServiceMode) (void); /* 171 */ + Tcl_Interp * (*tcl_GetChild) (Tcl_Interp *interp, const char *name); /* 172 */ + Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */ + const char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */ + const char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */ + int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */ + int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */ + int (*tcl_Init) (Tcl_Interp *interp); /* 180 */ + void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */ + int (*tcl_InputBlocked) (Tcl_Channel chan); /* 182 */ + int (*tcl_InputBuffered) (Tcl_Channel chan); /* 183 */ + int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */ + int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */ + char * (*tcl_JoinPath) (Tcl_Size argc, const char *const *argv, Tcl_DString *resultPtr); /* 186 */ + int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, void *addr, int type); /* 187 */ + void (*reserved188)(void); + Tcl_Channel (*tcl_MakeFileChannel) (void *handle, int mode); /* 189 */ + TCL_DEPRECATED_API("") int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */ + Tcl_Channel (*tcl_MakeTcpClientChannel) (void *tcpSocket); /* 191 */ + char * (*tcl_Merge) (Tcl_Size argc, const char *const *argv); /* 192 */ + Tcl_HashEntry * (*tcl_NextHashEntry) (Tcl_HashSearch *searchPtr); /* 193 */ + void (*tcl_NotifyChannel) (Tcl_Channel channel, int mask); /* 194 */ + Tcl_Obj * (*tcl_ObjGetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 195 */ + Tcl_Obj * (*tcl_ObjSetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 196 */ + Tcl_Channel (*tcl_OpenCommandChannel) (Tcl_Interp *interp, Tcl_Size argc, const char **argv, int flags); /* 197 */ + Tcl_Channel (*tcl_OpenFileChannel) (Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 198 */ + Tcl_Channel (*tcl_OpenTcpClient) (Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int flags); /* 199 */ + Tcl_Channel (*tcl_OpenTcpServer) (Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, void *callbackData); /* 200 */ + void (*tcl_Preserve) (void *data); /* 201 */ + void (*tcl_PrintDouble) (Tcl_Interp *interp, double value, char *dst); /* 202 */ + int (*tcl_PutEnv) (const char *assignment); /* 203 */ + const char * (*tcl_PosixError) (Tcl_Interp *interp); /* 204 */ + void (*tcl_QueueEvent) (Tcl_Event *evPtr, int position); /* 205 */ + Tcl_Size (*tcl_Read) (Tcl_Channel chan, char *bufPtr, Tcl_Size toRead); /* 206 */ + void (*tcl_ReapDetachedProcs) (void); /* 207 */ + int (*tcl_RecordAndEval) (Tcl_Interp *interp, const char *cmd, int flags); /* 208 */ + int (*tcl_RecordAndEvalObj) (Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 209 */ + void (*tcl_RegisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 210 */ + void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */ + Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */ + int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */ + int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */ + void (*tcl_RegExpRange) (Tcl_RegExp regexp, Tcl_Size index, const char **startPtr, const char **endPtr); /* 215 */ + void (*tcl_Release) (void *clientData); /* 216 */ + void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */ + Tcl_Size (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */ + Tcl_Size (*tcl_ScanCountedElement) (const char *src, Tcl_Size length, int *flagPtr); /* 219 */ + TCL_DEPRECATED_API("") int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */ + int (*tcl_ServiceAll) (void); /* 221 */ + int (*tcl_ServiceEvent) (int flags); /* 222 */ + void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, void *clientData); /* 223 */ + void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, Tcl_Size sz); /* 224 */ + int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */ + int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */ + void (*tcl_SetErrno) (int err); /* 227 */ + void (*tcl_SetErrorCode) (Tcl_Interp *interp, ...); /* 228 */ + void (*tcl_SetMaxBlockTime) (const Tcl_Time *timePtr); /* 229 */ + TCL_DEPRECATED_API("Don't use this function in a stub-enabled extension") const char * (*tcl_SetPanicProc) (TCL_NORETURN1 Tcl_PanicProc *panicProc); /* 230 */ + Tcl_Size (*tcl_SetRecursionLimit) (Tcl_Interp *interp, Tcl_Size depth); /* 231 */ + void (*tcl_SetResult) (Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); /* 232 */ + int (*tcl_SetServiceMode) (int mode); /* 233 */ + void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */ + void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */ + void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */ + const char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */ + const char * (*tcl_SignalId) (int sig); /* 239 */ + const char * (*tcl_SignalMsg) (int sig); /* 240 */ + void (*tcl_SourceRCFile) (Tcl_Interp *interp); /* 241 */ + int (*tcl_SplitList) (Tcl_Interp *interp, const char *listStr, int *argcPtr, const char ***argvPtr); /* 242 */ + void (*tcl_SplitPath) (const char *path, int *argcPtr, const char ***argvPtr); /* 243 */ + TCL_DEPRECATED_API("Don't use this function in a stub-enabled extension") void (*tcl_StaticLibrary) (Tcl_Interp *interp, const char *prefix, Tcl_LibraryInitProc *initProc, Tcl_LibraryInitProc *safeInitProc); /* 244 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */ + TCL_DEPRECATED_API("") int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, void *clientData); /* 247 */ + int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, void *clientData); /* 248 */ + char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */ + Tcl_Size (*tcl_Ungets) (Tcl_Channel chan, const char *str, Tcl_Size len, int atHead); /* 250 */ + void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */ + int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */ + int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, void *clientData); /* 255 */ + void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, void *clientData); /* 256 */ + void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */ + int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */ + int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") void * (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, void *prevClientData); /* 261 */ + void * (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, void *prevClientData); /* 262 */ + Tcl_Size (*tcl_Write) (Tcl_Channel chan, const char *s, Tcl_Size slen); /* 263 */ + void (*tcl_WrongNumArgs) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], const char *message); /* 264 */ + int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */ + void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */ + TCL_DEPRECATED_API("see TIP #422") void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */ + TCL_DEPRECATED_API("see TIP #422") void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */ + char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */ + const char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, const char **termPtr); /* 270 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */ + const char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */ + TCL_DEPRECATED_API("see TIP #422") void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */ + TCL_DEPRECATED_API("see TIP #422") int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */ + Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */ + TCL_DEPRECATED_API("see TIP #422") TCL_NORETURN1 void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */ + void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */ + void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */ + Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, void *instanceData, int mask, Tcl_Channel prevChan); /* 281 */ + int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */ + Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */ + void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */ + void (*reserved285)(void); + void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */ + Tcl_Encoding (*tcl_CreateEncoding) (const Tcl_EncodingType *typePtr); /* 287 */ + void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 288 */ + void (*tcl_DeleteThreadExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 289 */ + TCL_DEPRECATED_API("Use Tcl_DiscardInterpState") void (*tcl_DiscardResult) (Tcl_SavedResult *statePtr); /* 290 */ + int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, Tcl_Size numBytes, int flags); /* 291 */ + int (*tcl_EvalObjv) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 292 */ + int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */ + TCL_NORETURN1 void (*tcl_ExitThread) (int status); /* 294 */ + int (*tcl_ExternalToUtf) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, Tcl_Size dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 295 */ + char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, Tcl_DString *dsPtr); /* 296 */ + void (*tcl_FinalizeThread) (void); /* 297 */ + void (*tcl_FinalizeNotifier) (void *clientData); /* 298 */ + void (*tcl_FreeEncoding) (Tcl_Encoding encoding); /* 299 */ + Tcl_ThreadId (*tcl_GetCurrentThread) (void); /* 300 */ + Tcl_Encoding (*tcl_GetEncoding) (Tcl_Interp *interp, const char *name); /* 301 */ + const char * (*tcl_GetEncodingName) (Tcl_Encoding encoding); /* 302 */ + void (*tcl_GetEncodingNames) (Tcl_Interp *interp); /* 303 */ + int (*tcl_GetIndexFromObjStruct) (Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, Tcl_Size offset, const char *msg, int flags, void *indexPtr); /* 304 */ + void * (*tcl_GetThreadData) (Tcl_ThreadDataKey *keyPtr, Tcl_Size size); /* 305 */ + Tcl_Obj * (*tcl_GetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 306 */ + void * (*tcl_InitNotifier) (void); /* 307 */ + void (*tcl_MutexLock) (Tcl_Mutex *mutexPtr); /* 308 */ + void (*tcl_MutexUnlock) (Tcl_Mutex *mutexPtr); /* 309 */ + void (*tcl_ConditionNotify) (Tcl_Condition *condPtr); /* 310 */ + void (*tcl_ConditionWait) (Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 311 */ + Tcl_Size (*tcl_NumUtfChars) (const char *src, Tcl_Size length); /* 312 */ + Tcl_Size (*tcl_ReadChars) (Tcl_Channel channel, Tcl_Obj *objPtr, Tcl_Size charsToRead, int appendFlag); /* 313 */ + TCL_DEPRECATED_API("Use Tcl_RestoreInterpState") void (*tcl_RestoreResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 314 */ + TCL_DEPRECATED_API("Use Tcl_SaveInterpState") void (*tcl_SaveResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 315 */ + int (*tcl_SetSystemEncoding) (Tcl_Interp *interp, const char *name); /* 316 */ + Tcl_Obj * (*tcl_SetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 317 */ + void (*tcl_ThreadAlert) (Tcl_ThreadId threadId); /* 318 */ + void (*tcl_ThreadQueueEvent) (Tcl_ThreadId threadId, Tcl_Event *evPtr, int position); /* 319 */ + int (*tcl_UniCharAtIndex) (const char *src, Tcl_Size index); /* 320 */ + int (*tcl_UniCharToLower) (int ch); /* 321 */ + int (*tcl_UniCharToTitle) (int ch); /* 322 */ + int (*tcl_UniCharToUpper) (int ch); /* 323 */ + Tcl_Size (*tcl_UniCharToUtf) (int ch, char *buf); /* 324 */ + const char * (*tcl_UtfAtIndex) (const char *src, Tcl_Size index); /* 325 */ + int (*tclUtfCharComplete) (const char *src, Tcl_Size length); /* 326 */ + Tcl_Size (*tcl_UtfBackslash) (const char *src, int *readPtr, char *dst); /* 327 */ + const char * (*tcl_UtfFindFirst) (const char *src, int ch); /* 328 */ + const char * (*tcl_UtfFindLast) (const char *src, int ch); /* 329 */ + const char * (*tclUtfNext) (const char *src); /* 330 */ + const char * (*tclUtfPrev) (const char *src, const char *start); /* 331 */ + int (*tcl_UtfToExternal) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, Tcl_Size dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 332 */ + char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, Tcl_DString *dsPtr); /* 333 */ + Tcl_Size (*tcl_UtfToLower) (char *src); /* 334 */ + Tcl_Size (*tcl_UtfToTitle) (char *src); /* 335 */ + Tcl_Size (*tcl_UtfToChar16) (const char *src, unsigned short *chPtr); /* 336 */ + Tcl_Size (*tcl_UtfToUpper) (char *src); /* 337 */ + Tcl_Size (*tcl_WriteChars) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 338 */ + Tcl_Size (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */ + char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */ + TCL_DEPRECATED_API("Use Tcl_GetEncodingSearchPath") const char * (*tcl_GetDefaultEncodingDir) (void); /* 341 */ + TCL_DEPRECATED_API("Use Tcl_SetEncodingSearchPath") void (*tcl_SetDefaultEncodingDir) (const char *path); /* 342 */ + void (*tcl_AlertNotifier) (void *clientData); /* 343 */ + void (*tcl_ServiceModeHook) (int mode); /* 344 */ + int (*tcl_UniCharIsAlnum) (int ch); /* 345 */ + int (*tcl_UniCharIsAlpha) (int ch); /* 346 */ + int (*tcl_UniCharIsDigit) (int ch); /* 347 */ + int (*tcl_UniCharIsLower) (int ch); /* 348 */ + int (*tcl_UniCharIsSpace) (int ch); /* 349 */ + int (*tcl_UniCharIsUpper) (int ch); /* 350 */ + int (*tcl_UniCharIsWordChar) (int ch); /* 351 */ + Tcl_Size (*tcl_Char16Len) (const unsigned short *uniStr); /* 352 */ + TCL_DEPRECATED_API("Use Tcl_UtfNcmp") int (*tcl_UniCharNcmp) (const unsigned short *ucs, const unsigned short *uct, unsigned long numChars); /* 353 */ + char * (*tcl_Char16ToUtfDString) (const unsigned short *uniStr, Tcl_Size uniLength, Tcl_DString *dsPtr); /* 354 */ + unsigned short * (*tcl_UtfToChar16DString) (const char *src, Tcl_Size length, Tcl_DString *dsPtr); /* 355 */ + Tcl_RegExp (*tcl_GetRegExpFromObj) (Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 356 */ + TCL_DEPRECATED_API("Use Tcl_EvalTokensStandard") Tcl_Obj * (*tcl_EvalTokens) (Tcl_Interp *interp, Tcl_Token *tokenPtr, Tcl_Size count); /* 357 */ + void (*tcl_FreeParse) (Tcl_Parse *parsePtr); /* 358 */ + void (*tcl_LogCommandInfo) (Tcl_Interp *interp, const char *script, const char *command, Tcl_Size length); /* 359 */ + int (*tcl_ParseBraces) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr, int append, const char **termPtr); /* 360 */ + int (*tcl_ParseCommand) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, int nested, Tcl_Parse *parsePtr); /* 361 */ + int (*tcl_ParseExpr) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr); /* 362 */ + int (*tcl_ParseQuotedString) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr, int append, const char **termPtr); /* 363 */ + int (*tcl_ParseVarName) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr, int append); /* 364 */ + char * (*tcl_GetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 365 */ + int (*tcl_Chdir) (const char *dirName); /* 366 */ + int (*tcl_Access) (const char *path, int mode); /* 367 */ + int (*tcl_Stat) (const char *path, struct stat *bufPtr); /* 368 */ + int (*tcl_UtfNcmp) (const char *s1, const char *s2, unsigned long n); /* 369 */ + int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, unsigned long n); /* 370 */ + int (*tcl_StringCaseMatch) (const char *str, const char *pattern, int nocase); /* 371 */ + int (*tcl_UniCharIsControl) (int ch); /* 372 */ + int (*tcl_UniCharIsGraph) (int ch); /* 373 */ + int (*tcl_UniCharIsPrint) (int ch); /* 374 */ + int (*tcl_UniCharIsPunct) (int ch); /* 375 */ + int (*tcl_RegExpExecObj) (Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, Tcl_Size offset, Tcl_Size nmatches, int flags); /* 376 */ + void (*tcl_RegExpGetInfo) (Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 377 */ + Tcl_Obj * (*tcl_NewUnicodeObj) (const unsigned short *unicode, Tcl_Size numChars); /* 378 */ + void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const unsigned short *unicode, Tcl_Size numChars); /* 379 */ + Tcl_Size (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */ + int (*tcl_GetUniChar) (Tcl_Obj *objPtr, Tcl_Size index); /* 381 */ + TCL_DEPRECATED_API("No longer in use, changed to macro") unsigned short * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */ + Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, Tcl_Size first, Tcl_Size last); /* 383 */ + void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const unsigned short *unicode, Tcl_Size length); /* 384 */ + int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */ + void (*tcl_SetNotifier) (const Tcl_NotifierProcs *notifierProcPtr); /* 386 */ + Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */ + int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */ + int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */ + int (*tcl_ProcObjCmd) (void *clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); /* 390 */ + void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */ + void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */ + int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, TCL_HASH_TYPE stackSize, int flags); /* 393 */ + Tcl_Size (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, Tcl_Size bytesToRead); /* 394 */ + Tcl_Size (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 395 */ + Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */ + int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */ + const char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */ + Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */ + Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */ + TCL_DEPRECATED_API("Use Tcl_ChannelClose2Proc") Tcl_DriverCloseProc * (*tcl_ChannelCloseProc) (const Tcl_ChannelType *chanTypePtr); /* 401 */ + Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) (const Tcl_ChannelType *chanTypePtr); /* 402 */ + Tcl_DriverInputProc * (*tcl_ChannelInputProc) (const Tcl_ChannelType *chanTypePtr); /* 403 */ + Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) (const Tcl_ChannelType *chanTypePtr); /* 404 */ + TCL_DEPRECATED_API("Use Tcl_ChannelWideSeekProc") Tcl_DriverSeekProc * (*tcl_ChannelSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 405 */ + Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 406 */ + Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 407 */ + Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) (const Tcl_ChannelType *chanTypePtr); /* 408 */ + Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) (const Tcl_ChannelType *chanTypePtr); /* 409 */ + Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) (const Tcl_ChannelType *chanTypePtr); /* 410 */ + Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) (const Tcl_ChannelType *chanTypePtr); /* 411 */ + int (*tcl_JoinThread) (Tcl_ThreadId threadId, int *result); /* 412 */ + int (*tcl_IsChannelShared) (Tcl_Channel channel); /* 413 */ + int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */ + void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */ + void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */ + void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */ + int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */ + TCL_DEPRECATED_API("Use Tcl_UtfNcasecmp") int (*tcl_UniCharNcasecmp) (const unsigned short *ucs, const unsigned short *uct, unsigned long numChars); /* 419 */ + TCL_DEPRECATED_API("Use Tcl_StringCaseMatch") int (*tcl_UniCharCaseMatch) (const unsigned short *uniStr, const unsigned short *uniPattern, int nocase); /* 420 */ + Tcl_HashEntry * (*tcl_FindHashEntry) (Tcl_HashTable *tablePtr, const void *key); /* 421 */ + Tcl_HashEntry * (*tcl_CreateHashEntry) (Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 422 */ + void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */ + void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */ + void * (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, void *prevClientData); /* 425 */ + int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 426 */ + void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 427 */ + char * (*tcl_AttemptAlloc) (TCL_HASH_TYPE size); /* 428 */ + char * (*tcl_AttemptDbCkalloc) (TCL_HASH_TYPE size, const char *file, int line); /* 429 */ + char * (*tcl_AttemptRealloc) (char *ptr, TCL_HASH_TYPE size); /* 430 */ + char * (*tcl_AttemptDbCkrealloc) (char *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 431 */ + int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, Tcl_Size length); /* 432 */ + Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */ + unsigned short * (*tcl_GetUnicodeFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 434 */ + TCL_DEPRECATED_API("") int (*tcl_GetMathFuncInfo) (Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, void **clientDataPtr); /* 435 */ + TCL_DEPRECATED_API("") Tcl_Obj * (*tcl_ListMathFuncs) (Tcl_Interp *interp, const char *pattern); /* 436 */ + Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */ + int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */ + int (*tcl_IsStandardChannel) (Tcl_Channel channel); /* 439 */ + int (*tcl_FSCopyFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 440 */ + int (*tcl_FSCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 441 */ + int (*tcl_FSCreateDirectory) (Tcl_Obj *pathPtr); /* 442 */ + int (*tcl_FSDeleteFile) (Tcl_Obj *pathPtr); /* 443 */ + int (*tcl_FSLoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *sym1, const char *sym2, Tcl_LibraryInitProc **proc1Ptr, Tcl_LibraryInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); /* 444 */ + int (*tcl_FSMatchInDirectory) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 445 */ + Tcl_Obj * (*tcl_FSLink) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 446 */ + int (*tcl_FSRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 447 */ + int (*tcl_FSRenameFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 448 */ + int (*tcl_FSLstat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 449 */ + int (*tcl_FSUtime) (Tcl_Obj *pathPtr, struct utimbuf *tval); /* 450 */ + int (*tcl_FSFileAttrsGet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 451 */ + int (*tcl_FSFileAttrsSet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 452 */ + const char *CONST86 * (*tcl_FSFileAttrStrings) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 453 */ + int (*tcl_FSStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 454 */ + int (*tcl_FSAccess) (Tcl_Obj *pathPtr, int mode); /* 455 */ + Tcl_Channel (*tcl_FSOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 456 */ + Tcl_Obj * (*tcl_FSGetCwd) (Tcl_Interp *interp); /* 457 */ + int (*tcl_FSChdir) (Tcl_Obj *pathPtr); /* 458 */ + int (*tcl_FSConvertToPathType) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 459 */ + Tcl_Obj * (*tcl_FSJoinPath) (Tcl_Obj *listObj, Tcl_Size elements); /* 460 */ + Tcl_Obj * (*tcl_FSSplitPath) (Tcl_Obj *pathPtr, int *lenPtr); /* 461 */ + int (*tcl_FSEqualPaths) (Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 462 */ + Tcl_Obj * (*tcl_FSGetNormalizedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 463 */ + Tcl_Obj * (*tcl_FSJoinToPath) (Tcl_Obj *pathPtr, Tcl_Size objc, Tcl_Obj *const objv[]); /* 464 */ + void * (*tcl_FSGetInternalRep) (Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 465 */ + Tcl_Obj * (*tcl_FSGetTranslatedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 466 */ + int (*tcl_FSEvalFile) (Tcl_Interp *interp, Tcl_Obj *fileName); /* 467 */ + Tcl_Obj * (*tcl_FSNewNativePath) (const Tcl_Filesystem *fromFilesystem, void *clientData); /* 468 */ + const void * (*tcl_FSGetNativePath) (Tcl_Obj *pathPtr); /* 469 */ + Tcl_Obj * (*tcl_FSFileSystemInfo) (Tcl_Obj *pathPtr); /* 470 */ + Tcl_Obj * (*tcl_FSPathSeparator) (Tcl_Obj *pathPtr); /* 471 */ + Tcl_Obj * (*tcl_FSListVolumes) (void); /* 472 */ + int (*tcl_FSRegister) (void *clientData, const Tcl_Filesystem *fsPtr); /* 473 */ + int (*tcl_FSUnregister) (const Tcl_Filesystem *fsPtr); /* 474 */ + void * (*tcl_FSData) (const Tcl_Filesystem *fsPtr); /* 475 */ + const char * (*tcl_FSGetTranslatedStringPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 476 */ + CONST86 Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) (Tcl_Obj *pathPtr); /* 477 */ + Tcl_PathType (*tcl_FSGetPathType) (Tcl_Obj *pathPtr); /* 478 */ + int (*tcl_OutputBuffered) (Tcl_Channel chan); /* 479 */ + void (*tcl_FSMountsChanged) (const Tcl_Filesystem *fsPtr); /* 480 */ + int (*tcl_EvalTokensStandard) (Tcl_Interp *interp, Tcl_Token *tokenPtr, Tcl_Size count); /* 481 */ + void (*tcl_GetTime) (Tcl_Time *timeBuf); /* 482 */ + Tcl_Trace (*tcl_CreateObjTrace) (Tcl_Interp *interp, Tcl_Size level, int flags, Tcl_CmdObjTraceProc *objProc, void *clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 483 */ + int (*tcl_GetCommandInfoFromToken) (Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 484 */ + int (*tcl_SetCommandInfoFromToken) (Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 485 */ + Tcl_Obj * (*tcl_DbNewWideIntObj) (Tcl_WideInt wideValue, const char *file, int line); /* 486 */ + int (*tcl_GetWideIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 487 */ + Tcl_Obj * (*tcl_NewWideIntObj) (Tcl_WideInt wideValue); /* 488 */ + void (*tcl_SetWideIntObj) (Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 489 */ + Tcl_StatBuf * (*tcl_AllocStatBuf) (void); /* 490 */ + long long (*tcl_Seek) (Tcl_Channel chan, long long offset, int mode); /* 491 */ + long long (*tcl_Tell) (Tcl_Channel chan); /* 492 */ + Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 493 */ + int (*tcl_DictObjPut) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 494 */ + int (*tcl_DictObjGet) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 495 */ + int (*tcl_DictObjRemove) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 496 */ + int (*tcl_DictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr); /* 497 */ + int (*tcl_DictObjFirst) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 498 */ + void (*tcl_DictObjNext) (Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */ + void (*tcl_DictObjDone) (Tcl_DictSearch *searchPtr); /* 500 */ + int (*tcl_DictObjPutKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Size keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 501 */ + int (*tcl_DictObjRemoveKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Size keyc, Tcl_Obj *const *keyv); /* 502 */ + Tcl_Obj * (*tcl_NewDictObj) (void); /* 503 */ + Tcl_Obj * (*tcl_DbNewDictObj) (const char *file, int line); /* 504 */ + void (*tcl_RegisterConfig) (Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 505 */ + Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, const char *name, void *clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 506 */ + void (*tcl_DeleteNamespace) (Tcl_Namespace *nsPtr); /* 507 */ + int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 508 */ + int (*tcl_Export) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 509 */ + int (*tcl_Import) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 510 */ + int (*tcl_ForgetImport) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 511 */ + Tcl_Namespace * (*tcl_GetCurrentNamespace) (Tcl_Interp *interp); /* 512 */ + Tcl_Namespace * (*tcl_GetGlobalNamespace) (Tcl_Interp *interp); /* 513 */ + Tcl_Namespace * (*tcl_FindNamespace) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 514 */ + Tcl_Command (*tcl_FindCommand) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */ + Tcl_Command (*tcl_GetCommandFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 516 */ + void (*tcl_GetCommandFullName) (Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 517 */ + int (*tcl_FSEvalFileEx) (Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 518 */ + TCL_DEPRECATED_API("Don't use this function in a stub-enabled extension") Tcl_ExitProc * (*tcl_SetExitProc) (TCL_NORETURN1 Tcl_ExitProc *proc); /* 519 */ + void (*tcl_LimitAddHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, void *clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 520 */ + void (*tcl_LimitRemoveHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, void *clientData); /* 521 */ + int (*tcl_LimitReady) (Tcl_Interp *interp); /* 522 */ + int (*tcl_LimitCheck) (Tcl_Interp *interp); /* 523 */ + int (*tcl_LimitExceeded) (Tcl_Interp *interp); /* 524 */ + void (*tcl_LimitSetCommands) (Tcl_Interp *interp, Tcl_Size commandLimit); /* 525 */ + void (*tcl_LimitSetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 526 */ + void (*tcl_LimitSetGranularity) (Tcl_Interp *interp, int type, int granularity); /* 527 */ + int (*tcl_LimitTypeEnabled) (Tcl_Interp *interp, int type); /* 528 */ + int (*tcl_LimitTypeExceeded) (Tcl_Interp *interp, int type); /* 529 */ + void (*tcl_LimitTypeSet) (Tcl_Interp *interp, int type); /* 530 */ + void (*tcl_LimitTypeReset) (Tcl_Interp *interp, int type); /* 531 */ + int (*tcl_LimitGetCommands) (Tcl_Interp *interp); /* 532 */ + void (*tcl_LimitGetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 533 */ + int (*tcl_LimitGetGranularity) (Tcl_Interp *interp, int type); /* 534 */ + Tcl_InterpState (*tcl_SaveInterpState) (Tcl_Interp *interp, int status); /* 535 */ + int (*tcl_RestoreInterpState) (Tcl_Interp *interp, Tcl_InterpState state); /* 536 */ + void (*tcl_DiscardInterpState) (Tcl_InterpState state); /* 537 */ + int (*tcl_SetReturnOptions) (Tcl_Interp *interp, Tcl_Obj *options); /* 538 */ + Tcl_Obj * (*tcl_GetReturnOptions) (Tcl_Interp *interp, int result); /* 539 */ + int (*tcl_IsEnsemble) (Tcl_Command token); /* 540 */ + Tcl_Command (*tcl_CreateEnsemble) (Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 541 */ + Tcl_Command (*tcl_FindEnsemble) (Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 542 */ + int (*tcl_SetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 543 */ + int (*tcl_SetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 544 */ + int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */ + int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */ + int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */ + int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */ + int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */ + int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */ + int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */ + void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, void *clientData); /* 552 */ + void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, void **clientData); /* 553 */ + Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */ + Tcl_Obj * (*tcl_NewBignumObj) (void *value); /* 555 */ + Tcl_Obj * (*tcl_DbNewBignumObj) (void *value, const char *file, int line); /* 556 */ + void (*tcl_SetBignumObj) (Tcl_Obj *obj, void *value); /* 557 */ + int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, void *value); /* 558 */ + int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, void *value); /* 559 */ + int (*tcl_TruncateChannel) (Tcl_Channel chan, long long length); /* 560 */ + Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) (const Tcl_ChannelType *chanTypePtr); /* 561 */ + void (*tcl_SetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj *msg); /* 562 */ + void (*tcl_GetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj **msg); /* 563 */ + void (*tcl_SetChannelError) (Tcl_Channel chan, Tcl_Obj *msg); /* 564 */ + void (*tcl_GetChannelError) (Tcl_Channel chan, Tcl_Obj **msg); /* 565 */ + int (*tcl_InitBignumFromDouble) (Tcl_Interp *interp, double initval, void *toInit); /* 566 */ + Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 567 */ + int (*tcl_SetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 568 */ + int (*tcl_GetEncodingFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 569 */ + Tcl_Obj * (*tcl_GetEncodingSearchPath) (void); /* 570 */ + int (*tcl_SetEncodingSearchPath) (Tcl_Obj *searchPath); /* 571 */ + const char * (*tcl_GetEncodingNameFromEnvironment) (Tcl_DString *bufPtr); /* 572 */ + int (*tcl_PkgRequireProc) (Tcl_Interp *interp, const char *name, Tcl_Size objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 573 */ + void (*tcl_AppendObjToErrorInfo) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 574 */ + void (*tcl_AppendLimitedToObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length, Tcl_Size limit, const char *ellipsis); /* 575 */ + Tcl_Obj * (*tcl_Format) (Tcl_Interp *interp, const char *format, Tcl_Size objc, Tcl_Obj *const objv[]); /* 576 */ + int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, Tcl_Size objc, Tcl_Obj *const objv[]); /* 577 */ + Tcl_Obj * (*tcl_ObjPrintf) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 578 */ + void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 579 */ + int (*tcl_CancelEval) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr, void *clientData, int flags); /* 580 */ + int (*tcl_Canceled) (Tcl_Interp *interp, int flags); /* 581 */ + int (*tcl_CreatePipe) (Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 582 */ + Tcl_Command (*tcl_NRCreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 583 */ + int (*tcl_NREvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 584 */ + int (*tcl_NREvalObjv) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 585 */ + int (*tcl_NRCmdSwap) (Tcl_Interp *interp, Tcl_Command cmd, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 586 */ + void (*tcl_NRAddCallback) (Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, void *data0, void *data1, void *data2, void *data3); /* 587 */ + int (*tcl_NRCallObjProc) (Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, void *clientData, Tcl_Size objc, Tcl_Obj *const objv[]); /* 588 */ + unsigned (*tcl_GetFSDeviceFromStat) (const Tcl_StatBuf *statPtr); /* 589 */ + unsigned (*tcl_GetFSInodeFromStat) (const Tcl_StatBuf *statPtr); /* 590 */ + unsigned (*tcl_GetModeFromStat) (const Tcl_StatBuf *statPtr); /* 591 */ + int (*tcl_GetLinkCountFromStat) (const Tcl_StatBuf *statPtr); /* 592 */ + int (*tcl_GetUserIdFromStat) (const Tcl_StatBuf *statPtr); /* 593 */ + int (*tcl_GetGroupIdFromStat) (const Tcl_StatBuf *statPtr); /* 594 */ + int (*tcl_GetDeviceTypeFromStat) (const Tcl_StatBuf *statPtr); /* 595 */ + long long (*tcl_GetAccessTimeFromStat) (const Tcl_StatBuf *statPtr); /* 596 */ + long long (*tcl_GetModificationTimeFromStat) (const Tcl_StatBuf *statPtr); /* 597 */ + long long (*tcl_GetChangeTimeFromStat) (const Tcl_StatBuf *statPtr); /* 598 */ + unsigned long long (*tcl_GetSizeFromStat) (const Tcl_StatBuf *statPtr); /* 599 */ + unsigned long long (*tcl_GetBlocksFromStat) (const Tcl_StatBuf *statPtr); /* 600 */ + unsigned (*tcl_GetBlockSizeFromStat) (const Tcl_StatBuf *statPtr); /* 601 */ + int (*tcl_SetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 602 */ + int (*tcl_GetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 603 */ + int (*tcl_ParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 604 */ + int (*tcl_GetErrorLine) (Tcl_Interp *interp); /* 605 */ + void (*tcl_SetErrorLine) (Tcl_Interp *interp, int lineNum); /* 606 */ + void (*tcl_TransferResult) (Tcl_Interp *sourceInterp, int code, Tcl_Interp *targetInterp); /* 607 */ + int (*tcl_InterpActive) (Tcl_Interp *interp); /* 608 */ + void (*tcl_BackgroundException) (Tcl_Interp *interp, int code); /* 609 */ + int (*tcl_ZlibDeflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 610 */ + int (*tcl_ZlibInflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, Tcl_Size buffersize, Tcl_Obj *gzipHeaderDictObj); /* 611 */ + unsigned int (*tcl_ZlibCRC32) (unsigned int crc, const unsigned char *buf, Tcl_Size len); /* 612 */ + unsigned int (*tcl_ZlibAdler32) (unsigned int adler, const unsigned char *buf, Tcl_Size len); /* 613 */ + int (*tcl_ZlibStreamInit) (Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 614 */ + Tcl_Obj * (*tcl_ZlibStreamGetCommandName) (Tcl_ZlibStream zshandle); /* 615 */ + int (*tcl_ZlibStreamEof) (Tcl_ZlibStream zshandle); /* 616 */ + int (*tcl_ZlibStreamChecksum) (Tcl_ZlibStream zshandle); /* 617 */ + int (*tcl_ZlibStreamPut) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 618 */ + int (*tcl_ZlibStreamGet) (Tcl_ZlibStream zshandle, Tcl_Obj *data, Tcl_Size count); /* 619 */ + int (*tcl_ZlibStreamClose) (Tcl_ZlibStream zshandle); /* 620 */ + int (*tcl_ZlibStreamReset) (Tcl_ZlibStream zshandle); /* 621 */ + void (*tcl_SetStartupScript) (Tcl_Obj *path, const char *encoding); /* 622 */ + Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */ + int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */ + int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */ + int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */ + int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */ + void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */ + int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */ + void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */ + Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned int flags, int backlog, Tcl_TcpAcceptProc *acceptProc, void *callbackData); /* 631 */ + int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *zipname, const char *mountPoint, const char *passwd); /* 632 */ + int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *mountPoint); /* 633 */ + Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */ + int (*tclZipfs_MountBuffer) (Tcl_Interp *interp, const void *data, size_t datalen, const char *mountPoint, int copy); /* 635 */ + void (*tcl_FreeInternalRep) (Tcl_Obj *objPtr); /* 636 */ + char * (*tcl_InitStringRep) (Tcl_Obj *objPtr, const char *bytes, TCL_HASH_TYPE numBytes); /* 637 */ + Tcl_ObjInternalRep * (*tcl_FetchInternalRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 638 */ + void (*tcl_StoreInternalRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr, const Tcl_ObjInternalRep *irPtr); /* 639 */ + int (*tcl_HasStringRep) (Tcl_Obj *objPtr); /* 640 */ + void (*tcl_IncrRefCount) (Tcl_Obj *objPtr); /* 641 */ + void (*tcl_DecrRefCount) (Tcl_Obj *objPtr); /* 642 */ + int (*tcl_IsShared) (Tcl_Obj *objPtr); /* 643 */ + int (*tcl_LinkArray) (Tcl_Interp *interp, const char *varName, void *addr, int type, Tcl_Size size); /* 644 */ + int (*tcl_GetIntForIndex) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Size endValue, Tcl_Size *indexPtr); /* 645 */ + Tcl_Size (*tcl_UtfToUniChar) (const char *src, int *chPtr); /* 646 */ + char * (*tcl_UniCharToUtfDString) (const int *uniStr, Tcl_Size uniLength, Tcl_DString *dsPtr); /* 647 */ + int * (*tcl_UtfToUniCharDString) (const char *src, Tcl_Size length, Tcl_DString *dsPtr); /* 648 */ + unsigned char * (*tcl_GetBytesFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *numBytesPtr); /* 649 */ + void (*reserved650)(void); + void (*reserved651)(void); + void (*reserved652)(void); + void (*reserved653)(void); + int (*tcl_UtfCharComplete) (const char *src, Tcl_Size length); /* 654 */ + const char * (*tcl_UtfNext) (const char *src); /* 655 */ + const char * (*tcl_UtfPrev) (const char *src, const char *start); /* 656 */ + int (*tcl_UniCharIsUnicode) (int ch); /* 657 */ + int (*tcl_ExternalToUtfDStringEx) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_DString *dsPtr, Tcl_Size *errorLocationPtr); /* 658 */ + int (*tcl_UtfToExternalDStringEx) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_DString *dsPtr, Tcl_Size *errorLocationPtr); /* 659 */ + int (*tcl_AsyncMarkFromSignal) (Tcl_AsyncHandler async, int sigNumber); /* 660 */ + void (*reserved661)(void); + void (*reserved662)(void); + void (*reserved663)(void); + void (*reserved664)(void); + void (*reserved665)(void); + void (*reserved666)(void); + void (*reserved667)(void); + Tcl_Size (*tcl_UniCharLen) (const int *uniStr); /* 668 */ + Tcl_Size (*tclNumUtfChars) (const char *src, Tcl_Size length); /* 669 */ + Tcl_Size (*tclGetCharLength) (Tcl_Obj *objPtr); /* 670 */ + const char * (*tclUtfAtIndex) (const char *src, Tcl_Size index); /* 671 */ + Tcl_Obj * (*tclGetRange) (Tcl_Obj *objPtr, Tcl_Size first, Tcl_Size last); /* 672 */ + int (*tclGetUniChar) (Tcl_Obj *objPtr, Tcl_Size index); /* 673 */ + int (*tcl_GetBool) (Tcl_Interp *interp, const char *src, int flags, char *charPtr); /* 674 */ + int (*tcl_GetBoolFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, char *charPtr); /* 675 */ + void (*reserved676)(void); + void (*reserved677)(void); + void (*reserved678)(void); + void (*reserved679)(void); + int (*tcl_GetNumberFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, void **clientDataPtr, int *typePtr); /* 680 */ + int (*tcl_GetNumber) (Tcl_Interp *interp, const char *bytes, Tcl_Size numBytes, void **clientDataPtr, int *typePtr); /* 681 */ + int (*tcl_RemoveChannelMode) (Tcl_Interp *interp, Tcl_Channel chan, int mode); /* 682 */ + Tcl_Size (*tcl_GetEncodingNulLength) (Tcl_Encoding encoding); /* 683 */ + int (*tcl_GetWideUIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr); /* 684 */ + Tcl_Obj * (*tcl_DStringToObj) (Tcl_DString *dsPtr); /* 685 */ + void (*reserved686)(void); + void (*reserved687)(void); + void (*tclUnusedStubEntry) (void); /* 688 */ +} TclStubs; + +extern const TclStubs *tclStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +#define Tcl_PkgProvideEx \ + (tclStubsPtr->tcl_PkgProvideEx) /* 0 */ +#define Tcl_PkgRequireEx \ + (tclStubsPtr->tcl_PkgRequireEx) /* 1 */ +#define Tcl_Panic \ + (tclStubsPtr->tcl_Panic) /* 2 */ +#define Tcl_Alloc \ + (tclStubsPtr->tcl_Alloc) /* 3 */ +#define Tcl_Free \ + (tclStubsPtr->tcl_Free) /* 4 */ +#define Tcl_Realloc \ + (tclStubsPtr->tcl_Realloc) /* 5 */ +#define Tcl_DbCkalloc \ + (tclStubsPtr->tcl_DbCkalloc) /* 6 */ +#define Tcl_DbCkfree \ + (tclStubsPtr->tcl_DbCkfree) /* 7 */ +#define Tcl_DbCkrealloc \ + (tclStubsPtr->tcl_DbCkrealloc) /* 8 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +#define Tcl_CreateFileHandler \ + (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_CreateFileHandler \ + (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ +#endif /* MACOSX */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +#define Tcl_DeleteFileHandler \ + (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_DeleteFileHandler \ + (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ +#endif /* MACOSX */ +#define Tcl_SetTimer \ + (tclStubsPtr->tcl_SetTimer) /* 11 */ +#define Tcl_Sleep \ + (tclStubsPtr->tcl_Sleep) /* 12 */ +#define Tcl_WaitForEvent \ + (tclStubsPtr->tcl_WaitForEvent) /* 13 */ +#define Tcl_AppendAllObjTypes \ + (tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */ +#define Tcl_AppendStringsToObj \ + (tclStubsPtr->tcl_AppendStringsToObj) /* 15 */ +#define Tcl_AppendToObj \ + (tclStubsPtr->tcl_AppendToObj) /* 16 */ +#define Tcl_ConcatObj \ + (tclStubsPtr->tcl_ConcatObj) /* 17 */ +#define Tcl_ConvertToType \ + (tclStubsPtr->tcl_ConvertToType) /* 18 */ +#define Tcl_DbDecrRefCount \ + (tclStubsPtr->tcl_DbDecrRefCount) /* 19 */ +#define Tcl_DbIncrRefCount \ + (tclStubsPtr->tcl_DbIncrRefCount) /* 20 */ +#define Tcl_DbIsShared \ + (tclStubsPtr->tcl_DbIsShared) /* 21 */ +#define Tcl_DbNewBooleanObj \ + (tclStubsPtr->tcl_DbNewBooleanObj) /* 22 */ +#define Tcl_DbNewByteArrayObj \ + (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ +#define Tcl_DbNewDoubleObj \ + (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ +#define Tcl_DbNewListObj \ + (tclStubsPtr->tcl_DbNewListObj) /* 25 */ +#define Tcl_DbNewLongObj \ + (tclStubsPtr->tcl_DbNewLongObj) /* 26 */ +#define Tcl_DbNewObj \ + (tclStubsPtr->tcl_DbNewObj) /* 27 */ +#define Tcl_DbNewStringObj \ + (tclStubsPtr->tcl_DbNewStringObj) /* 28 */ +#define Tcl_DuplicateObj \ + (tclStubsPtr->tcl_DuplicateObj) /* 29 */ +#define TclFreeObj \ + (tclStubsPtr->tclFreeObj) /* 30 */ +#define Tcl_GetBoolean \ + (tclStubsPtr->tcl_GetBoolean) /* 31 */ +#define Tcl_GetBooleanFromObj \ + (tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */ +#define Tcl_GetByteArrayFromObj \ + (tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */ +#define Tcl_GetDouble \ + (tclStubsPtr->tcl_GetDouble) /* 34 */ +#define Tcl_GetDoubleFromObj \ + (tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */ +#define Tcl_GetIndexFromObj \ + (tclStubsPtr->tcl_GetIndexFromObj) /* 36 */ +#define Tcl_GetInt \ + (tclStubsPtr->tcl_GetInt) /* 37 */ +#define Tcl_GetIntFromObj \ + (tclStubsPtr->tcl_GetIntFromObj) /* 38 */ +#define Tcl_GetLongFromObj \ + (tclStubsPtr->tcl_GetLongFromObj) /* 39 */ +#define Tcl_GetObjType \ + (tclStubsPtr->tcl_GetObjType) /* 40 */ +#define Tcl_GetStringFromObj \ + (tclStubsPtr->tcl_GetStringFromObj) /* 41 */ +#define Tcl_InvalidateStringRep \ + (tclStubsPtr->tcl_InvalidateStringRep) /* 42 */ +#define Tcl_ListObjAppendList \ + (tclStubsPtr->tcl_ListObjAppendList) /* 43 */ +#define Tcl_ListObjAppendElement \ + (tclStubsPtr->tcl_ListObjAppendElement) /* 44 */ +#define Tcl_ListObjGetElements \ + (tclStubsPtr->tcl_ListObjGetElements) /* 45 */ +#define Tcl_ListObjIndex \ + (tclStubsPtr->tcl_ListObjIndex) /* 46 */ +#define Tcl_ListObjLength \ + (tclStubsPtr->tcl_ListObjLength) /* 47 */ +#define Tcl_ListObjReplace \ + (tclStubsPtr->tcl_ListObjReplace) /* 48 */ +#define Tcl_NewBooleanObj \ + (tclStubsPtr->tcl_NewBooleanObj) /* 49 */ +#define Tcl_NewByteArrayObj \ + (tclStubsPtr->tcl_NewByteArrayObj) /* 50 */ +#define Tcl_NewDoubleObj \ + (tclStubsPtr->tcl_NewDoubleObj) /* 51 */ +#define Tcl_NewIntObj \ + (tclStubsPtr->tcl_NewIntObj) /* 52 */ +#define Tcl_NewListObj \ + (tclStubsPtr->tcl_NewListObj) /* 53 */ +#define Tcl_NewLongObj \ + (tclStubsPtr->tcl_NewLongObj) /* 54 */ +#define Tcl_NewObj \ + (tclStubsPtr->tcl_NewObj) /* 55 */ +#define Tcl_NewStringObj \ + (tclStubsPtr->tcl_NewStringObj) /* 56 */ +#define Tcl_SetBooleanObj \ + (tclStubsPtr->tcl_SetBooleanObj) /* 57 */ +#define Tcl_SetByteArrayLength \ + (tclStubsPtr->tcl_SetByteArrayLength) /* 58 */ +#define Tcl_SetByteArrayObj \ + (tclStubsPtr->tcl_SetByteArrayObj) /* 59 */ +#define Tcl_SetDoubleObj \ + (tclStubsPtr->tcl_SetDoubleObj) /* 60 */ +#define Tcl_SetIntObj \ + (tclStubsPtr->tcl_SetIntObj) /* 61 */ +#define Tcl_SetListObj \ + (tclStubsPtr->tcl_SetListObj) /* 62 */ +#define Tcl_SetLongObj \ + (tclStubsPtr->tcl_SetLongObj) /* 63 */ +#define Tcl_SetObjLength \ + (tclStubsPtr->tcl_SetObjLength) /* 64 */ +#define Tcl_SetStringObj \ + (tclStubsPtr->tcl_SetStringObj) /* 65 */ +#define Tcl_AddErrorInfo \ + (tclStubsPtr->tcl_AddErrorInfo) /* 66 */ +#define Tcl_AddObjErrorInfo \ + (tclStubsPtr->tcl_AddObjErrorInfo) /* 67 */ +#define Tcl_AllowExceptions \ + (tclStubsPtr->tcl_AllowExceptions) /* 68 */ +#define Tcl_AppendElement \ + (tclStubsPtr->tcl_AppendElement) /* 69 */ +#define Tcl_AppendResult \ + (tclStubsPtr->tcl_AppendResult) /* 70 */ +#define Tcl_AsyncCreate \ + (tclStubsPtr->tcl_AsyncCreate) /* 71 */ +#define Tcl_AsyncDelete \ + (tclStubsPtr->tcl_AsyncDelete) /* 72 */ +#define Tcl_AsyncInvoke \ + (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ +#define Tcl_AsyncMark \ + (tclStubsPtr->tcl_AsyncMark) /* 74 */ +#define Tcl_AsyncReady \ + (tclStubsPtr->tcl_AsyncReady) /* 75 */ +#define Tcl_BackgroundError \ + (tclStubsPtr->tcl_BackgroundError) /* 76 */ +#define Tcl_Backslash \ + (tclStubsPtr->tcl_Backslash) /* 77 */ +#define Tcl_BadChannelOption \ + (tclStubsPtr->tcl_BadChannelOption) /* 78 */ +#define Tcl_CallWhenDeleted \ + (tclStubsPtr->tcl_CallWhenDeleted) /* 79 */ +#define Tcl_CancelIdleCall \ + (tclStubsPtr->tcl_CancelIdleCall) /* 80 */ +#define Tcl_Close \ + (tclStubsPtr->tcl_Close) /* 81 */ +#define Tcl_CommandComplete \ + (tclStubsPtr->tcl_CommandComplete) /* 82 */ +#define Tcl_Concat \ + (tclStubsPtr->tcl_Concat) /* 83 */ +#define Tcl_ConvertElement \ + (tclStubsPtr->tcl_ConvertElement) /* 84 */ +#define Tcl_ConvertCountedElement \ + (tclStubsPtr->tcl_ConvertCountedElement) /* 85 */ +#define Tcl_CreateAlias \ + (tclStubsPtr->tcl_CreateAlias) /* 86 */ +#define Tcl_CreateAliasObj \ + (tclStubsPtr->tcl_CreateAliasObj) /* 87 */ +#define Tcl_CreateChannel \ + (tclStubsPtr->tcl_CreateChannel) /* 88 */ +#define Tcl_CreateChannelHandler \ + (tclStubsPtr->tcl_CreateChannelHandler) /* 89 */ +#define Tcl_CreateCloseHandler \ + (tclStubsPtr->tcl_CreateCloseHandler) /* 90 */ +#define Tcl_CreateCommand \ + (tclStubsPtr->tcl_CreateCommand) /* 91 */ +#define Tcl_CreateEventSource \ + (tclStubsPtr->tcl_CreateEventSource) /* 92 */ +#define Tcl_CreateExitHandler \ + (tclStubsPtr->tcl_CreateExitHandler) /* 93 */ +#define Tcl_CreateInterp \ + (tclStubsPtr->tcl_CreateInterp) /* 94 */ +#define Tcl_CreateMathFunc \ + (tclStubsPtr->tcl_CreateMathFunc) /* 95 */ +#define Tcl_CreateObjCommand \ + (tclStubsPtr->tcl_CreateObjCommand) /* 96 */ +#define Tcl_CreateChild \ + (tclStubsPtr->tcl_CreateChild) /* 97 */ +#define Tcl_CreateTimerHandler \ + (tclStubsPtr->tcl_CreateTimerHandler) /* 98 */ +#define Tcl_CreateTrace \ + (tclStubsPtr->tcl_CreateTrace) /* 99 */ +#define Tcl_DeleteAssocData \ + (tclStubsPtr->tcl_DeleteAssocData) /* 100 */ +#define Tcl_DeleteChannelHandler \ + (tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */ +#define Tcl_DeleteCloseHandler \ + (tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */ +#define Tcl_DeleteCommand \ + (tclStubsPtr->tcl_DeleteCommand) /* 103 */ +#define Tcl_DeleteCommandFromToken \ + (tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */ +#define Tcl_DeleteEvents \ + (tclStubsPtr->tcl_DeleteEvents) /* 105 */ +#define Tcl_DeleteEventSource \ + (tclStubsPtr->tcl_DeleteEventSource) /* 106 */ +#define Tcl_DeleteExitHandler \ + (tclStubsPtr->tcl_DeleteExitHandler) /* 107 */ +#define Tcl_DeleteHashEntry \ + (tclStubsPtr->tcl_DeleteHashEntry) /* 108 */ +#define Tcl_DeleteHashTable \ + (tclStubsPtr->tcl_DeleteHashTable) /* 109 */ +#define Tcl_DeleteInterp \ + (tclStubsPtr->tcl_DeleteInterp) /* 110 */ +#define Tcl_DetachPids \ + (tclStubsPtr->tcl_DetachPids) /* 111 */ +#define Tcl_DeleteTimerHandler \ + (tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */ +#define Tcl_DeleteTrace \ + (tclStubsPtr->tcl_DeleteTrace) /* 113 */ +#define Tcl_DontCallWhenDeleted \ + (tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */ +#define Tcl_DoOneEvent \ + (tclStubsPtr->tcl_DoOneEvent) /* 115 */ +#define Tcl_DoWhenIdle \ + (tclStubsPtr->tcl_DoWhenIdle) /* 116 */ +#define Tcl_DStringAppend \ + (tclStubsPtr->tcl_DStringAppend) /* 117 */ +#define Tcl_DStringAppendElement \ + (tclStubsPtr->tcl_DStringAppendElement) /* 118 */ +#define Tcl_DStringEndSublist \ + (tclStubsPtr->tcl_DStringEndSublist) /* 119 */ +#define Tcl_DStringFree \ + (tclStubsPtr->tcl_DStringFree) /* 120 */ +#define Tcl_DStringGetResult \ + (tclStubsPtr->tcl_DStringGetResult) /* 121 */ +#define Tcl_DStringInit \ + (tclStubsPtr->tcl_DStringInit) /* 122 */ +#define Tcl_DStringResult \ + (tclStubsPtr->tcl_DStringResult) /* 123 */ +#define Tcl_DStringSetLength \ + (tclStubsPtr->tcl_DStringSetLength) /* 124 */ +#define Tcl_DStringStartSublist \ + (tclStubsPtr->tcl_DStringStartSublist) /* 125 */ +#define Tcl_Eof \ + (tclStubsPtr->tcl_Eof) /* 126 */ +#define Tcl_ErrnoId \ + (tclStubsPtr->tcl_ErrnoId) /* 127 */ +#define Tcl_ErrnoMsg \ + (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ +#define Tcl_Eval \ + (tclStubsPtr->tcl_Eval) /* 129 */ +#define Tcl_EvalFile \ + (tclStubsPtr->tcl_EvalFile) /* 130 */ +#define Tcl_EvalObj \ + (tclStubsPtr->tcl_EvalObj) /* 131 */ +#define Tcl_EventuallyFree \ + (tclStubsPtr->tcl_EventuallyFree) /* 132 */ +#define Tcl_Exit \ + (tclStubsPtr->tcl_Exit) /* 133 */ +#define Tcl_ExposeCommand \ + (tclStubsPtr->tcl_ExposeCommand) /* 134 */ +#define Tcl_ExprBoolean \ + (tclStubsPtr->tcl_ExprBoolean) /* 135 */ +#define Tcl_ExprBooleanObj \ + (tclStubsPtr->tcl_ExprBooleanObj) /* 136 */ +#define Tcl_ExprDouble \ + (tclStubsPtr->tcl_ExprDouble) /* 137 */ +#define Tcl_ExprDoubleObj \ + (tclStubsPtr->tcl_ExprDoubleObj) /* 138 */ +#define Tcl_ExprLong \ + (tclStubsPtr->tcl_ExprLong) /* 139 */ +#define Tcl_ExprLongObj \ + (tclStubsPtr->tcl_ExprLongObj) /* 140 */ +#define Tcl_ExprObj \ + (tclStubsPtr->tcl_ExprObj) /* 141 */ +#define Tcl_ExprString \ + (tclStubsPtr->tcl_ExprString) /* 142 */ +#define Tcl_Finalize \ + (tclStubsPtr->tcl_Finalize) /* 143 */ +#define Tcl_FindExecutable \ + (tclStubsPtr->tcl_FindExecutable) /* 144 */ +#define Tcl_FirstHashEntry \ + (tclStubsPtr->tcl_FirstHashEntry) /* 145 */ +#define Tcl_Flush \ + (tclStubsPtr->tcl_Flush) /* 146 */ +#define Tcl_FreeResult \ + (tclStubsPtr->tcl_FreeResult) /* 147 */ +#define Tcl_GetAlias \ + (tclStubsPtr->tcl_GetAlias) /* 148 */ +#define Tcl_GetAliasObj \ + (tclStubsPtr->tcl_GetAliasObj) /* 149 */ +#define Tcl_GetAssocData \ + (tclStubsPtr->tcl_GetAssocData) /* 150 */ +#define Tcl_GetChannel \ + (tclStubsPtr->tcl_GetChannel) /* 151 */ +#define Tcl_GetChannelBufferSize \ + (tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */ +#define Tcl_GetChannelHandle \ + (tclStubsPtr->tcl_GetChannelHandle) /* 153 */ +#define Tcl_GetChannelInstanceData \ + (tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */ +#define Tcl_GetChannelMode \ + (tclStubsPtr->tcl_GetChannelMode) /* 155 */ +#define Tcl_GetChannelName \ + (tclStubsPtr->tcl_GetChannelName) /* 156 */ +#define Tcl_GetChannelOption \ + (tclStubsPtr->tcl_GetChannelOption) /* 157 */ +#define Tcl_GetChannelType \ + (tclStubsPtr->tcl_GetChannelType) /* 158 */ +#define Tcl_GetCommandInfo \ + (tclStubsPtr->tcl_GetCommandInfo) /* 159 */ +#define Tcl_GetCommandName \ + (tclStubsPtr->tcl_GetCommandName) /* 160 */ +#define Tcl_GetErrno \ + (tclStubsPtr->tcl_GetErrno) /* 161 */ +#define Tcl_GetHostName \ + (tclStubsPtr->tcl_GetHostName) /* 162 */ +#define Tcl_GetInterpPath \ + (tclStubsPtr->tcl_GetInterpPath) /* 163 */ +#define Tcl_GetParent \ + (tclStubsPtr->tcl_GetParent) /* 164 */ +#define Tcl_GetNameOfExecutable \ + (tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */ +#define Tcl_GetObjResult \ + (tclStubsPtr->tcl_GetObjResult) /* 166 */ +#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ +#define Tcl_GetOpenFile \ + (tclStubsPtr->tcl_GetOpenFile) /* 167 */ +#endif /* UNIX */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_GetOpenFile \ + (tclStubsPtr->tcl_GetOpenFile) /* 167 */ +#endif /* MACOSX */ +#define Tcl_GetPathType \ + (tclStubsPtr->tcl_GetPathType) /* 168 */ +#define Tcl_Gets \ + (tclStubsPtr->tcl_Gets) /* 169 */ +#define Tcl_GetsObj \ + (tclStubsPtr->tcl_GetsObj) /* 170 */ +#define Tcl_GetServiceMode \ + (tclStubsPtr->tcl_GetServiceMode) /* 171 */ +#define Tcl_GetChild \ + (tclStubsPtr->tcl_GetChild) /* 172 */ +#define Tcl_GetStdChannel \ + (tclStubsPtr->tcl_GetStdChannel) /* 173 */ +#define Tcl_GetStringResult \ + (tclStubsPtr->tcl_GetStringResult) /* 174 */ +#define Tcl_GetVar \ + (tclStubsPtr->tcl_GetVar) /* 175 */ +#define Tcl_GetVar2 \ + (tclStubsPtr->tcl_GetVar2) /* 176 */ +#define Tcl_GlobalEval \ + (tclStubsPtr->tcl_GlobalEval) /* 177 */ +#define Tcl_GlobalEvalObj \ + (tclStubsPtr->tcl_GlobalEvalObj) /* 178 */ +#define Tcl_HideCommand \ + (tclStubsPtr->tcl_HideCommand) /* 179 */ +#define Tcl_Init \ + (tclStubsPtr->tcl_Init) /* 180 */ +#define Tcl_InitHashTable \ + (tclStubsPtr->tcl_InitHashTable) /* 181 */ +#define Tcl_InputBlocked \ + (tclStubsPtr->tcl_InputBlocked) /* 182 */ +#define Tcl_InputBuffered \ + (tclStubsPtr->tcl_InputBuffered) /* 183 */ +#define Tcl_InterpDeleted \ + (tclStubsPtr->tcl_InterpDeleted) /* 184 */ +#define Tcl_IsSafe \ + (tclStubsPtr->tcl_IsSafe) /* 185 */ +#define Tcl_JoinPath \ + (tclStubsPtr->tcl_JoinPath) /* 186 */ +#define Tcl_LinkVar \ + (tclStubsPtr->tcl_LinkVar) /* 187 */ +/* Slot 188 is reserved */ +#define Tcl_MakeFileChannel \ + (tclStubsPtr->tcl_MakeFileChannel) /* 189 */ +#define Tcl_MakeSafe \ + (tclStubsPtr->tcl_MakeSafe) /* 190 */ +#define Tcl_MakeTcpClientChannel \ + (tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */ +#define Tcl_Merge \ + (tclStubsPtr->tcl_Merge) /* 192 */ +#define Tcl_NextHashEntry \ + (tclStubsPtr->tcl_NextHashEntry) /* 193 */ +#define Tcl_NotifyChannel \ + (tclStubsPtr->tcl_NotifyChannel) /* 194 */ +#define Tcl_ObjGetVar2 \ + (tclStubsPtr->tcl_ObjGetVar2) /* 195 */ +#define Tcl_ObjSetVar2 \ + (tclStubsPtr->tcl_ObjSetVar2) /* 196 */ +#define Tcl_OpenCommandChannel \ + (tclStubsPtr->tcl_OpenCommandChannel) /* 197 */ +#define Tcl_OpenFileChannel \ + (tclStubsPtr->tcl_OpenFileChannel) /* 198 */ +#define Tcl_OpenTcpClient \ + (tclStubsPtr->tcl_OpenTcpClient) /* 199 */ +#define Tcl_OpenTcpServer \ + (tclStubsPtr->tcl_OpenTcpServer) /* 200 */ +#define Tcl_Preserve \ + (tclStubsPtr->tcl_Preserve) /* 201 */ +#define Tcl_PrintDouble \ + (tclStubsPtr->tcl_PrintDouble) /* 202 */ +#define Tcl_PutEnv \ + (tclStubsPtr->tcl_PutEnv) /* 203 */ +#define Tcl_PosixError \ + (tclStubsPtr->tcl_PosixError) /* 204 */ +#define Tcl_QueueEvent \ + (tclStubsPtr->tcl_QueueEvent) /* 205 */ +#define Tcl_Read \ + (tclStubsPtr->tcl_Read) /* 206 */ +#define Tcl_ReapDetachedProcs \ + (tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */ +#define Tcl_RecordAndEval \ + (tclStubsPtr->tcl_RecordAndEval) /* 208 */ +#define Tcl_RecordAndEvalObj \ + (tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */ +#define Tcl_RegisterChannel \ + (tclStubsPtr->tcl_RegisterChannel) /* 210 */ +#define Tcl_RegisterObjType \ + (tclStubsPtr->tcl_RegisterObjType) /* 211 */ +#define Tcl_RegExpCompile \ + (tclStubsPtr->tcl_RegExpCompile) /* 212 */ +#define Tcl_RegExpExec \ + (tclStubsPtr->tcl_RegExpExec) /* 213 */ +#define Tcl_RegExpMatch \ + (tclStubsPtr->tcl_RegExpMatch) /* 214 */ +#define Tcl_RegExpRange \ + (tclStubsPtr->tcl_RegExpRange) /* 215 */ +#define Tcl_Release \ + (tclStubsPtr->tcl_Release) /* 216 */ +#define Tcl_ResetResult \ + (tclStubsPtr->tcl_ResetResult) /* 217 */ +#define Tcl_ScanElement \ + (tclStubsPtr->tcl_ScanElement) /* 218 */ +#define Tcl_ScanCountedElement \ + (tclStubsPtr->tcl_ScanCountedElement) /* 219 */ +#define Tcl_SeekOld \ + (tclStubsPtr->tcl_SeekOld) /* 220 */ +#define Tcl_ServiceAll \ + (tclStubsPtr->tcl_ServiceAll) /* 221 */ +#define Tcl_ServiceEvent \ + (tclStubsPtr->tcl_ServiceEvent) /* 222 */ +#define Tcl_SetAssocData \ + (tclStubsPtr->tcl_SetAssocData) /* 223 */ +#define Tcl_SetChannelBufferSize \ + (tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */ +#define Tcl_SetChannelOption \ + (tclStubsPtr->tcl_SetChannelOption) /* 225 */ +#define Tcl_SetCommandInfo \ + (tclStubsPtr->tcl_SetCommandInfo) /* 226 */ +#define Tcl_SetErrno \ + (tclStubsPtr->tcl_SetErrno) /* 227 */ +#define Tcl_SetErrorCode \ + (tclStubsPtr->tcl_SetErrorCode) /* 228 */ +#define Tcl_SetMaxBlockTime \ + (tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */ +#define Tcl_SetPanicProc \ + (tclStubsPtr->tcl_SetPanicProc) /* 230 */ +#define Tcl_SetRecursionLimit \ + (tclStubsPtr->tcl_SetRecursionLimit) /* 231 */ +#define Tcl_SetResult \ + (tclStubsPtr->tcl_SetResult) /* 232 */ +#define Tcl_SetServiceMode \ + (tclStubsPtr->tcl_SetServiceMode) /* 233 */ +#define Tcl_SetObjErrorCode \ + (tclStubsPtr->tcl_SetObjErrorCode) /* 234 */ +#define Tcl_SetObjResult \ + (tclStubsPtr->tcl_SetObjResult) /* 235 */ +#define Tcl_SetStdChannel \ + (tclStubsPtr->tcl_SetStdChannel) /* 236 */ +#define Tcl_SetVar \ + (tclStubsPtr->tcl_SetVar) /* 237 */ +#define Tcl_SetVar2 \ + (tclStubsPtr->tcl_SetVar2) /* 238 */ +#define Tcl_SignalId \ + (tclStubsPtr->tcl_SignalId) /* 239 */ +#define Tcl_SignalMsg \ + (tclStubsPtr->tcl_SignalMsg) /* 240 */ +#define Tcl_SourceRCFile \ + (tclStubsPtr->tcl_SourceRCFile) /* 241 */ +#define Tcl_SplitList \ + (tclStubsPtr->tcl_SplitList) /* 242 */ +#define Tcl_SplitPath \ + (tclStubsPtr->tcl_SplitPath) /* 243 */ +#define Tcl_StaticLibrary \ + (tclStubsPtr->tcl_StaticLibrary) /* 244 */ +#define Tcl_StringMatch \ + (tclStubsPtr->tcl_StringMatch) /* 245 */ +#define Tcl_TellOld \ + (tclStubsPtr->tcl_TellOld) /* 246 */ +#define Tcl_TraceVar \ + (tclStubsPtr->tcl_TraceVar) /* 247 */ +#define Tcl_TraceVar2 \ + (tclStubsPtr->tcl_TraceVar2) /* 248 */ +#define Tcl_TranslateFileName \ + (tclStubsPtr->tcl_TranslateFileName) /* 249 */ +#define Tcl_Ungets \ + (tclStubsPtr->tcl_Ungets) /* 250 */ +#define Tcl_UnlinkVar \ + (tclStubsPtr->tcl_UnlinkVar) /* 251 */ +#define Tcl_UnregisterChannel \ + (tclStubsPtr->tcl_UnregisterChannel) /* 252 */ +#define Tcl_UnsetVar \ + (tclStubsPtr->tcl_UnsetVar) /* 253 */ +#define Tcl_UnsetVar2 \ + (tclStubsPtr->tcl_UnsetVar2) /* 254 */ +#define Tcl_UntraceVar \ + (tclStubsPtr->tcl_UntraceVar) /* 255 */ +#define Tcl_UntraceVar2 \ + (tclStubsPtr->tcl_UntraceVar2) /* 256 */ +#define Tcl_UpdateLinkedVar \ + (tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */ +#define Tcl_UpVar \ + (tclStubsPtr->tcl_UpVar) /* 258 */ +#define Tcl_UpVar2 \ + (tclStubsPtr->tcl_UpVar2) /* 259 */ +#define Tcl_VarEval \ + (tclStubsPtr->tcl_VarEval) /* 260 */ +#define Tcl_VarTraceInfo \ + (tclStubsPtr->tcl_VarTraceInfo) /* 261 */ +#define Tcl_VarTraceInfo2 \ + (tclStubsPtr->tcl_VarTraceInfo2) /* 262 */ +#define Tcl_Write \ + (tclStubsPtr->tcl_Write) /* 263 */ +#define Tcl_WrongNumArgs \ + (tclStubsPtr->tcl_WrongNumArgs) /* 264 */ +#define Tcl_DumpActiveMemory \ + (tclStubsPtr->tcl_DumpActiveMemory) /* 265 */ +#define Tcl_ValidateAllMemory \ + (tclStubsPtr->tcl_ValidateAllMemory) /* 266 */ +#define Tcl_AppendResultVA \ + (tclStubsPtr->tcl_AppendResultVA) /* 267 */ +#define Tcl_AppendStringsToObjVA \ + (tclStubsPtr->tcl_AppendStringsToObjVA) /* 268 */ +#define Tcl_HashStats \ + (tclStubsPtr->tcl_HashStats) /* 269 */ +#define Tcl_ParseVar \ + (tclStubsPtr->tcl_ParseVar) /* 270 */ +#define Tcl_PkgPresent \ + (tclStubsPtr->tcl_PkgPresent) /* 271 */ +#define Tcl_PkgPresentEx \ + (tclStubsPtr->tcl_PkgPresentEx) /* 272 */ +#define Tcl_PkgProvide \ + (tclStubsPtr->tcl_PkgProvide) /* 273 */ +#define Tcl_PkgRequire \ + (tclStubsPtr->tcl_PkgRequire) /* 274 */ +#define Tcl_SetErrorCodeVA \ + (tclStubsPtr->tcl_SetErrorCodeVA) /* 275 */ +#define Tcl_VarEvalVA \ + (tclStubsPtr->tcl_VarEvalVA) /* 276 */ +#define Tcl_WaitPid \ + (tclStubsPtr->tcl_WaitPid) /* 277 */ +#define Tcl_PanicVA \ + (tclStubsPtr->tcl_PanicVA) /* 278 */ +#define Tcl_GetVersion \ + (tclStubsPtr->tcl_GetVersion) /* 279 */ +#define Tcl_InitMemory \ + (tclStubsPtr->tcl_InitMemory) /* 280 */ +#define Tcl_StackChannel \ + (tclStubsPtr->tcl_StackChannel) /* 281 */ +#define Tcl_UnstackChannel \ + (tclStubsPtr->tcl_UnstackChannel) /* 282 */ +#define Tcl_GetStackedChannel \ + (tclStubsPtr->tcl_GetStackedChannel) /* 283 */ +#define Tcl_SetMainLoop \ + (tclStubsPtr->tcl_SetMainLoop) /* 284 */ +/* Slot 285 is reserved */ +#define Tcl_AppendObjToObj \ + (tclStubsPtr->tcl_AppendObjToObj) /* 286 */ +#define Tcl_CreateEncoding \ + (tclStubsPtr->tcl_CreateEncoding) /* 287 */ +#define Tcl_CreateThreadExitHandler \ + (tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */ +#define Tcl_DeleteThreadExitHandler \ + (tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */ +#define Tcl_DiscardResult \ + (tclStubsPtr->tcl_DiscardResult) /* 290 */ +#define Tcl_EvalEx \ + (tclStubsPtr->tcl_EvalEx) /* 291 */ +#define Tcl_EvalObjv \ + (tclStubsPtr->tcl_EvalObjv) /* 292 */ +#define Tcl_EvalObjEx \ + (tclStubsPtr->tcl_EvalObjEx) /* 293 */ +#define Tcl_ExitThread \ + (tclStubsPtr->tcl_ExitThread) /* 294 */ +#define Tcl_ExternalToUtf \ + (tclStubsPtr->tcl_ExternalToUtf) /* 295 */ +#define Tcl_ExternalToUtfDString \ + (tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */ +#define Tcl_FinalizeThread \ + (tclStubsPtr->tcl_FinalizeThread) /* 297 */ +#define Tcl_FinalizeNotifier \ + (tclStubsPtr->tcl_FinalizeNotifier) /* 298 */ +#define Tcl_FreeEncoding \ + (tclStubsPtr->tcl_FreeEncoding) /* 299 */ +#define Tcl_GetCurrentThread \ + (tclStubsPtr->tcl_GetCurrentThread) /* 300 */ +#define Tcl_GetEncoding \ + (tclStubsPtr->tcl_GetEncoding) /* 301 */ +#define Tcl_GetEncodingName \ + (tclStubsPtr->tcl_GetEncodingName) /* 302 */ +#define Tcl_GetEncodingNames \ + (tclStubsPtr->tcl_GetEncodingNames) /* 303 */ +#define Tcl_GetIndexFromObjStruct \ + (tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */ +#define Tcl_GetThreadData \ + (tclStubsPtr->tcl_GetThreadData) /* 305 */ +#define Tcl_GetVar2Ex \ + (tclStubsPtr->tcl_GetVar2Ex) /* 306 */ +#define Tcl_InitNotifier \ + (tclStubsPtr->tcl_InitNotifier) /* 307 */ +#define Tcl_MutexLock \ + (tclStubsPtr->tcl_MutexLock) /* 308 */ +#define Tcl_MutexUnlock \ + (tclStubsPtr->tcl_MutexUnlock) /* 309 */ +#define Tcl_ConditionNotify \ + (tclStubsPtr->tcl_ConditionNotify) /* 310 */ +#define Tcl_ConditionWait \ + (tclStubsPtr->tcl_ConditionWait) /* 311 */ +#define Tcl_NumUtfChars \ + (tclStubsPtr->tcl_NumUtfChars) /* 312 */ +#define Tcl_ReadChars \ + (tclStubsPtr->tcl_ReadChars) /* 313 */ +#define Tcl_RestoreResult \ + (tclStubsPtr->tcl_RestoreResult) /* 314 */ +#define Tcl_SaveResult \ + (tclStubsPtr->tcl_SaveResult) /* 315 */ +#define Tcl_SetSystemEncoding \ + (tclStubsPtr->tcl_SetSystemEncoding) /* 316 */ +#define Tcl_SetVar2Ex \ + (tclStubsPtr->tcl_SetVar2Ex) /* 317 */ +#define Tcl_ThreadAlert \ + (tclStubsPtr->tcl_ThreadAlert) /* 318 */ +#define Tcl_ThreadQueueEvent \ + (tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */ +#define Tcl_UniCharAtIndex \ + (tclStubsPtr->tcl_UniCharAtIndex) /* 320 */ +#define Tcl_UniCharToLower \ + (tclStubsPtr->tcl_UniCharToLower) /* 321 */ +#define Tcl_UniCharToTitle \ + (tclStubsPtr->tcl_UniCharToTitle) /* 322 */ +#define Tcl_UniCharToUpper \ + (tclStubsPtr->tcl_UniCharToUpper) /* 323 */ +#define Tcl_UniCharToUtf \ + (tclStubsPtr->tcl_UniCharToUtf) /* 324 */ +#define Tcl_UtfAtIndex \ + (tclStubsPtr->tcl_UtfAtIndex) /* 325 */ +#define TclUtfCharComplete \ + (tclStubsPtr->tclUtfCharComplete) /* 326 */ +#define Tcl_UtfBackslash \ + (tclStubsPtr->tcl_UtfBackslash) /* 327 */ +#define Tcl_UtfFindFirst \ + (tclStubsPtr->tcl_UtfFindFirst) /* 328 */ +#define Tcl_UtfFindLast \ + (tclStubsPtr->tcl_UtfFindLast) /* 329 */ +#define TclUtfNext \ + (tclStubsPtr->tclUtfNext) /* 330 */ +#define TclUtfPrev \ + (tclStubsPtr->tclUtfPrev) /* 331 */ +#define Tcl_UtfToExternal \ + (tclStubsPtr->tcl_UtfToExternal) /* 332 */ +#define Tcl_UtfToExternalDString \ + (tclStubsPtr->tcl_UtfToExternalDString) /* 333 */ +#define Tcl_UtfToLower \ + (tclStubsPtr->tcl_UtfToLower) /* 334 */ +#define Tcl_UtfToTitle \ + (tclStubsPtr->tcl_UtfToTitle) /* 335 */ +#define Tcl_UtfToChar16 \ + (tclStubsPtr->tcl_UtfToChar16) /* 336 */ +#define Tcl_UtfToUpper \ + (tclStubsPtr->tcl_UtfToUpper) /* 337 */ +#define Tcl_WriteChars \ + (tclStubsPtr->tcl_WriteChars) /* 338 */ +#define Tcl_WriteObj \ + (tclStubsPtr->tcl_WriteObj) /* 339 */ +#define Tcl_GetString \ + (tclStubsPtr->tcl_GetString) /* 340 */ +#define Tcl_GetDefaultEncodingDir \ + (tclStubsPtr->tcl_GetDefaultEncodingDir) /* 341 */ +#define Tcl_SetDefaultEncodingDir \ + (tclStubsPtr->tcl_SetDefaultEncodingDir) /* 342 */ +#define Tcl_AlertNotifier \ + (tclStubsPtr->tcl_AlertNotifier) /* 343 */ +#define Tcl_ServiceModeHook \ + (tclStubsPtr->tcl_ServiceModeHook) /* 344 */ +#define Tcl_UniCharIsAlnum \ + (tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */ +#define Tcl_UniCharIsAlpha \ + (tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */ +#define Tcl_UniCharIsDigit \ + (tclStubsPtr->tcl_UniCharIsDigit) /* 347 */ +#define Tcl_UniCharIsLower \ + (tclStubsPtr->tcl_UniCharIsLower) /* 348 */ +#define Tcl_UniCharIsSpace \ + (tclStubsPtr->tcl_UniCharIsSpace) /* 349 */ +#define Tcl_UniCharIsUpper \ + (tclStubsPtr->tcl_UniCharIsUpper) /* 350 */ +#define Tcl_UniCharIsWordChar \ + (tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */ +#define Tcl_Char16Len \ + (tclStubsPtr->tcl_Char16Len) /* 352 */ +#define Tcl_UniCharNcmp \ + (tclStubsPtr->tcl_UniCharNcmp) /* 353 */ +#define Tcl_Char16ToUtfDString \ + (tclStubsPtr->tcl_Char16ToUtfDString) /* 354 */ +#define Tcl_UtfToChar16DString \ + (tclStubsPtr->tcl_UtfToChar16DString) /* 355 */ +#define Tcl_GetRegExpFromObj \ + (tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */ +#define Tcl_EvalTokens \ + (tclStubsPtr->tcl_EvalTokens) /* 357 */ +#define Tcl_FreeParse \ + (tclStubsPtr->tcl_FreeParse) /* 358 */ +#define Tcl_LogCommandInfo \ + (tclStubsPtr->tcl_LogCommandInfo) /* 359 */ +#define Tcl_ParseBraces \ + (tclStubsPtr->tcl_ParseBraces) /* 360 */ +#define Tcl_ParseCommand \ + (tclStubsPtr->tcl_ParseCommand) /* 361 */ +#define Tcl_ParseExpr \ + (tclStubsPtr->tcl_ParseExpr) /* 362 */ +#define Tcl_ParseQuotedString \ + (tclStubsPtr->tcl_ParseQuotedString) /* 363 */ +#define Tcl_ParseVarName \ + (tclStubsPtr->tcl_ParseVarName) /* 364 */ +#define Tcl_GetCwd \ + (tclStubsPtr->tcl_GetCwd) /* 365 */ +#define Tcl_Chdir \ + (tclStubsPtr->tcl_Chdir) /* 366 */ +#define Tcl_Access \ + (tclStubsPtr->tcl_Access) /* 367 */ +#define Tcl_Stat \ + (tclStubsPtr->tcl_Stat) /* 368 */ +#define Tcl_UtfNcmp \ + (tclStubsPtr->tcl_UtfNcmp) /* 369 */ +#define Tcl_UtfNcasecmp \ + (tclStubsPtr->tcl_UtfNcasecmp) /* 370 */ +#define Tcl_StringCaseMatch \ + (tclStubsPtr->tcl_StringCaseMatch) /* 371 */ +#define Tcl_UniCharIsControl \ + (tclStubsPtr->tcl_UniCharIsControl) /* 372 */ +#define Tcl_UniCharIsGraph \ + (tclStubsPtr->tcl_UniCharIsGraph) /* 373 */ +#define Tcl_UniCharIsPrint \ + (tclStubsPtr->tcl_UniCharIsPrint) /* 374 */ +#define Tcl_UniCharIsPunct \ + (tclStubsPtr->tcl_UniCharIsPunct) /* 375 */ +#define Tcl_RegExpExecObj \ + (tclStubsPtr->tcl_RegExpExecObj) /* 376 */ +#define Tcl_RegExpGetInfo \ + (tclStubsPtr->tcl_RegExpGetInfo) /* 377 */ +#define Tcl_NewUnicodeObj \ + (tclStubsPtr->tcl_NewUnicodeObj) /* 378 */ +#define Tcl_SetUnicodeObj \ + (tclStubsPtr->tcl_SetUnicodeObj) /* 379 */ +#define Tcl_GetCharLength \ + (tclStubsPtr->tcl_GetCharLength) /* 380 */ +#define Tcl_GetUniChar \ + (tclStubsPtr->tcl_GetUniChar) /* 381 */ +#define Tcl_GetUnicode \ + (tclStubsPtr->tcl_GetUnicode) /* 382 */ +#define Tcl_GetRange \ + (tclStubsPtr->tcl_GetRange) /* 383 */ +#define Tcl_AppendUnicodeToObj \ + (tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */ +#define Tcl_RegExpMatchObj \ + (tclStubsPtr->tcl_RegExpMatchObj) /* 385 */ +#define Tcl_SetNotifier \ + (tclStubsPtr->tcl_SetNotifier) /* 386 */ +#define Tcl_GetAllocMutex \ + (tclStubsPtr->tcl_GetAllocMutex) /* 387 */ +#define Tcl_GetChannelNames \ + (tclStubsPtr->tcl_GetChannelNames) /* 388 */ +#define Tcl_GetChannelNamesEx \ + (tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */ +#define Tcl_ProcObjCmd \ + (tclStubsPtr->tcl_ProcObjCmd) /* 390 */ +#define Tcl_ConditionFinalize \ + (tclStubsPtr->tcl_ConditionFinalize) /* 391 */ +#define Tcl_MutexFinalize \ + (tclStubsPtr->tcl_MutexFinalize) /* 392 */ +#define Tcl_CreateThread \ + (tclStubsPtr->tcl_CreateThread) /* 393 */ +#define Tcl_ReadRaw \ + (tclStubsPtr->tcl_ReadRaw) /* 394 */ +#define Tcl_WriteRaw \ + (tclStubsPtr->tcl_WriteRaw) /* 395 */ +#define Tcl_GetTopChannel \ + (tclStubsPtr->tcl_GetTopChannel) /* 396 */ +#define Tcl_ChannelBuffered \ + (tclStubsPtr->tcl_ChannelBuffered) /* 397 */ +#define Tcl_ChannelName \ + (tclStubsPtr->tcl_ChannelName) /* 398 */ +#define Tcl_ChannelVersion \ + (tclStubsPtr->tcl_ChannelVersion) /* 399 */ +#define Tcl_ChannelBlockModeProc \ + (tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */ +#define Tcl_ChannelCloseProc \ + (tclStubsPtr->tcl_ChannelCloseProc) /* 401 */ +#define Tcl_ChannelClose2Proc \ + (tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */ +#define Tcl_ChannelInputProc \ + (tclStubsPtr->tcl_ChannelInputProc) /* 403 */ +#define Tcl_ChannelOutputProc \ + (tclStubsPtr->tcl_ChannelOutputProc) /* 404 */ +#define Tcl_ChannelSeekProc \ + (tclStubsPtr->tcl_ChannelSeekProc) /* 405 */ +#define Tcl_ChannelSetOptionProc \ + (tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */ +#define Tcl_ChannelGetOptionProc \ + (tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */ +#define Tcl_ChannelWatchProc \ + (tclStubsPtr->tcl_ChannelWatchProc) /* 408 */ +#define Tcl_ChannelGetHandleProc \ + (tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */ +#define Tcl_ChannelFlushProc \ + (tclStubsPtr->tcl_ChannelFlushProc) /* 410 */ +#define Tcl_ChannelHandlerProc \ + (tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */ +#define Tcl_JoinThread \ + (tclStubsPtr->tcl_JoinThread) /* 412 */ +#define Tcl_IsChannelShared \ + (tclStubsPtr->tcl_IsChannelShared) /* 413 */ +#define Tcl_IsChannelRegistered \ + (tclStubsPtr->tcl_IsChannelRegistered) /* 414 */ +#define Tcl_CutChannel \ + (tclStubsPtr->tcl_CutChannel) /* 415 */ +#define Tcl_SpliceChannel \ + (tclStubsPtr->tcl_SpliceChannel) /* 416 */ +#define Tcl_ClearChannelHandlers \ + (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ +#define Tcl_IsChannelExisting \ + (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ +#define Tcl_UniCharNcasecmp \ + (tclStubsPtr->tcl_UniCharNcasecmp) /* 419 */ +#define Tcl_UniCharCaseMatch \ + (tclStubsPtr->tcl_UniCharCaseMatch) /* 420 */ +#define Tcl_FindHashEntry \ + (tclStubsPtr->tcl_FindHashEntry) /* 421 */ +#define Tcl_CreateHashEntry \ + (tclStubsPtr->tcl_CreateHashEntry) /* 422 */ +#define Tcl_InitCustomHashTable \ + (tclStubsPtr->tcl_InitCustomHashTable) /* 423 */ +#define Tcl_InitObjHashTable \ + (tclStubsPtr->tcl_InitObjHashTable) /* 424 */ +#define Tcl_CommandTraceInfo \ + (tclStubsPtr->tcl_CommandTraceInfo) /* 425 */ +#define Tcl_TraceCommand \ + (tclStubsPtr->tcl_TraceCommand) /* 426 */ +#define Tcl_UntraceCommand \ + (tclStubsPtr->tcl_UntraceCommand) /* 427 */ +#define Tcl_AttemptAlloc \ + (tclStubsPtr->tcl_AttemptAlloc) /* 428 */ +#define Tcl_AttemptDbCkalloc \ + (tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */ +#define Tcl_AttemptRealloc \ + (tclStubsPtr->tcl_AttemptRealloc) /* 430 */ +#define Tcl_AttemptDbCkrealloc \ + (tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */ +#define Tcl_AttemptSetObjLength \ + (tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */ +#define Tcl_GetChannelThread \ + (tclStubsPtr->tcl_GetChannelThread) /* 433 */ +#define Tcl_GetUnicodeFromObj \ + (tclStubsPtr->tcl_GetUnicodeFromObj) /* 434 */ +#define Tcl_GetMathFuncInfo \ + (tclStubsPtr->tcl_GetMathFuncInfo) /* 435 */ +#define Tcl_ListMathFuncs \ + (tclStubsPtr->tcl_ListMathFuncs) /* 436 */ +#define Tcl_SubstObj \ + (tclStubsPtr->tcl_SubstObj) /* 437 */ +#define Tcl_DetachChannel \ + (tclStubsPtr->tcl_DetachChannel) /* 438 */ +#define Tcl_IsStandardChannel \ + (tclStubsPtr->tcl_IsStandardChannel) /* 439 */ +#define Tcl_FSCopyFile \ + (tclStubsPtr->tcl_FSCopyFile) /* 440 */ +#define Tcl_FSCopyDirectory \ + (tclStubsPtr->tcl_FSCopyDirectory) /* 441 */ +#define Tcl_FSCreateDirectory \ + (tclStubsPtr->tcl_FSCreateDirectory) /* 442 */ +#define Tcl_FSDeleteFile \ + (tclStubsPtr->tcl_FSDeleteFile) /* 443 */ +#define Tcl_FSLoadFile \ + (tclStubsPtr->tcl_FSLoadFile) /* 444 */ +#define Tcl_FSMatchInDirectory \ + (tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */ +#define Tcl_FSLink \ + (tclStubsPtr->tcl_FSLink) /* 446 */ +#define Tcl_FSRemoveDirectory \ + (tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */ +#define Tcl_FSRenameFile \ + (tclStubsPtr->tcl_FSRenameFile) /* 448 */ +#define Tcl_FSLstat \ + (tclStubsPtr->tcl_FSLstat) /* 449 */ +#define Tcl_FSUtime \ + (tclStubsPtr->tcl_FSUtime) /* 450 */ +#define Tcl_FSFileAttrsGet \ + (tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */ +#define Tcl_FSFileAttrsSet \ + (tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */ +#define Tcl_FSFileAttrStrings \ + (tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */ +#define Tcl_FSStat \ + (tclStubsPtr->tcl_FSStat) /* 454 */ +#define Tcl_FSAccess \ + (tclStubsPtr->tcl_FSAccess) /* 455 */ +#define Tcl_FSOpenFileChannel \ + (tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */ +#define Tcl_FSGetCwd \ + (tclStubsPtr->tcl_FSGetCwd) /* 457 */ +#define Tcl_FSChdir \ + (tclStubsPtr->tcl_FSChdir) /* 458 */ +#define Tcl_FSConvertToPathType \ + (tclStubsPtr->tcl_FSConvertToPathType) /* 459 */ +#define Tcl_FSJoinPath \ + (tclStubsPtr->tcl_FSJoinPath) /* 460 */ +#define Tcl_FSSplitPath \ + (tclStubsPtr->tcl_FSSplitPath) /* 461 */ +#define Tcl_FSEqualPaths \ + (tclStubsPtr->tcl_FSEqualPaths) /* 462 */ +#define Tcl_FSGetNormalizedPath \ + (tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */ +#define Tcl_FSJoinToPath \ + (tclStubsPtr->tcl_FSJoinToPath) /* 464 */ +#define Tcl_FSGetInternalRep \ + (tclStubsPtr->tcl_FSGetInternalRep) /* 465 */ +#define Tcl_FSGetTranslatedPath \ + (tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */ +#define Tcl_FSEvalFile \ + (tclStubsPtr->tcl_FSEvalFile) /* 467 */ +#define Tcl_FSNewNativePath \ + (tclStubsPtr->tcl_FSNewNativePath) /* 468 */ +#define Tcl_FSGetNativePath \ + (tclStubsPtr->tcl_FSGetNativePath) /* 469 */ +#define Tcl_FSFileSystemInfo \ + (tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */ +#define Tcl_FSPathSeparator \ + (tclStubsPtr->tcl_FSPathSeparator) /* 471 */ +#define Tcl_FSListVolumes \ + (tclStubsPtr->tcl_FSListVolumes) /* 472 */ +#define Tcl_FSRegister \ + (tclStubsPtr->tcl_FSRegister) /* 473 */ +#define Tcl_FSUnregister \ + (tclStubsPtr->tcl_FSUnregister) /* 474 */ +#define Tcl_FSData \ + (tclStubsPtr->tcl_FSData) /* 475 */ +#define Tcl_FSGetTranslatedStringPath \ + (tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */ +#define Tcl_FSGetFileSystemForPath \ + (tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */ +#define Tcl_FSGetPathType \ + (tclStubsPtr->tcl_FSGetPathType) /* 478 */ +#define Tcl_OutputBuffered \ + (tclStubsPtr->tcl_OutputBuffered) /* 479 */ +#define Tcl_FSMountsChanged \ + (tclStubsPtr->tcl_FSMountsChanged) /* 480 */ +#define Tcl_EvalTokensStandard \ + (tclStubsPtr->tcl_EvalTokensStandard) /* 481 */ +#define Tcl_GetTime \ + (tclStubsPtr->tcl_GetTime) /* 482 */ +#define Tcl_CreateObjTrace \ + (tclStubsPtr->tcl_CreateObjTrace) /* 483 */ +#define Tcl_GetCommandInfoFromToken \ + (tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */ +#define Tcl_SetCommandInfoFromToken \ + (tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */ +#define Tcl_DbNewWideIntObj \ + (tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */ +#define Tcl_GetWideIntFromObj \ + (tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */ +#define Tcl_NewWideIntObj \ + (tclStubsPtr->tcl_NewWideIntObj) /* 488 */ +#define Tcl_SetWideIntObj \ + (tclStubsPtr->tcl_SetWideIntObj) /* 489 */ +#define Tcl_AllocStatBuf \ + (tclStubsPtr->tcl_AllocStatBuf) /* 490 */ +#define Tcl_Seek \ + (tclStubsPtr->tcl_Seek) /* 491 */ +#define Tcl_Tell \ + (tclStubsPtr->tcl_Tell) /* 492 */ +#define Tcl_ChannelWideSeekProc \ + (tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */ +#define Tcl_DictObjPut \ + (tclStubsPtr->tcl_DictObjPut) /* 494 */ +#define Tcl_DictObjGet \ + (tclStubsPtr->tcl_DictObjGet) /* 495 */ +#define Tcl_DictObjRemove \ + (tclStubsPtr->tcl_DictObjRemove) /* 496 */ +#define Tcl_DictObjSize \ + (tclStubsPtr->tcl_DictObjSize) /* 497 */ +#define Tcl_DictObjFirst \ + (tclStubsPtr->tcl_DictObjFirst) /* 498 */ +#define Tcl_DictObjNext \ + (tclStubsPtr->tcl_DictObjNext) /* 499 */ +#define Tcl_DictObjDone \ + (tclStubsPtr->tcl_DictObjDone) /* 500 */ +#define Tcl_DictObjPutKeyList \ + (tclStubsPtr->tcl_DictObjPutKeyList) /* 501 */ +#define Tcl_DictObjRemoveKeyList \ + (tclStubsPtr->tcl_DictObjRemoveKeyList) /* 502 */ +#define Tcl_NewDictObj \ + (tclStubsPtr->tcl_NewDictObj) /* 503 */ +#define Tcl_DbNewDictObj \ + (tclStubsPtr->tcl_DbNewDictObj) /* 504 */ +#define Tcl_RegisterConfig \ + (tclStubsPtr->tcl_RegisterConfig) /* 505 */ +#define Tcl_CreateNamespace \ + (tclStubsPtr->tcl_CreateNamespace) /* 506 */ +#define Tcl_DeleteNamespace \ + (tclStubsPtr->tcl_DeleteNamespace) /* 507 */ +#define Tcl_AppendExportList \ + (tclStubsPtr->tcl_AppendExportList) /* 508 */ +#define Tcl_Export \ + (tclStubsPtr->tcl_Export) /* 509 */ +#define Tcl_Import \ + (tclStubsPtr->tcl_Import) /* 510 */ +#define Tcl_ForgetImport \ + (tclStubsPtr->tcl_ForgetImport) /* 511 */ +#define Tcl_GetCurrentNamespace \ + (tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */ +#define Tcl_GetGlobalNamespace \ + (tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */ +#define Tcl_FindNamespace \ + (tclStubsPtr->tcl_FindNamespace) /* 514 */ +#define Tcl_FindCommand \ + (tclStubsPtr->tcl_FindCommand) /* 515 */ +#define Tcl_GetCommandFromObj \ + (tclStubsPtr->tcl_GetCommandFromObj) /* 516 */ +#define Tcl_GetCommandFullName \ + (tclStubsPtr->tcl_GetCommandFullName) /* 517 */ +#define Tcl_FSEvalFileEx \ + (tclStubsPtr->tcl_FSEvalFileEx) /* 518 */ +#define Tcl_SetExitProc \ + (tclStubsPtr->tcl_SetExitProc) /* 519 */ +#define Tcl_LimitAddHandler \ + (tclStubsPtr->tcl_LimitAddHandler) /* 520 */ +#define Tcl_LimitRemoveHandler \ + (tclStubsPtr->tcl_LimitRemoveHandler) /* 521 */ +#define Tcl_LimitReady \ + (tclStubsPtr->tcl_LimitReady) /* 522 */ +#define Tcl_LimitCheck \ + (tclStubsPtr->tcl_LimitCheck) /* 523 */ +#define Tcl_LimitExceeded \ + (tclStubsPtr->tcl_LimitExceeded) /* 524 */ +#define Tcl_LimitSetCommands \ + (tclStubsPtr->tcl_LimitSetCommands) /* 525 */ +#define Tcl_LimitSetTime \ + (tclStubsPtr->tcl_LimitSetTime) /* 526 */ +#define Tcl_LimitSetGranularity \ + (tclStubsPtr->tcl_LimitSetGranularity) /* 527 */ +#define Tcl_LimitTypeEnabled \ + (tclStubsPtr->tcl_LimitTypeEnabled) /* 528 */ +#define Tcl_LimitTypeExceeded \ + (tclStubsPtr->tcl_LimitTypeExceeded) /* 529 */ +#define Tcl_LimitTypeSet \ + (tclStubsPtr->tcl_LimitTypeSet) /* 530 */ +#define Tcl_LimitTypeReset \ + (tclStubsPtr->tcl_LimitTypeReset) /* 531 */ +#define Tcl_LimitGetCommands \ + (tclStubsPtr->tcl_LimitGetCommands) /* 532 */ +#define Tcl_LimitGetTime \ + (tclStubsPtr->tcl_LimitGetTime) /* 533 */ +#define Tcl_LimitGetGranularity \ + (tclStubsPtr->tcl_LimitGetGranularity) /* 534 */ +#define Tcl_SaveInterpState \ + (tclStubsPtr->tcl_SaveInterpState) /* 535 */ +#define Tcl_RestoreInterpState \ + (tclStubsPtr->tcl_RestoreInterpState) /* 536 */ +#define Tcl_DiscardInterpState \ + (tclStubsPtr->tcl_DiscardInterpState) /* 537 */ +#define Tcl_SetReturnOptions \ + (tclStubsPtr->tcl_SetReturnOptions) /* 538 */ +#define Tcl_GetReturnOptions \ + (tclStubsPtr->tcl_GetReturnOptions) /* 539 */ +#define Tcl_IsEnsemble \ + (tclStubsPtr->tcl_IsEnsemble) /* 540 */ +#define Tcl_CreateEnsemble \ + (tclStubsPtr->tcl_CreateEnsemble) /* 541 */ +#define Tcl_FindEnsemble \ + (tclStubsPtr->tcl_FindEnsemble) /* 542 */ +#define Tcl_SetEnsembleSubcommandList \ + (tclStubsPtr->tcl_SetEnsembleSubcommandList) /* 543 */ +#define Tcl_SetEnsembleMappingDict \ + (tclStubsPtr->tcl_SetEnsembleMappingDict) /* 544 */ +#define Tcl_SetEnsembleUnknownHandler \ + (tclStubsPtr->tcl_SetEnsembleUnknownHandler) /* 545 */ +#define Tcl_SetEnsembleFlags \ + (tclStubsPtr->tcl_SetEnsembleFlags) /* 546 */ +#define Tcl_GetEnsembleSubcommandList \ + (tclStubsPtr->tcl_GetEnsembleSubcommandList) /* 547 */ +#define Tcl_GetEnsembleMappingDict \ + (tclStubsPtr->tcl_GetEnsembleMappingDict) /* 548 */ +#define Tcl_GetEnsembleUnknownHandler \ + (tclStubsPtr->tcl_GetEnsembleUnknownHandler) /* 549 */ +#define Tcl_GetEnsembleFlags \ + (tclStubsPtr->tcl_GetEnsembleFlags) /* 550 */ +#define Tcl_GetEnsembleNamespace \ + (tclStubsPtr->tcl_GetEnsembleNamespace) /* 551 */ +#define Tcl_SetTimeProc \ + (tclStubsPtr->tcl_SetTimeProc) /* 552 */ +#define Tcl_QueryTimeProc \ + (tclStubsPtr->tcl_QueryTimeProc) /* 553 */ +#define Tcl_ChannelThreadActionProc \ + (tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */ +#define Tcl_NewBignumObj \ + (tclStubsPtr->tcl_NewBignumObj) /* 555 */ +#define Tcl_DbNewBignumObj \ + (tclStubsPtr->tcl_DbNewBignumObj) /* 556 */ +#define Tcl_SetBignumObj \ + (tclStubsPtr->tcl_SetBignumObj) /* 557 */ +#define Tcl_GetBignumFromObj \ + (tclStubsPtr->tcl_GetBignumFromObj) /* 558 */ +#define Tcl_TakeBignumFromObj \ + (tclStubsPtr->tcl_TakeBignumFromObj) /* 559 */ +#define Tcl_TruncateChannel \ + (tclStubsPtr->tcl_TruncateChannel) /* 560 */ +#define Tcl_ChannelTruncateProc \ + (tclStubsPtr->tcl_ChannelTruncateProc) /* 561 */ +#define Tcl_SetChannelErrorInterp \ + (tclStubsPtr->tcl_SetChannelErrorInterp) /* 562 */ +#define Tcl_GetChannelErrorInterp \ + (tclStubsPtr->tcl_GetChannelErrorInterp) /* 563 */ +#define Tcl_SetChannelError \ + (tclStubsPtr->tcl_SetChannelError) /* 564 */ +#define Tcl_GetChannelError \ + (tclStubsPtr->tcl_GetChannelError) /* 565 */ +#define Tcl_InitBignumFromDouble \ + (tclStubsPtr->tcl_InitBignumFromDouble) /* 566 */ +#define Tcl_GetNamespaceUnknownHandler \ + (tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 567 */ +#define Tcl_SetNamespaceUnknownHandler \ + (tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 568 */ +#define Tcl_GetEncodingFromObj \ + (tclStubsPtr->tcl_GetEncodingFromObj) /* 569 */ +#define Tcl_GetEncodingSearchPath \ + (tclStubsPtr->tcl_GetEncodingSearchPath) /* 570 */ +#define Tcl_SetEncodingSearchPath \ + (tclStubsPtr->tcl_SetEncodingSearchPath) /* 571 */ +#define Tcl_GetEncodingNameFromEnvironment \ + (tclStubsPtr->tcl_GetEncodingNameFromEnvironment) /* 572 */ +#define Tcl_PkgRequireProc \ + (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ +#define Tcl_AppendObjToErrorInfo \ + (tclStubsPtr->tcl_AppendObjToErrorInfo) /* 574 */ +#define Tcl_AppendLimitedToObj \ + (tclStubsPtr->tcl_AppendLimitedToObj) /* 575 */ +#define Tcl_Format \ + (tclStubsPtr->tcl_Format) /* 576 */ +#define Tcl_AppendFormatToObj \ + (tclStubsPtr->tcl_AppendFormatToObj) /* 577 */ +#define Tcl_ObjPrintf \ + (tclStubsPtr->tcl_ObjPrintf) /* 578 */ +#define Tcl_AppendPrintfToObj \ + (tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */ +#define Tcl_CancelEval \ + (tclStubsPtr->tcl_CancelEval) /* 580 */ +#define Tcl_Canceled \ + (tclStubsPtr->tcl_Canceled) /* 581 */ +#define Tcl_CreatePipe \ + (tclStubsPtr->tcl_CreatePipe) /* 582 */ +#define Tcl_NRCreateCommand \ + (tclStubsPtr->tcl_NRCreateCommand) /* 583 */ +#define Tcl_NREvalObj \ + (tclStubsPtr->tcl_NREvalObj) /* 584 */ +#define Tcl_NREvalObjv \ + (tclStubsPtr->tcl_NREvalObjv) /* 585 */ +#define Tcl_NRCmdSwap \ + (tclStubsPtr->tcl_NRCmdSwap) /* 586 */ +#define Tcl_NRAddCallback \ + (tclStubsPtr->tcl_NRAddCallback) /* 587 */ +#define Tcl_NRCallObjProc \ + (tclStubsPtr->tcl_NRCallObjProc) /* 588 */ +#define Tcl_GetFSDeviceFromStat \ + (tclStubsPtr->tcl_GetFSDeviceFromStat) /* 589 */ +#define Tcl_GetFSInodeFromStat \ + (tclStubsPtr->tcl_GetFSInodeFromStat) /* 590 */ +#define Tcl_GetModeFromStat \ + (tclStubsPtr->tcl_GetModeFromStat) /* 591 */ +#define Tcl_GetLinkCountFromStat \ + (tclStubsPtr->tcl_GetLinkCountFromStat) /* 592 */ +#define Tcl_GetUserIdFromStat \ + (tclStubsPtr->tcl_GetUserIdFromStat) /* 593 */ +#define Tcl_GetGroupIdFromStat \ + (tclStubsPtr->tcl_GetGroupIdFromStat) /* 594 */ +#define Tcl_GetDeviceTypeFromStat \ + (tclStubsPtr->tcl_GetDeviceTypeFromStat) /* 595 */ +#define Tcl_GetAccessTimeFromStat \ + (tclStubsPtr->tcl_GetAccessTimeFromStat) /* 596 */ +#define Tcl_GetModificationTimeFromStat \ + (tclStubsPtr->tcl_GetModificationTimeFromStat) /* 597 */ +#define Tcl_GetChangeTimeFromStat \ + (tclStubsPtr->tcl_GetChangeTimeFromStat) /* 598 */ +#define Tcl_GetSizeFromStat \ + (tclStubsPtr->tcl_GetSizeFromStat) /* 599 */ +#define Tcl_GetBlocksFromStat \ + (tclStubsPtr->tcl_GetBlocksFromStat) /* 600 */ +#define Tcl_GetBlockSizeFromStat \ + (tclStubsPtr->tcl_GetBlockSizeFromStat) /* 601 */ +#define Tcl_SetEnsembleParameterList \ + (tclStubsPtr->tcl_SetEnsembleParameterList) /* 602 */ +#define Tcl_GetEnsembleParameterList \ + (tclStubsPtr->tcl_GetEnsembleParameterList) /* 603 */ +#define Tcl_ParseArgsObjv \ + (tclStubsPtr->tcl_ParseArgsObjv) /* 604 */ +#define Tcl_GetErrorLine \ + (tclStubsPtr->tcl_GetErrorLine) /* 605 */ +#define Tcl_SetErrorLine \ + (tclStubsPtr->tcl_SetErrorLine) /* 606 */ +#define Tcl_TransferResult \ + (tclStubsPtr->tcl_TransferResult) /* 607 */ +#define Tcl_InterpActive \ + (tclStubsPtr->tcl_InterpActive) /* 608 */ +#define Tcl_BackgroundException \ + (tclStubsPtr->tcl_BackgroundException) /* 609 */ +#define Tcl_ZlibDeflate \ + (tclStubsPtr->tcl_ZlibDeflate) /* 610 */ +#define Tcl_ZlibInflate \ + (tclStubsPtr->tcl_ZlibInflate) /* 611 */ +#define Tcl_ZlibCRC32 \ + (tclStubsPtr->tcl_ZlibCRC32) /* 612 */ +#define Tcl_ZlibAdler32 \ + (tclStubsPtr->tcl_ZlibAdler32) /* 613 */ +#define Tcl_ZlibStreamInit \ + (tclStubsPtr->tcl_ZlibStreamInit) /* 614 */ +#define Tcl_ZlibStreamGetCommandName \ + (tclStubsPtr->tcl_ZlibStreamGetCommandName) /* 615 */ +#define Tcl_ZlibStreamEof \ + (tclStubsPtr->tcl_ZlibStreamEof) /* 616 */ +#define Tcl_ZlibStreamChecksum \ + (tclStubsPtr->tcl_ZlibStreamChecksum) /* 617 */ +#define Tcl_ZlibStreamPut \ + (tclStubsPtr->tcl_ZlibStreamPut) /* 618 */ +#define Tcl_ZlibStreamGet \ + (tclStubsPtr->tcl_ZlibStreamGet) /* 619 */ +#define Tcl_ZlibStreamClose \ + (tclStubsPtr->tcl_ZlibStreamClose) /* 620 */ +#define Tcl_ZlibStreamReset \ + (tclStubsPtr->tcl_ZlibStreamReset) /* 621 */ +#define Tcl_SetStartupScript \ + (tclStubsPtr->tcl_SetStartupScript) /* 622 */ +#define Tcl_GetStartupScript \ + (tclStubsPtr->tcl_GetStartupScript) /* 623 */ +#define Tcl_CloseEx \ + (tclStubsPtr->tcl_CloseEx) /* 624 */ +#define Tcl_NRExprObj \ + (tclStubsPtr->tcl_NRExprObj) /* 625 */ +#define Tcl_NRSubstObj \ + (tclStubsPtr->tcl_NRSubstObj) /* 626 */ +#define Tcl_LoadFile \ + (tclStubsPtr->tcl_LoadFile) /* 627 */ +#define Tcl_FindSymbol \ + (tclStubsPtr->tcl_FindSymbol) /* 628 */ +#define Tcl_FSUnloadFile \ + (tclStubsPtr->tcl_FSUnloadFile) /* 629 */ +#define Tcl_ZlibStreamSetCompressionDictionary \ + (tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */ +#define Tcl_OpenTcpServerEx \ + (tclStubsPtr->tcl_OpenTcpServerEx) /* 631 */ +#define TclZipfs_Mount \ + (tclStubsPtr->tclZipfs_Mount) /* 632 */ +#define TclZipfs_Unmount \ + (tclStubsPtr->tclZipfs_Unmount) /* 633 */ +#define TclZipfs_TclLibrary \ + (tclStubsPtr->tclZipfs_TclLibrary) /* 634 */ +#define TclZipfs_MountBuffer \ + (tclStubsPtr->tclZipfs_MountBuffer) /* 635 */ +#define Tcl_FreeInternalRep \ + (tclStubsPtr->tcl_FreeInternalRep) /* 636 */ +#define Tcl_InitStringRep \ + (tclStubsPtr->tcl_InitStringRep) /* 637 */ +#define Tcl_FetchInternalRep \ + (tclStubsPtr->tcl_FetchInternalRep) /* 638 */ +#define Tcl_StoreInternalRep \ + (tclStubsPtr->tcl_StoreInternalRep) /* 639 */ +#define Tcl_HasStringRep \ + (tclStubsPtr->tcl_HasStringRep) /* 640 */ +#define Tcl_IncrRefCount \ + (tclStubsPtr->tcl_IncrRefCount) /* 641 */ +#define Tcl_DecrRefCount \ + (tclStubsPtr->tcl_DecrRefCount) /* 642 */ +#define Tcl_IsShared \ + (tclStubsPtr->tcl_IsShared) /* 643 */ +#define Tcl_LinkArray \ + (tclStubsPtr->tcl_LinkArray) /* 644 */ +#define Tcl_GetIntForIndex \ + (tclStubsPtr->tcl_GetIntForIndex) /* 645 */ +#define Tcl_UtfToUniChar \ + (tclStubsPtr->tcl_UtfToUniChar) /* 646 */ +#define Tcl_UniCharToUtfDString \ + (tclStubsPtr->tcl_UniCharToUtfDString) /* 647 */ +#define Tcl_UtfToUniCharDString \ + (tclStubsPtr->tcl_UtfToUniCharDString) /* 648 */ +#define Tcl_GetBytesFromObj \ + (tclStubsPtr->tcl_GetBytesFromObj) /* 649 */ +/* Slot 650 is reserved */ +/* Slot 651 is reserved */ +/* Slot 652 is reserved */ +/* Slot 653 is reserved */ +#define Tcl_UtfCharComplete \ + (tclStubsPtr->tcl_UtfCharComplete) /* 654 */ +#define Tcl_UtfNext \ + (tclStubsPtr->tcl_UtfNext) /* 655 */ +#define Tcl_UtfPrev \ + (tclStubsPtr->tcl_UtfPrev) /* 656 */ +#define Tcl_UniCharIsUnicode \ + (tclStubsPtr->tcl_UniCharIsUnicode) /* 657 */ +#define Tcl_ExternalToUtfDStringEx \ + (tclStubsPtr->tcl_ExternalToUtfDStringEx) /* 658 */ +#define Tcl_UtfToExternalDStringEx \ + (tclStubsPtr->tcl_UtfToExternalDStringEx) /* 659 */ +#define Tcl_AsyncMarkFromSignal \ + (tclStubsPtr->tcl_AsyncMarkFromSignal) /* 660 */ +/* Slot 661 is reserved */ +/* Slot 662 is reserved */ +/* Slot 663 is reserved */ +/* Slot 664 is reserved */ +/* Slot 665 is reserved */ +/* Slot 666 is reserved */ +/* Slot 667 is reserved */ +#define Tcl_UniCharLen \ + (tclStubsPtr->tcl_UniCharLen) /* 668 */ +#define TclNumUtfChars \ + (tclStubsPtr->tclNumUtfChars) /* 669 */ +#define TclGetCharLength \ + (tclStubsPtr->tclGetCharLength) /* 670 */ +#define TclUtfAtIndex \ + (tclStubsPtr->tclUtfAtIndex) /* 671 */ +#define TclGetRange \ + (tclStubsPtr->tclGetRange) /* 672 */ +#define TclGetUniChar \ + (tclStubsPtr->tclGetUniChar) /* 673 */ +#define Tcl_GetBool \ + (tclStubsPtr->tcl_GetBool) /* 674 */ +#define Tcl_GetBoolFromObj \ + (tclStubsPtr->tcl_GetBoolFromObj) /* 675 */ +/* Slot 676 is reserved */ +/* Slot 677 is reserved */ +/* Slot 678 is reserved */ +/* Slot 679 is reserved */ +#define Tcl_GetNumberFromObj \ + (tclStubsPtr->tcl_GetNumberFromObj) /* 680 */ +#define Tcl_GetNumber \ + (tclStubsPtr->tcl_GetNumber) /* 681 */ +#define Tcl_RemoveChannelMode \ + (tclStubsPtr->tcl_RemoveChannelMode) /* 682 */ +#define Tcl_GetEncodingNulLength \ + (tclStubsPtr->tcl_GetEncodingNulLength) /* 683 */ +#define Tcl_GetWideUIntFromObj \ + (tclStubsPtr->tcl_GetWideUIntFromObj) /* 684 */ +#define Tcl_DStringToObj \ + (tclStubsPtr->tcl_DStringToObj) /* 685 */ +/* Slot 686 is reserved */ +/* Slot 687 is reserved */ +#define TclUnusedStubEntry \ + (tclStubsPtr->tclUnusedStubEntry) /* 688 */ + +#endif /* defined(USE_TCL_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#undef TclUnusedStubEntry + +#if defined(USE_TCL_STUBS) +# undef Tcl_CreateInterp +# undef Tcl_FindExecutable +# undef Tcl_GetStringResult +# undef Tcl_Init +# undef Tcl_SetPanicProc +# undef Tcl_SetExitProc +# undef Tcl_ObjSetVar2 +# undef Tcl_StaticLibrary +# define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp()) +# define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp)) +# define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp)) +# define Tcl_ObjSetVar2(interp, part1, part2, newValue, flags) \ + (tclStubsPtr->tcl_ObjSetVar2(interp, part1, part2, newValue, flags)) +#endif + +#if defined(_WIN32) && defined(UNICODE) +# if defined(TCL_NO_DEPRECATED) +# define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg))) +# else +# define Tcl_FindExecutable(arg) ((void)((Tcl_FindExecutable)((const char *)(arg)))) +# define Tcl_SetPanicProc(arg) ((void)((Tcl_SetPanicProc)(arg))) +# endif +# define Tcl_MainEx Tcl_MainExW + EXTERN void Tcl_MainExW(Tcl_Size argc, wchar_t **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +#elif !defined(TCL_NO_DEPRECATED) +# define Tcl_FindExecutable(arg) ((void)((Tcl_FindExecutable)(arg))) +# define Tcl_SetPanicProc(arg) ((void)((Tcl_SetPanicProc)(arg))) +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#undef Tcl_SeekOld +#undef Tcl_TellOld + +#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_NewBooleanObj +#define Tcl_NewBooleanObj(intValue) \ + Tcl_NewWideIntObj((intValue)!=0) +#undef Tcl_DbNewBooleanObj +#define Tcl_DbNewBooleanObj(intValue, file, line) \ + Tcl_DbNewWideIntObj((intValue)!=0, file, line) +#undef Tcl_SetBooleanObj +#define Tcl_SetBooleanObj(objPtr, intValue) \ + Tcl_SetWideIntObj(objPtr, (intValue)!=0) +#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) +#undef Tcl_AddErrorInfo +#define Tcl_AddErrorInfo(interp, message) \ + Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, TCL_INDEX_NONE)) +#undef Tcl_AddObjErrorInfo +#define Tcl_AddObjErrorInfo(interp, message, length) \ + Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, length)) +#ifdef TCL_NO_DEPRECATED +#undef Tcl_FreeResult +#undef Tcl_AppendResultVA +#undef Tcl_AppendStringsToObjVA +#undef Tcl_SetErrorCodeVA +#undef Tcl_VarEvalVA +#undef Tcl_PanicVA +#undef Tcl_GetStringResult +#undef Tcl_GetDefaultEncodingDir +#undef Tcl_SetDefaultEncodingDir +#undef Tcl_UniCharNcmp +#undef Tcl_EvalTokens +#undef Tcl_UniCharNcasecmp +#undef Tcl_UniCharCaseMatch +#undef Tcl_GetMathFuncInfo +#undef Tcl_ListMathFuncs +#define Tcl_GetStringResult(interp) Tcl_GetString(Tcl_GetObjResult(interp)) +#undef Tcl_Eval +#define Tcl_Eval(interp, objPtr) \ + Tcl_EvalEx(interp, objPtr, TCL_INDEX_NONE, 0) +#undef Tcl_GlobalEval +#define Tcl_GlobalEval(interp, objPtr) \ + Tcl_EvalEx(interp, objPtr, TCL_INDEX_NONE, TCL_EVAL_GLOBAL) +#undef Tcl_SaveResult +#undef Tcl_RestoreResult +#undef Tcl_DiscardResult +#undef Tcl_SetResult +#define Tcl_SetResult(interp, result, freeProc) \ + do { \ + const char *__result = result; \ + Tcl_FreeProc *__freeProc = freeProc; \ + Tcl_SetObjResult(interp, Tcl_NewStringObj(__result, TCL_INDEX_NONE)); \ + if (__result != NULL && __freeProc != NULL && __freeProc != TCL_VOLATILE) { \ + if (__freeProc == TCL_DYNAMIC) { \ + ckfree((char *)__result); \ + } else { \ + (*__freeProc)((char *)__result); \ + } \ + } \ + } while(0) +#endif /* TCL_NO_DEPRECATED */ + +#if defined(USE_TCL_STUBS) +# if defined(_WIN32) && defined(_WIN64) +# undef Tcl_GetTime +/* Handle Win64 tk.dll being loaded in Cygwin64. */ +# define Tcl_GetTime(t) \ + do { \ + struct { \ + Tcl_Time now; \ + long long reserved; \ + } _t; \ + _t.reserved = -1; \ + tclStubsPtr->tcl_GetTime((&_t.now)); \ + if (_t.reserved != -1) { \ + _t.now.usec = (long) _t.reserved; \ + } \ + *(t) = _t.now; \ + } while (0) +# endif +# 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_GetLongFromObj +# undef Tcl_ExprLong +# undef Tcl_ExprLongObj +# undef Tcl_UniCharNcmp +# undef Tcl_UtfNcmp +# undef Tcl_UtfNcasecmp +# undef Tcl_UniCharNcasecmp +# define Tcl_GetLongFromObj ((int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetWideIntFromObj) +# 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))(void *)tclStubsPtr->tcl_UtfNcmp)(s1,s2,(unsigned int)(n)) +# define Tcl_UtfNcasecmp(s1,s2,n) \ + ((int(*)(const char*,const char*,unsigned int))(void *)tclStubsPtr->tcl_UtfNcasecmp)(s1,s2,(unsigned int)(n)) +# define Tcl_UniCharNcasecmp(ucs,uct,n) \ + ((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))(void *)tclStubsPtr->tcl_UniCharNcasecmp)(ucs,uct,(unsigned int)(n)) +# endif +#endif + +#undef Tcl_GetString +#undef Tcl_GetUnicode +#define Tcl_GetString(objPtr) \ + Tcl_GetStringFromObj(objPtr, NULL) +#define Tcl_GetUnicode(objPtr) \ + Tcl_GetUnicodeFromObj(objPtr, NULL) +#undef Tcl_GetIndexFromObjStruct +#undef Tcl_GetBooleanFromObj +#undef Tcl_GetBoolean +#if defined(USE_TCL_STUBS) +#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \ + (tclStubsPtr->tcl_GetIndexFromObjStruct((interp), (objPtr), (tablePtr), (offset), (msg), (flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr))) +#define Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) \ + (sizeof(*(boolPtr)) == sizeof(int) ? tclStubsPtr->tcl_GetBooleanFromObj(interp, objPtr, (int *)(boolPtr)) : \ + Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#define Tcl_GetBoolean(interp, src, boolPtr) \ + (sizeof(*(boolPtr)) == sizeof(int) ? tclStubsPtr->tcl_GetBoolean(interp, src, (int *)(boolPtr)) : \ + Tcl_GetBool(interp, src, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#else +#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \ + ((Tcl_GetIndexFromObjStruct)((interp), (objPtr), (tablePtr), (offset), (msg), (flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr))) +#define Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) \ + (sizeof(*(boolPtr)) == sizeof(int) ? Tcl_GetBooleanFromObj(interp, objPtr, (int *)(boolPtr)) : \ + Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#define Tcl_GetBoolean(interp, src, boolPtr) \ + (sizeof(*(boolPtr)) == sizeof(int) ? Tcl_GetBoolean(interp, src, (int *)(boolPtr)) : \ + Tcl_GetBool(interp, src, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#endif + +#undef Tcl_NewLongObj +#define Tcl_NewLongObj(value) Tcl_NewWideIntObj((long)(value)) +#undef Tcl_NewIntObj +#define Tcl_NewIntObj(value) Tcl_NewWideIntObj((int)(value)) +#undef Tcl_DbNewLongObj +#define Tcl_DbNewLongObj(value, file, line) Tcl_DbNewWideIntObj((long)(value), file, line) +#undef Tcl_SetIntObj +#define Tcl_SetIntObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (int)(value)) +#undef Tcl_SetLongObj +#define Tcl_SetLongObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (long)(value)) +#undef Tcl_BackgroundError +#define Tcl_BackgroundError(interp) Tcl_BackgroundException((interp), TCL_ERROR) +#undef Tcl_StringMatch +#define Tcl_StringMatch(str, pattern) Tcl_StringCaseMatch((str), (pattern), 0) + +#if TCL_UTF_MAX < 4 +# undef Tcl_UniCharToUtfDString +# define Tcl_UniCharToUtfDString Tcl_Char16ToUtfDString +# undef Tcl_UtfToUniCharDString +# define Tcl_UtfToUniCharDString Tcl_UtfToChar16DString +# undef Tcl_UtfToUniChar +# define Tcl_UtfToUniChar Tcl_UtfToChar16 +# undef Tcl_UniCharLen +# define Tcl_UniCharLen Tcl_Char16Len +#elif !defined(BUILD_tcl) +# undef Tcl_NumUtfChars +# define Tcl_NumUtfChars TclNumUtfChars +# undef Tcl_GetCharLength +# define Tcl_GetCharLength TclGetCharLength +# undef Tcl_UtfAtIndex +# define Tcl_UtfAtIndex TclUtfAtIndex +# undef Tcl_GetRange +# define Tcl_GetRange TclGetRange +# undef Tcl_GetUniChar +# define Tcl_GetUniChar TclGetUniChar +#endif +#if defined(USE_TCL_STUBS) +# define Tcl_WCharToUtfDString (sizeof(wchar_t) != sizeof(short) \ + ? (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))tclStubsPtr->tcl_UniCharToUtfDString \ + : (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_Char16ToUtfDString) +# define Tcl_UtfToWCharDString (sizeof(wchar_t) != sizeof(short) \ + ? (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))tclStubsPtr->tcl_UtfToUniCharDString \ + : (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToChar16DString) +# define Tcl_UtfToWChar (sizeof(wchar_t) != sizeof(short) \ + ? (int (*)(const char *, wchar_t *))tclStubsPtr->tcl_UtfToUniChar \ + : (int (*)(const char *, wchar_t *))Tcl_UtfToChar16) +# define Tcl_WCharLen (sizeof(wchar_t) != sizeof(short) \ + ? (Tcl_Size (*)(wchar_t *))tclStubsPtr->tcl_UniCharLen \ + : (Tcl_Size (*)(wchar_t *))Tcl_Char16Len) +#else /* !defined(USE_TCL_STUBS) */ +# define Tcl_WCharToUtfDString (sizeof(wchar_t) != sizeof(short) \ + ? (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_UniCharToUtfDString \ + : (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_Char16ToUtfDString) +# define Tcl_UtfToWCharDString (sizeof(wchar_t) != sizeof(short) \ + ? (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToUniCharDString \ + : (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToChar16DString) +# define Tcl_UtfToWChar (sizeof(wchar_t) != sizeof(short) \ + ? (int (*)(const char *, wchar_t *))Tcl_UtfToUniChar \ + : (int (*)(const char *, wchar_t *))Tcl_UtfToChar16) +# define Tcl_WCharLen (sizeof(wchar_t) != sizeof(short) \ + ? (Tcl_Size (*)(wchar_t *))Tcl_UniCharLen \ + : (Tcl_Size (*)(wchar_t *))Tcl_Char16Len) +#endif /* defined(USE_TCL_STUBS) */ + +/* + * Deprecated Tcl procedures: + */ + +#ifdef TCL_NO_DEPRECATED +# undef Tcl_SavedResult +#endif /* TCL_NO_DEPRECATED */ +#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) + +#if defined(TCL_NO_DEPRECATED) && defined(USE_TCL_STUBS) +#undef Tcl_Close +#define Tcl_Close(interp, chan) Tcl_CloseEx(interp, chan, 0) +#endif + +#undef TclUtfCharComplete +#undef TclUtfNext +#undef TclUtfPrev +#if defined(USE_TCL_STUBS) && (TCL_UTF_MAX < 4) && !defined(TCL_NO_DEPRECATED) +# undef Tcl_UtfCharComplete +# undef Tcl_UtfNext +# undef Tcl_UtfPrev +# define Tcl_UtfCharComplete (tclStubsPtr->tclUtfCharComplete) +# define Tcl_UtfNext (tclStubsPtr->tclUtfNext) +# define Tcl_UtfPrev (tclStubsPtr->tclUtfPrev) +#endif +#define Tcl_CreateSlave Tcl_CreateChild +#define Tcl_GetSlave Tcl_GetChild +#define Tcl_GetMaster Tcl_GetParent + +#define Tcl_NRCallObjProc2 Tcl_NRCallObjProc +#define Tcl_CreateObjCommand2 Tcl_CreateObjCommand +#define Tcl_CreateObjTrace2 Tcl_CreateObjTrace +#define Tcl_NRCreateCommand2 Tcl_NRCreateCommand + +/* TIP #660 */ +#define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj + +#endif /* _TCLDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tclPlatDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tclPlatDecls.h new file mode 100644 index 00000000..8d1eee13 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl8.7/tclPlatDecls.h @@ -0,0 +1,159 @@ +/* + * tclPlatDecls.h -- + * + * Declarations of platform specific Tcl APIs. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * All rights reserved. + */ + +#ifndef _TCLPLATDECLS +#define _TCLPLATDECLS + +#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 + +/* + * 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. + */ + +/* + * 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 + +#ifndef MODULE_SCOPE +# ifdef __cplusplus +# define MODULE_SCOPE extern "C" +# else +# define MODULE_SCOPE extern +# endif +#endif + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +/* 0 */ +EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len, + Tcl_DString *dsPtr); +/* 1 */ +EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len, + Tcl_DString *dsPtr); +/* Slot 2 is reserved */ +/* 3 */ +EXTERN void Tcl_WinConvertError(unsigned errCode); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 0 */ +EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, + const char *bundleName, int hasResourceFile, + Tcl_Size maxPathLen, char *libraryPath); +/* 1 */ +EXTERN int Tcl_MacOSXOpenVersionedBundleResources( + Tcl_Interp *interp, const char *bundleName, + const char *bundleVersion, + int hasResourceFile, Tcl_Size maxPathLen, + char *libraryPath); +/* 2 */ +EXTERN void Tcl_MacOSXNotifierAddRunLoopMode( + const void *runLoopMode); +#endif /* MACOSX */ + +typedef struct TclPlatStubs { + int magic; + void *hooks; + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ + TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */ + char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */ + void (*reserved2)(void); + void (*tcl_WinConvertError) (unsigned errCode); /* 3 */ +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 0 */ + int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 1 */ + void (*tcl_MacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 2 */ +#endif /* MACOSX */ +} TclPlatStubs; + +extern const TclPlatStubs *tclPlatStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +#define Tcl_WinUtfToTChar \ + (tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */ +#define Tcl_WinTCharToUtf \ + (tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */ +/* Slot 2 is reserved */ +#define Tcl_WinConvertError \ + (tclPlatStubsPtr->tcl_WinConvertError) /* 3 */ +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_MacOSXOpenBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ +#define Tcl_MacOSXOpenVersionedBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ +#define Tcl_MacOSXNotifierAddRunLoopMode \ + (tclPlatStubsPtr->tcl_MacOSXNotifierAddRunLoopMode) /* 2 */ +#endif /* MACOSX */ + +#endif /* defined(USE_TCL_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#ifdef MAC_OSX_TCL /* MACOSX */ +#undef Tcl_MacOSXOpenBundleResources +#define Tcl_MacOSXOpenBundleResources(a,b,c,d,e) Tcl_MacOSXOpenVersionedBundleResources(a,b,NULL,c,d,e) +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#if defined(USE_TCL_STUBS) && (defined(_WIN32) || defined(__CYGWIN__))\ + && (defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8) +#undef Tcl_WinUtfToTChar +#undef Tcl_WinTCharToUtf +#ifdef _WIN32 +#define Tcl_WinUtfToTChar(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ + (TCHAR *)Tcl_UtfToChar16DString((string), (len), (dsPtr))) +#define Tcl_WinTCharToUtf(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ + (char *)Tcl_Char16ToUtfDString((const unsigned short *)(string), ((((len) + 2) >> 1) - 1), (dsPtr))) +#endif +#endif + +#endif /* _TCLPLATDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tcl.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tcl.h new file mode 100644 index 00000000..0f532285 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tcl.h @@ -0,0 +1,2619 @@ +/* + * 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 (1 LOC patch) + * unix/configure.ac (2 LOC Major, 2 LOC minor, 1 LOC patch) + * win/configure.ac (as above) + * win/tcl.m4 (not patchlevel) + * README.md (sections 0 and 2, with and without separator) + * macosx/Tcl-Common.xcconfig (not patchlevel) 1 LOC + * win/README (not patchlevel) (sections 0 and 2) + * unix/tcl.spec (1 LOC patch) + */ + +#if !defined(TCL_MAJOR_VERSION) +# define TCL_MAJOR_VERSION 9 +#endif +#if TCL_MAJOR_VERSION == 9 +# define TCL_MINOR_VERSION 0 +# define TCL_RELEASE_LEVEL TCL_BETA_RELEASE +# define TCL_RELEASE_SERIAL 1 + +# define TCL_VERSION "9.0" +# define TCL_PATCH_LEVEL "9.0b1" +#endif /* TCL_MAJOR_VERSION */ + +#if defined(RC_INVOKED) +/* + * 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 +#endif /* RC_INVOKED */ + +/* + * 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 function + * declarations, that occur below, so block them out. + */ + +#ifndef RC_INVOKED + +/* + * Special macro to define mutexes. + */ + +#define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name; + +/* + * Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and + * SEEK_END, all #define'd by stdio.h . + * + * Also, many extensions need stdio.h, and they've grown accustomed to tcl.h + * providing it for them rather than #include-ing it themselves as they + * should, so also for their sake, we keep the #include to be consistent with + * prior Tcl releases. + */ + +#include +#include + +#if defined(__GNUC__) && (__GNUC__ > 2) +# if defined(_WIN32) && defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO +# define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__MINGW_PRINTF_FORMAT, a, b))) +# else +# define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b))) +# endif +# define TCL_NORETURN __attribute__ ((noreturn)) +# define TCL_NOINLINE __attribute__ ((noinline)) +# define TCL_NORETURN1 __attribute__ ((noreturn)) +#else +# define TCL_FORMAT_PRINTF(a,b) +# if defined(_MSC_VER) +# define TCL_NORETURN _declspec(noreturn) +# define TCL_NOINLINE __declspec(noinline) +# else +# define TCL_NORETURN /* nothing */ +# define TCL_NOINLINE /* nothing */ +# endif +# define TCL_NORETURN1 /* nothing */ +#endif + +/* + * Allow a part of Tcl's API to be explicitly marked as deprecated. + * + * Used to make TIP 330/336 generate moans even if people use the + * compatibility macros. Change your code, guys! We won't support you forever. + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) +# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__ (msg))) +# else +# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__)) +# endif +#else +# define TCL_DEPRECATED_API(msg) /* nothing portable */ +#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. + * + * Note: when building static but linking dynamically to MSVCRT we must still + * correctly decorate the C library imported function. Use CRTIMPORT + * for this purpose. _DLL is defined by the compiler when linking to + * MSVCRT. + */ + +#ifdef _WIN32 +# ifdef STATIC_BUILD +# define DLLIMPORT +# define DLLEXPORT +# ifdef _DLL +# define CRTIMPORT __declspec(dllimport) +# else +# define CRTIMPORT +# endif +# else +# define DLLIMPORT __declspec(dllimport) +# define DLLEXPORT __declspec(dllexport) +# define CRTIMPORT __declspec(dllimport) +# endif +#else +# define DLLIMPORT +# if defined(__GNUC__) && __GNUC__ > 3 +# define DLLEXPORT __attribute__ ((visibility("default"))) +# else +# define DLLEXPORT +# endif +# define CRTIMPORT +#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 being 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 + +#if !defined(CONST86) && !defined(TCL_NO_DEPRECATED) +# define CONST86 const +#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 + +/* + * Miscellaneous declarations. + */ + +typedef void *ClientData; + +/* + * Darwin specific configure overrides (to support fat compiles, where + * configure runs only once for multiple architectures): + */ + +#ifdef __APPLE__ +# ifdef __LP64__ +# define TCL_WIDE_INT_IS_LONG 1 +# define TCL_CFG_DO64BIT 1 +# else /* !__LP64__ */ +# undef TCL_WIDE_INT_IS_LONG +# undef TCL_CFG_DO64BIT +# endif /* __LP64__ */ +# undef HAVE_STRUCT_STAT64 +#endif /* __APPLE__ */ + +/* Cross-compiling 32-bit on a 64-bit platform? Then our + * configure script does the wrong thing. Correct that here. + */ +#if defined(__GNUC__) && !defined(_WIN32) && !defined(__LP64__) +# undef TCL_WIDE_INT_IS_LONG +#endif + +/* + * 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 + * LP64 system such as modern Solaris or Linux ... not including Win64) + * 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)) + */ + +#if !defined(TCL_WIDE_INT_TYPE) && !defined(TCL_WIDE_INT_IS_LONG) && !defined(_WIN32) && !defined(__GNUC__) +/* + * Don't know what platform it is and configure hasn't discovered what is + * going on for us. Try to guess... + */ +# include +# if defined(LLONG_MAX) && (LLONG_MAX == LONG_MAX) +# define TCL_WIDE_INT_IS_LONG 1 +# endif +#endif + +#ifndef TCL_WIDE_INT_TYPE +# define TCL_WIDE_INT_TYPE long long +#endif /* !TCL_WIDE_INT_TYPE */ + +typedef TCL_WIDE_INT_TYPE Tcl_WideInt; +typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; + +#ifndef TCL_LL_MODIFIER +# if defined(_WIN32) && (!defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO) +# define TCL_LL_MODIFIER "I64" +# else +# define TCL_LL_MODIFIER "ll" +# endif +#endif /* !TCL_LL_MODIFIER */ +#ifndef TCL_Z_MODIFIER +# if defined(__GNUC__) && !defined(_WIN32) +# define TCL_Z_MODIFIER "z" +# elif defined(_WIN64) +# define TCL_Z_MODIFIER TCL_LL_MODIFIER +# else +# define TCL_Z_MODIFIER "" +# endif +#endif /* !TCL_Z_MODIFIER */ +#ifndef TCL_T_MODIFIER +# if defined(__GNUC__) && !defined(_WIN32) +# define TCL_T_MODIFIER "t" +# elif defined(_WIN64) +# define TCL_T_MODIFIER TCL_LL_MODIFIER +# else +# define TCL_T_MODIFIER TCL_Z_MODIFIER +# endif +#endif /* !TCL_T_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))) + +#if TCL_MAJOR_VERSION < 9 + typedef int Tcl_Size; +# define TCL_SIZE_MAX ((int)(((unsigned int)-1)>>1)) +# define TCL_SIZE_MODIFIER "" +#else + typedef ptrdiff_t Tcl_Size; +# define TCL_SIZE_MAX ((ptrdiff_t)(((size_t)-1)>>1)) +# define TCL_SIZE_MODIFIER TCL_T_MODIFIER +#endif /* TCL_MAJOR_VERSION */ + +#ifdef _WIN32 +# if TCL_MAJOR_VERSION > 8 || defined(_WIN64) || defined(_USE_64BIT_TIME_T) + typedef struct __stat64 Tcl_StatBuf; +# elif defined(_USE_32BIT_TIME_T) + typedef struct _stati64 Tcl_StatBuf; +# else + typedef struct _stat32i64 Tcl_StatBuf; +# endif +#elif defined(__CYGWIN__) + typedef struct { + unsigned 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 */ + unsigned 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; + } Tcl_StatBuf; +#else + typedef struct stat Tcl_StatBuf; +#endif + +/* + *---------------------------------------------------------------------------- + * Data structures defined opaquely in this module. The definitions below just + * provide dummy types. + */ + +typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler; +typedef struct Tcl_Channel_ *Tcl_Channel; +typedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion; +typedef struct Tcl_Command_ *Tcl_Command; +typedef struct Tcl_Condition_ *Tcl_Condition; +typedef struct Tcl_Dict_ *Tcl_Dict; +typedef struct Tcl_EncodingState_ *Tcl_EncodingState; +typedef struct Tcl_Encoding_ *Tcl_Encoding; +typedef struct Tcl_Event Tcl_Event; +typedef struct Tcl_Interp Tcl_Interp; +typedef struct Tcl_InterpState_ *Tcl_InterpState; +typedef struct Tcl_LoadHandle_ *Tcl_LoadHandle; +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_ZLibStream_ *Tcl_ZlibStream; + +/* + *---------------------------------------------------------------------------- + * Definition of the interface to functions implementing threads. A function + * 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) (void *clientData); +#else +typedef void (Tcl_ThreadCreateProc) (void *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. + */ + +#if defined _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_StringCaseMatch. + */ + +#define TCL_MATCH_NOCASE (1<<0) + +/* + * 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. */ + +/* + * 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 { +#if TCL_MAJOR_VERSION > 8 + Tcl_Size start; /* Character offset of first character in + * match. */ + Tcl_Size end; /* Character offset of first character after + * the match. */ +#else + long start; + long end; +#endif +} Tcl_RegExpIndices; + +typedef struct Tcl_RegExpInfo { + Tcl_Size nsubs; /* Number of subexpressions in the compiled + * expression. */ + Tcl_RegExpIndices *matches; /* Array of nsubs match offset pairs. */ +#if TCL_MAJOR_VERSION > 8 + Tcl_Size extendStart; /* The offset at which a subsequent match + * might begin. */ +#else + long extendStart; + long reserved; /* Reserved for later use. */ +#endif +} 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 functions + * Tcl_GetObjResult() or Tcl_GetStringResult() to read the interpreter's + * result. See the SetResult man page for details. Besides this result, the + * command function 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 function return; + * the interpreter's result contains the function'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 + +/* + *---------------------------------------------------------------------------- + * 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 + +/* + * Forward declaration of Tcl_Obj to prevent an error when the forward + * reference to Tcl_Obj is encountered in the function types declared below. + */ + +struct Tcl_Obj; + +/* + *---------------------------------------------------------------------------- + * Function types defined by Tcl: + */ + +typedef int (Tcl_AppInitProc) (Tcl_Interp *interp); +typedef int (Tcl_AsyncProc) (void *clientData, Tcl_Interp *interp, + int code); +typedef void (Tcl_ChannelProc) (void *clientData, int mask); +typedef void (Tcl_CloseProc) (void *data); +typedef void (Tcl_CmdDeleteProc) (void *clientData); +typedef int (Tcl_CmdProc) (void *clientData, Tcl_Interp *interp, + int argc, const char *argv[]); +typedef void (Tcl_CmdTraceProc) (void *clientData, Tcl_Interp *interp, + int level, char *command, Tcl_CmdProc *proc, + void *cmdClientData, int argc, const char *argv[]); +typedef int (Tcl_CmdObjTraceProc) (void *clientData, Tcl_Interp *interp, + int level, const char *command, Tcl_Command commandInfo, int objc, + struct Tcl_Obj *const *objv); +typedef void (Tcl_CmdObjTraceDeleteProc) (void *clientData); +typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, + struct Tcl_Obj *dupPtr); +typedef int (Tcl_EncodingConvertProc) (void *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) (void *clientData); +typedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags); +typedef void (Tcl_EventCheckProc) (void *clientData, int flags); +typedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, void *clientData); +typedef void (Tcl_EventSetupProc) (void *clientData, int flags); +typedef void (Tcl_ExitProc) (void *clientData); +typedef void (Tcl_FileProc) (void *clientData, int mask); +typedef void (Tcl_FileFreeProc) (void *clientData); +typedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr); +typedef void (Tcl_IdleProc) (void *clientData); +typedef void (Tcl_InterpDeleteProc) (void *clientData, + Tcl_Interp *interp); +typedef void (Tcl_NamespaceDeleteProc) (void *clientData); +typedef int (Tcl_ObjCmdProc) (void *clientData, Tcl_Interp *interp, + int objc, struct Tcl_Obj *const *objv); +#if TCL_MAJOR_VERSION > 8 +typedef int (Tcl_ObjCmdProc2) (void *clientData, Tcl_Interp *interp, + Tcl_Size objc, struct Tcl_Obj *const *objv); +typedef int (Tcl_CmdObjTraceProc2) (void *clientData, Tcl_Interp *interp, + Tcl_Size level, const char *command, Tcl_Command commandInfo, Tcl_Size objc, + struct Tcl_Obj *const *objv); +typedef void (Tcl_FreeProc) (void *blockPtr); +#define Tcl_ExitProc Tcl_FreeProc +#define Tcl_FileFreeProc Tcl_FreeProc +#define Tcl_FileFreeProc Tcl_FreeProc +#define Tcl_EncodingFreeProc Tcl_FreeProc +#else +#define Tcl_ObjCmdProc2 Tcl_ObjCmdProc +#define Tcl_CmdObjTraceProc2 Tcl_CmdObjTraceProc +typedef void (Tcl_FreeProc) (char *blockPtr); +#endif +typedef int (Tcl_LibraryInitProc) (Tcl_Interp *interp); +typedef int (Tcl_LibraryUnloadProc) (Tcl_Interp *interp, int flags); +typedef void (Tcl_PanicProc) (const char *format, ...); +typedef void (Tcl_TcpAcceptProc) (void *callbackData, Tcl_Channel chan, + char *address, int port); +typedef void (Tcl_TimerProc) (void *clientData); +typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr); +typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr); +typedef char * (Tcl_VarTraceProc) (void *clientData, Tcl_Interp *interp, + const char *part1, const char *part2, int flags); +typedef void (Tcl_CommandTraceProc) (void *clientData, Tcl_Interp *interp, + const char *oldName, const char *newName, int flags); +typedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc, + void *clientData); +typedef void (Tcl_DeleteFileHandlerProc) (int fd); +typedef void (Tcl_AlertNotifierProc) (void *clientData); +typedef void (Tcl_ServiceModeHookProc) (int mode); +typedef void *(Tcl_InitNotifierProc) (void); +typedef void (Tcl_FinalizeNotifierProc) (void *clientData); +typedef void (Tcl_MainLoopProc) (void); + +/* Abstract List functions */ +typedef Tcl_Size (Tcl_ObjTypeLengthProc) (struct Tcl_Obj *listPtr); +typedef int (Tcl_ObjTypeIndexProc) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, + Tcl_Size index, struct Tcl_Obj** elemObj); +typedef int (Tcl_ObjTypeSliceProc) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, + Tcl_Size fromIdx, Tcl_Size toIdx, + struct Tcl_Obj **newObjPtr); +typedef int (Tcl_ObjTypeReverseProc) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, + struct Tcl_Obj **newObjPtr); +typedef int (Tcl_ObjTypeGetElements) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, + Tcl_Size *objcptr, struct Tcl_Obj ***objvptr); +typedef struct Tcl_Obj* (Tcl_ObjTypeSetElement) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, + Tcl_Size indexCount, + struct Tcl_Obj *const indexArray[], + struct Tcl_Obj *valueObj); +typedef int (Tcl_ObjTypeReplaceProc) (Tcl_Interp *interp, struct Tcl_Obj *listObj, + Tcl_Size first, Tcl_Size numToDelete, + Tcl_Size numToInsert, + struct Tcl_Obj *const insertObjs[]); +typedef int (Tcl_ObjTypeInOperatorProc) (Tcl_Interp *interp, struct Tcl_Obj *valueObj, + struct Tcl_Obj *listObj, int *boolResult); + +#ifndef TCL_NO_DEPRECATED +# define Tcl_PackageInitProc Tcl_LibraryInitProc +# define Tcl_PackageUnloadProc Tcl_LibraryUnloadProc +#endif + +/* + *---------------------------------------------------------------------------- + * The following structure represents a type of object, which is a particular + * internal representation for an object plus a set of functions that provide + * standard operations on objects of that type. + */ + +typedef struct Tcl_ObjType { + const 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. */ +#if TCL_MAJOR_VERSION > 8 + size_t version; + + /* List emulation functions - ObjType Version 1 */ + Tcl_ObjTypeLengthProc *lengthProc; /* Return the [llength] of the + ** AbstractList */ + Tcl_ObjTypeIndexProc *indexProc; /* Return a value (Tcl_Obj) for + ** [lindex $al $index] */ + Tcl_ObjTypeSliceProc *sliceProc; /* Return an AbstractList for + ** [lrange $al $start $end] */ + Tcl_ObjTypeReverseProc *reverseProc; /* Return an AbstractList for + ** [lreverse $al] */ + Tcl_ObjTypeGetElements *getElementsProc; /* Return an objv[] of all elements in + ** the list */ + Tcl_ObjTypeSetElement *setElementProc; /* Replace the element at the indicie + ** with the given valueObj. */ + Tcl_ObjTypeReplaceProc *replaceProc; /* Replace subset with subset */ + Tcl_ObjTypeInOperatorProc *inOperProc; /* "in" and "ni" expr list + ** operation Determine if the given + ** string value matches an element in + ** the list */ +#endif +} Tcl_ObjType; + +#if TCL_MAJOR_VERSION > 8 +# define TCL_OBJTYPE_V0 0, \ + 0,0,0,0,0,0,0,0 /* Pre-Tcl 9 */ +# define TCL_OBJTYPE_V1(a) offsetof(Tcl_ObjType, indexProc), \ + a,0,0,0,0,0,0,0 /* Tcl 9 Version 1 */ +# define TCL_OBJTYPE_V2(a,b,c,d,e,f,g,h) sizeof(Tcl_ObjType), \ + a,b,c,d,e,f,g,h /* Tcl 9 - AbstractLists */ +#else +# define TCL_OBJTYPE_V0 /* just empty */ +#endif + +/* + * The following structure stores an internal representation (internalrep) for + * a Tcl value. An internalrep is associated with an Tcl_ObjType when both + * are stored in the same Tcl_Obj. The routines of the Tcl_ObjType govern + * the handling of the internalrep. + */ + +typedef union Tcl_ObjInternalRep { /* The internal representation: */ + long longValue; /* - an long integer value. */ + double doubleValue; /* - a double-precision floating value. */ + void *otherValuePtr; /* - another, type-specific value, */ + /* not used internally any more. */ + Tcl_WideInt wideValue; /* - an integer value >= 64bits */ + struct { /* - internal rep as two pointers. */ + void *ptr1; + void *ptr2; + } twoPtrValue; + struct { /* - internal rep as a pointer and a long, */ + void *ptr; /* not used internally any more. */ + unsigned long value; + } ptrAndLongRep; +} Tcl_ObjInternalRep; + +/* + * 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 { + Tcl_Size 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 Tcl_Alloc. 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. */ + Tcl_Size length; /* The number of bytes at *bytes, not + * including the terminating null. */ + const 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). */ + Tcl_ObjInternalRep internalRep; /* The internal representation: */ +} Tcl_Obj; + + +/* + *---------------------------------------------------------------------------- + * 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 ::. */ + void *clientData; /* Arbitrary value associated with this + * namespace. */ + Tcl_NamespaceDeleteProc *deleteProc; + /* Function 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; + Tcl_Size dummy2; + void *dummy3; + void *dummy4; + void *dummy5; + Tcl_Size dummy6; + void *dummy7; + void *dummy8; + Tcl_Size 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 + * function while proc is a traditional Tcl argc/argv string-based function. + * 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 function was registered by + * Tcl_CreateObjCommand, and to 0 if a string-based function was registered by + * Tcl_CreateCommand. The other function is typically set to a compatibility + * wrapper that does string-to-object or object-to-string argument conversions + * then calls the other function. + */ + +typedef struct { + int isNativeObjectProc; /* 1 if objProc was registered by a call to + * Tcl_CreateObjCommand; 2 if objProc was registered by + * a call to Tcl_CreateObjCommand2; 0 otherwise. + * Tcl_SetCmdInfo does not modify this field. */ + Tcl_ObjCmdProc *objProc; /* Command's object-based function. */ + void *objClientData; /* ClientData for object proc. */ + Tcl_CmdProc *proc; /* Command's string-based function. */ + void *clientData; /* ClientData for string proc. */ + Tcl_CmdDeleteProc *deleteProc; + /* Function to call when command is + * deleted. */ + void *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 + * TclRenameCommand or Tcl_Eval (of 'rename') + * to do that. */ + Tcl_ObjCmdProc2 *objProc2; /* Command's object2-based function. */ + void *objClientData2; /* ClientData for object2 proc. */ +} Tcl_CmdInfo; + +/* + *---------------------------------------------------------------------------- + * The structure defined below is used to hold dynamic strings. The only + * fields that clients should use are string and length, accessible via the + * macros Tcl_DStringValue and Tcl_DStringLength. + */ + +#define TCL_DSTRING_STATIC_SIZE 200 +typedef struct Tcl_DString { + char *string; /* Points to beginning of string: either + * staticSpace below or a malloced array. */ + Tcl_Size length; /* Number of bytes in string excluding + * terminating nul */ + Tcl_Size 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) + +/* + * Definitions for the maximum number of digits of precision that may be + * produced by Tcl_PrintDouble, 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 (3*(int)sizeof(Tcl_WideInt)) + +/* + *---------------------------------------------------------------------------- + * Type values returned by Tcl_GetNumberFromObj + * TCL_NUMBER_INT Representation is a Tcl_WideInt + * TCL_NUMBER_BIG Representation is an mp_int + * TCL_NUMBER_DOUBLE Representation is a double + * TCL_NUMBER_NAN Value is NaN. + */ + +#define TCL_NUMBER_INT 2 +#define TCL_NUMBER_BIG 3 +#define TCL_NUMBER_DOUBLE 4 +#define TCL_NUMBER_NAN 5 + +/* + * Flag values passed to Tcl_ConvertElement. + * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to + * use backslash quoting instead. + * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It + * is safe to leave the hash unquoted when the element is not the first + * element of a list, and this flag can be used by the caller to indicate + * that condition. + */ + +#define TCL_DONT_USE_BRACES 1 +#define TCL_DONT_QUOTE_HASH 8 + +/* + * Flags that may be passed to Tcl_GetIndexFromObj. + * TCL_EXACT disallows abbreviated strings. + * TCL_NULL_OK allows the empty string or NULL to return TCL_OK. + * The returned value will be -1; + * TCL_INDEX_TEMP_TABLE disallows caching of lookups. A possible use case is + * a table that will not live long enough to make it worthwhile. + */ + +#define TCL_EXACT 1 +#define TCL_NULL_OK 32 +#define TCL_INDEX_TEMP_TABLE 64 + +/* + * Flags that may be passed to Tcl_UniCharToUtf. + * TCL_COMBINE Combine surrogates + */ + +#if TCL_MAJOR_VERSION > 8 +# define TCL_COMBINE 0x1000000 +#else +# define TCL_COMBINE 0 +#endif +/* + *---------------------------------------------------------------------------- + * Flag values passed to Tcl_RecordAndEval, Tcl_EvalObj, Tcl_EvalObjv. + * WARNING: these bit choices must not conflict with the bit choices for + * evalFlag bits in tclInt.h! + * + * Meanings: + * TCL_NO_EVAL: Just record this command + * TCL_EVAL_GLOBAL: Execute script in global namespace + * TCL_EVAL_DIRECT: Do not compile this script + * TCL_EVAL_INVOKE: Magical Tcl_EvalObjv mode for aliases/ensembles + * o Run in iPtr->lookupNsPtr or global namespace + * o Cut out of error traces + * o Don't reset the flags controlling ensemble + * error message rewriting. + * TCL_CANCEL_UNWIND: Magical Tcl_CancelEval mode that causes the + * stack for the script in progress to be + * completely unwound. + * TCL_EVAL_NOERR: Do no exception reporting at all, just return + * as the caller will report. + */ + +#define TCL_NO_EVAL 0x010000 +#define TCL_EVAL_GLOBAL 0x020000 +#define TCL_EVAL_DIRECT 0x040000 +#define TCL_EVAL_INVOKE 0x080000 +#define TCL_CANCEL_UNWIND 0x100000 +#define TCL_EVAL_NOERR 0x200000 + +/* + * 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 functions. + * WARNING: these bit choices must not conflict with the bit choice for + * TCL_CANCEL_UNWIND, above. + */ + +#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_LEAVE_ERR_MSG 0x200 +#define TCL_TRACE_ARRAY 0x800 +/* Indicate the semantics of the result of a trace. */ +#define TCL_TRACE_RESULT_DYNAMIC 0x8000 +#define TCL_TRACE_RESULT_OBJECT 0x10000 + +/* + * Flag values for ensemble commands. + */ + +#define TCL_ENSEMBLE_PREFIX 0x02/* Flag value to say whether to allow + * unambiguous prefixes of commands or to + * require exact matches for command names. */ + +/* + * Flag values passed to command-related functions. + */ + +#define TCL_TRACE_RENAME 0x2000 +#define TCL_TRACE_DELETE 0x4000 + +#define TCL_ALLOW_INLINE_COMPILATION 0x20000 + +/* + * 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_CHAR 6 +#define TCL_LINK_UCHAR 7 +#define TCL_LINK_SHORT 8 +#define TCL_LINK_USHORT 9 +#define TCL_LINK_UINT 10 +#define TCL_LINK_LONG ((sizeof(long) != sizeof(int)) ? TCL_LINK_WIDE_INT : TCL_LINK_INT) +#define TCL_LINK_ULONG ((sizeof(long) != sizeof(int)) ? TCL_LINK_WIDE_UINT : TCL_LINK_UINT) +#define TCL_LINK_FLOAT 13 +#define TCL_LINK_WIDE_UINT 14 +#define TCL_LINK_CHARS 15 +#define TCL_LINK_BINARY 16 +#define TCL_LINK_READ_ONLY 0x80 + +/* + *---------------------------------------------------------------------------- + * Forward declarations of Tcl_HashTable and related types. + */ + +#ifndef TCL_HASH_TYPE +#if TCL_MAJOR_VERSION > 8 +# define TCL_HASH_TYPE size_t +#else +# define TCL_HASH_TYPE unsigned +#endif +#endif + +typedef struct Tcl_HashKeyType Tcl_HashKeyType; +typedef struct Tcl_HashTable Tcl_HashTable; +typedef struct Tcl_HashEntry Tcl_HashEntry; + +typedef TCL_HASH_TYPE (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr); +typedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr); +typedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr, + void *keyPtr); +typedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *hPtr); + +/* + * 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. */ + size_t hash; /* Hash value. */ + void *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[1]; /* 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. + * TCL_HASH_KEY_SYSTEM_HASH - If this flag is set then all memory internally + * allocated for the hash table that is not for an + * entry will use the system heap. + */ + +#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1 +#define TCL_HASH_KEY_SYSTEM_HASH 0x2 + +/* + * 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. */ + Tcl_HashKeyProc *hashKeyProc; + /* Calculates a hash value for the key. If + * this is NULL then the pointer itself is + * used as a hash value. */ + Tcl_CompareHashKeysProc *compareKeysProc; + /* 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_AllocHashEntryProc *allocEntryProc; + /* 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_FreeHashEntryProc *freeEntryProc; + /* 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. */ +}; + +/* + * 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). */ + Tcl_Size numBuckets; /* Total number of buckets allocated at + * **bucketPtr. */ + Tcl_Size numEntries; /* Total number of entries present in + * table. */ + Tcl_Size rebuildSize; /* Enlarge table when numEntries gets to be + * this large. */ +#if TCL_MAJOR_VERSION > 8 + size_t mask; /* Mask value used in hashing function. */ +#endif + int downShift; /* Shift count used in hashing function. + * Designed to use high-order bits of + * randomized keys. */ +#if TCL_MAJOR_VERSION < 9 + int mask; /* Mask value used in hashing function. */ +#endif + 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. */ + Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key); + Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key, + int *newPtr); + const 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. */ + Tcl_Size nextIndex; /* Index of next bucket to be enumerated after + * present one. */ + Tcl_HashEntry *nextEntryPtr;/* Next entry to be enumerated in 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 compatibility 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 compatibility + * 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) +#define TCL_CUSTOM_TYPE_KEYS (-2) +#define TCL_CUSTOM_PTR_KEYS (-1) + +/* + * Structure definition for information used to keep track of searches through + * dictionaries. These fields should not be accessed by code outside + * tclDictObj.c + */ + +typedef struct { + void *next; /* Search position for underlying hash + * table. */ + TCL_HASH_TYPE epoch; /* Epoch marker for dictionary being searched, + * or 0 if search has terminated. */ + Tcl_Dict dictionaryPtr; /* Reference to dictionary being searched. */ +} Tcl_DictSearch; + +/* + *---------------------------------------------------------------------------- + * 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; /* Function to call to service this event. */ + struct Tcl_Event *nextPtr; /* Next in list of pending events, or NULL. */ +}; + +/* + * Positions to pass to Tcl_QueueEvent/Tcl_ThreadQueueEvent: + */ + +typedef enum { + TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK, + TCL_QUEUE_ALERT_IF_EMPTY=4 +} 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 { +#if TCL_MAJOR_VERSION > 8 + long long sec; /* Seconds. */ +#else + long sec; /* Seconds. */ +#endif +#if defined(_CYGWIN_) && TCL_MAJOR_VERSION > 8 + int usec; /* Microseconds. */ +#else + long usec; /* Microseconds. */ +#endif +} Tcl_Time; + +typedef void (Tcl_SetTimerProc) (const Tcl_Time *timePtr); +typedef int (Tcl_WaitForEventProc) (const Tcl_Time *timePtr); + +/* + * TIP #233 (Virtualized Time) + */ + +typedef void (Tcl_GetTimeProc) (Tcl_Time *timebuf, void *clientData); +typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, void *clientData); + +/* + *---------------------------------------------------------------------------- + * 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. + */ + +#if TCL_MAJOR_VERSION > 8 +# define TCL_CLOSE2PROC NULL +#else +# define TCL_CLOSE2PROC ((void *) 1) +#endif + +/* + * Channel version tag. This was introduced in 8.3.2/8.4. + */ + +#define TCL_CHANNEL_VERSION_5 ((Tcl_ChannelTypeVersion) 0x5) + +/* + * 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) (void *instanceData, int mode); +typedef void Tcl_DriverCloseProc; +typedef int (Tcl_DriverClose2Proc) (void *instanceData, + Tcl_Interp *interp, int flags); +typedef int (Tcl_DriverInputProc) (void *instanceData, char *buf, + int toRead, int *errorCodePtr); +typedef int (Tcl_DriverOutputProc) (void *instanceData, + const char *buf, int toWrite, int *errorCodePtr); +typedef void Tcl_DriverSeekProc; +typedef int (Tcl_DriverSetOptionProc) (void *instanceData, + Tcl_Interp *interp, const char *optionName, + const char *value); +typedef int (Tcl_DriverGetOptionProc) (void *instanceData, + Tcl_Interp *interp, const char *optionName, + Tcl_DString *dsPtr); +typedef void (Tcl_DriverWatchProc) (void *instanceData, int mask); +typedef int (Tcl_DriverGetHandleProc) (void *instanceData, + int direction, void **handlePtr); +typedef int (Tcl_DriverFlushProc) (void *instanceData); +typedef int (Tcl_DriverHandlerProc) (void *instanceData, + int interestMask); +typedef long long (Tcl_DriverWideSeekProc) (void *instanceData, + long long offset, int mode, int *errorCodePtr); +/* + * TIP #218, Channel Thread Actions + */ +typedef void (Tcl_DriverThreadActionProc) (void *instanceData, + int action); +/* + * TIP #208, File Truncation (etc.) + */ +typedef int (Tcl_DriverTruncateProc) (void *instanceData, + long long length); + +/* + * 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 { + const 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. */ + void *closeProc; /* Not used any more. */ + Tcl_DriverInputProc *inputProc; + /* Function to call for input on channel. */ + Tcl_DriverOutputProc *outputProc; + /* Function to call for output on channel. */ + void *seekProc; /* Not used any more. */ + 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; + /* Function 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. */ + Tcl_DriverFlushProc *flushProc; + /* Function to call to flush a channel. May be + * NULL. */ + Tcl_DriverHandlerProc *handlerProc; + /* Function to call to handle a channel event. + * This will be passed up the stacked channel + * chain. */ + Tcl_DriverWideSeekProc *wideSeekProc; + /* Function to call to seek on the channel + * which can handle 64-bit offsets. May be + * NULL, and must be NULL if seekProc is + * NULL. */ + Tcl_DriverThreadActionProc *threadActionProc; + /* Function to call to notify the driver of + * thread specific activity for a channel. May + * be NULL. */ + Tcl_DriverTruncateProc *truncateProc; + /* Function to call to truncate the underlying + * file to a particular length. May be NULL if + * the channel does not support truncation. */ +} 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 function 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 { + int type; /* Corresponds to bcdpfls as in 'find -t'. */ + int perm; /* Corresponds to file permissions. */ + Tcl_Obj *macType; /* Acceptable Mac type. */ + Tcl_Obj *macCreator; /* Acceptable Mac creator. */ +} 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) + +/* + * Flags for the unload callback function. + */ + +#define TCL_UNLOAD_DETACH_FROM_INTERPRETER (1<<0) +#define TCL_UNLOAD_DETACH_FROM_PROCESS (1<<1) + +/* + * Typedefs for the various filesystem operations: + */ + +typedef int (Tcl_FSStatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +typedef int (Tcl_FSAccessProc) (Tcl_Obj *pathPtr, int mode); +typedef Tcl_Channel (Tcl_FSOpenFileChannelProc) (Tcl_Interp *interp, + Tcl_Obj *pathPtr, int mode, int permissions); +typedef int (Tcl_FSMatchInDirectoryProc) (Tcl_Interp *interp, Tcl_Obj *result, + Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); +typedef Tcl_Obj * (Tcl_FSGetCwdProc) (Tcl_Interp *interp); +typedef int (Tcl_FSChdirProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSLstatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +typedef int (Tcl_FSCreateDirectoryProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSDeleteFileProc) (Tcl_Obj *pathPtr); +typedef int (Tcl_FSCopyDirectoryProc) (Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); +typedef int (Tcl_FSCopyFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); +typedef int (Tcl_FSRemoveDirectoryProc) (Tcl_Obj *pathPtr, int recursive, + Tcl_Obj **errorPtr); +typedef int (Tcl_FSRenameFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); +typedef void (Tcl_FSUnloadFileProc) (Tcl_LoadHandle loadHandle); +typedef Tcl_Obj * (Tcl_FSListVolumesProc) (void); +/* We have to declare the utime structure here. */ +struct utimbuf; +typedef int (Tcl_FSUtimeProc) (Tcl_Obj *pathPtr, struct utimbuf *tval); +typedef int (Tcl_FSNormalizePathProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + int nextCheckpoint); +typedef int (Tcl_FSFileAttrsGetProc) (Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); +typedef const char *const * (Tcl_FSFileAttrStringsProc) (Tcl_Obj *pathPtr, + Tcl_Obj **objPtrRef); +typedef int (Tcl_FSFileAttrsSetProc) (Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj *objPtr); +typedef Tcl_Obj * (Tcl_FSLinkProc) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, + int linkType); +typedef int (Tcl_FSLoadFileProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); +typedef int (Tcl_FSPathInFilesystemProc) (Tcl_Obj *pathPtr, + void **clientDataPtr); +typedef Tcl_Obj * (Tcl_FSFilesystemPathTypeProc) (Tcl_Obj *pathPtr); +typedef Tcl_Obj * (Tcl_FSFilesystemSeparatorProc) (Tcl_Obj *pathPtr); +#define Tcl_FSFreeInternalRepProc Tcl_FreeProc +typedef void *(Tcl_FSDupInternalRepProc) (void *clientData); +typedef Tcl_Obj * (Tcl_FSInternalToNormalizedProc) (void *clientData); +typedef void *(Tcl_FSCreateInternalRepProc) (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 the functions that form the interface for a particulr the + * 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. */ + Tcl_Size structureLength; /* Length of this structure, so future binary + * compatibility can be assured. */ + Tcl_FSVersion version; /* Version of the filesystem type. */ + Tcl_FSPathInFilesystemProc *pathInFilesystemProc; + /* Determines whether the pathname is in this + * filesystem. This is the most important + * filesystem function. */ + Tcl_FSDupInternalRepProc *dupInternalRepProc; + /* Duplicates the internal handle of the node. + * If it is NULL, the filesystem is less + * performant. */ + Tcl_FSFreeInternalRepProc *freeInternalRepProc; + /* Frees the internal handle of the node. NULL + * only if there is no need to free resources + * used for the internal handle. */ + Tcl_FSInternalToNormalizedProc *internalToNormalizedProc; + /* Converts the internal handle to a normalized + * path. NULL if the filesystem creates nodes + * having no pathname. */ + Tcl_FSCreateInternalRepProc *createInternalRepProc; + /* Creates an internal handle for a pathname. + * May be NULL if pathnames have no internal + * handle or if pathInFilesystemProc always + * immediately creates an internal + * representation for pathnames in the + * filesystem. */ + Tcl_FSNormalizePathProc *normalizePathProc; + /* Normalizes a path. Should be implemented if + * the filesystems supports multiple paths to + * the same node. */ + Tcl_FSFilesystemPathTypeProc *filesystemPathTypeProc; + /* Determines the type of a path in this + * filesystem. May be NULL. */ + Tcl_FSFilesystemSeparatorProc *filesystemSeparatorProc; + /* Produces the separator character(s) for this + * filesystem. Must not be NULL. */ + Tcl_FSStatProc *statProc; /* Called by 'Tcl_FSStat()'. Provided by any + * reasonable filesystem. */ + Tcl_FSAccessProc *accessProc; + /* Called by 'Tcl_FSAccess()'. Implemented by + * any reasonable filesystem. */ + Tcl_FSOpenFileChannelProc *openFileChannelProc; + /* Called by 'Tcl_FSOpenFileChannel()'. + * Provided by any reasonable filesystem. */ + Tcl_FSMatchInDirectoryProc *matchInDirectoryProc; + /* Called by 'Tcl_FSMatchInDirectory()'. NULL + * if the filesystem does not support glob or + * recursive copy. */ + Tcl_FSUtimeProc *utimeProc; /* Called by 'Tcl_FSUtime()', by 'file + * mtime' to set (not read) times, 'file + * atime', and the open-r/open-w/fcopy variant + * of 'file copy'. */ + Tcl_FSLinkProc *linkProc; /* Called by 'Tcl_FSLink()'. NULL if reading or + * creating links is not supported. */ + Tcl_FSListVolumesProc *listVolumesProc; + /* Lists filesystem volumes added by this + * filesystem. NULL if the filesystem does not + * use volumes. */ + Tcl_FSFileAttrStringsProc *fileAttrStringsProc; + /* List all valid attributes strings. NULL if + * the filesystem does not support the 'file + * attributes' command. Can be used to attach + * arbitrary additional data to files in a + * filesystem. */ + Tcl_FSFileAttrsGetProc *fileAttrsGetProc; + /* Called by 'Tcl_FSFileAttrsGet()' and by + * 'file attributes'. */ + Tcl_FSFileAttrsSetProc *fileAttrsSetProc; + /* Called by 'Tcl_FSFileAttrsSet()' and by + * 'file attributes'. */ + Tcl_FSCreateDirectoryProc *createDirectoryProc; + /* Called by 'Tcl_FSCreateDirectory()'. May be + * NULL if the filesystem is read-only. */ + Tcl_FSRemoveDirectoryProc *removeDirectoryProc; + /* Called by 'Tcl_FSRemoveDirectory()'. May be + * NULL if the filesystem is read-only. */ + Tcl_FSDeleteFileProc *deleteFileProc; + /* Called by 'Tcl_FSDeleteFile()' May be NULL + * if the filesystem is is read-only. */ + Tcl_FSCopyFileProc *copyFileProc; + /* Called by 'Tcl_FSCopyFile()'. If NULL, for + * a copy operation at the script level (not + * C) Tcl uses open-r, open-w and fcopy. */ + Tcl_FSRenameFileProc *renameFileProc; + /* Called by 'Tcl_FSRenameFile()'. If NULL, for + * a rename operation at the script level (not + * C) Tcl performs a copy operation followed + * by a delete operation. */ + Tcl_FSCopyDirectoryProc *copyDirectoryProc; + /* Called by 'Tcl_FSCopyDirectory()'. If NULL, + * for a copy operation at the script level + * (not C) Tcl recursively creates directories + * and copies files. */ + Tcl_FSLstatProc *lstatProc; /* Called by 'Tcl_FSLstat()'. If NULL, Tcl + * attempts to use 'statProc' instead. */ + Tcl_FSLoadFileProc *loadFileProc; + /* Called by 'Tcl_FSLoadFile()'. If NULL, Tcl + * performs a copy to a temporary file in the + * native filesystem and then calls + * Tcl_FSLoadFile() on that temporary copy. */ + Tcl_FSGetCwdProc *getCwdProc; + /* Called by 'Tcl_FSGetCwd()'. Normally NULL. + * Usually only called once: If 'getcwd' is + * called before 'chdir' is ever called. */ + Tcl_FSChdirProc *chdirProc; /* Called by 'Tcl_FSChdir()'. For a virtual + * filesystem, chdirProc just returns zero + * (success) if the pathname is a valid + * directory, and some other value otherwise. + * For A real filesystem, chdirProc performs + * the correct action, e.g. calls the system + * 'chdir' function. If not implemented, then + * 'cd' and 'pwd' fail for a pathname in this + * filesystem. On success Tcl stores the + * pathname for use by GetCwd. If NULL, Tcl + * performs records the pathname as the new + * current directory if it passes a series of + * directory access checks. */ +} 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 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. */ + Tcl_Size size; /* Number of bytes in token. */ + Tcl_Size 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 an + * 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 preceded 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. + * TCL_TOKEN_EXPAND_WORD - This token is just like TCL_TOKEN_WORD except + * that it marks a word that began with the + * literal character prefix "{*}". This word is + * marked to be expanded - that is, broken into + * words after substitution is complete. + */ + +#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 +#define TCL_TOKEN_EXPAND_WORD 256 + +/* + * 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. */ + Tcl_Size 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. */ + Tcl_Size commandSize; /* Number of bytes in command, including first + * character of first word, up through the + * terminating newline, close bracket, or + * semicolon. */ + Tcl_Size 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. */ + Tcl_Size numTokens; /* Total number of tokens in command. */ + Tcl_Size tokensAvailable; /* Total number of tokens available at + * *tokenPtr. */ + int errorType; /* One of the parsing error types defined + * above. */ +#if TCL_MAJOR_VERSION > 8 + 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. */ +#endif + + /* + * The fields below are intended only for the private use of the parser. + * They should not be used by functions 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). */ +#if TCL_MAJOR_VERSION < 9 + int incomplete; +#endif + 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 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; + /* Function to convert from external encoding + * into UTF-8. */ + Tcl_EncodingConvertProc *fromUtfProc; + /* Function to convert from UTF-8 into + * external encoding. */ + Tcl_FreeProc *freeProc; + /* If non-NULL, function to call when this + * encoding is deleted. */ + void *clientData; /* Arbitrary value associated with encoding + * type. Passed to conversion functions. */ + Tcl_Size 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, 2, or 4. */ +} 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 function 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 - Not used any more. + * TCL_ENCODING_NO_TERMINATE - If set, Tcl_ExternalToUtf does not append a + * terminating NUL byte. Since it does not need + * an extra byte for a terminating NUL, it fills + * all dstLen bytes with encoded UTF-8 content if + * needed. If clear, a byte is reserved in the + * dst space for NUL termination, and a + * terminating NUL is appended. + * TCL_ENCODING_CHAR_LIMIT - If set and dstCharsPtr is not NULL, then + * Tcl_ExternalToUtf takes the initial value of + * *dstCharsPtr as a limit of the maximum number + * of chars to produce in the encoded UTF-8 + * content. Otherwise, the number of chars + * produced is controlled only by other limiting + * factors. + * TCL_ENCODING_PROFILE_* - Mutually exclusive encoding profile ids. Note + * these are bit masks. + * + * NOTE: THESE BIT DEFINITIONS SHOULD NOT OVERLAP WITH INTERNAL USE BITS + * DEFINED IN tclEncoding.c (ENCODING_INPUT et al). Be cognizant of this + * when adding bits. + */ + +#define TCL_ENCODING_START 0x01 +#define TCL_ENCODING_END 0x02 +#if TCL_MAJOR_VERSION > 8 +# define TCL_ENCODING_STOPONERROR 0x0 /* Not used any more */ +#else +# define TCL_ENCODING_STOPONERROR 0x04 +#endif +#define TCL_ENCODING_NO_TERMINATE 0x08 +#define TCL_ENCODING_CHAR_LIMIT 0x10 +/* Internal use bits, do not define bits in this space. See above comment */ +#define TCL_ENCODING_INTERNAL_USE_MASK 0xFF00 +/* + * Reserve top byte for profile values (disjoint, not a mask). In case of + * changes, ensure ENCODING_PROFILE_* macros in tclInt.h are modified if + * necessary. + */ +#define TCL_ENCODING_PROFILE_STRICT TCL_ENCODING_STOPONERROR +#define TCL_ENCODING_PROFILE_TCL8 0x01000000 +#define TCL_ENCODING_PROFILE_REPLACE 0x02000000 + +/* + * 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. + * TCL_CONVERT_UNKNOWN - The source string contained a character that + * could not be represented in the target + * encoding. + */ + +#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 are 3 and 4. If > 3, + * then Tcl_UniChar must be 4-bytes in size (UCS-4) (the default). If == 3, + * then Tcl_UniChar must be 2-bytes in size (UTF-16). Since Tcl 9.0, UCS-4 + * mode is the default and recommended mode. + */ + +#ifndef TCL_UTF_MAX +# if TCL_MAJOR_VERSION > 8 +# define TCL_UTF_MAX 4 +# else +# define TCL_UTF_MAX 3 +# endif +#endif + +/* + * This represents a Unicode character. Any changes to this should also be + * reflected in regcustom.h. + */ + +#if TCL_UTF_MAX == 4 + /* + * int isn't 100% accurate as it should be a strict 4-byte value + * (perhaps int32_t). ILP64/SILP64 systems may have troubles. The + * size of this value must be reflected correctly in regcustom.h. + */ +typedef int Tcl_UniChar; +#elif TCL_UTF_MAX == 3 && !defined(BUILD_tcl) +typedef unsigned short Tcl_UniChar; +#else +# error "This TCL_UTF_MAX value is not supported" +#endif + +/* + *---------------------------------------------------------------------------- + * TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to + * provide the system with the embedded configuration data. + */ + +typedef struct Tcl_Config { + const char *key; /* Configuration key to register. ASCII + * encoded, thus UTF-8. */ + const char *value; /* The value associated with the key. System + * encoding. */ +} Tcl_Config; + +/* + *---------------------------------------------------------------------------- + * Flags for TIP#143 limits, detailing which limits are active in an + * interpreter. Used for Tcl_{Add,Remove}LimitHandler type argument. + */ + +#define TCL_LIMIT_COMMANDS 0x01 +#define TCL_LIMIT_TIME 0x02 + +/* + * Structure containing information about a limit handler to be called when a + * command- or time-limit is exceeded by an interpreter. + */ + +typedef void (Tcl_LimitHandlerProc) (void *clientData, Tcl_Interp *interp); +#if TCL_MAJOR_VERSION > 8 +#define Tcl_LimitHandlerDeleteProc Tcl_FreeProc +#else +typedef void (Tcl_LimitHandlerDeleteProc) (void *clientData); +#endif + +#if 0 +/* + *---------------------------------------------------------------------------- + * We would like to provide an anonymous structure "mp_int" here, which is + * compatible with libtommath's "mp_int", but without duplicating anything + * from or including here. But the libtommath project + * didn't honor our request. See: + * + * That's why this part is commented out, and we are using (void *) in + * various API's in stead of the more correct (mp_int *). + */ + +#ifndef MP_INT_DECLARED +#define MP_INT_DECLARED +typedef struct mp_int mp_int; +#endif + +#endif + +/* + *---------------------------------------------------------------------------- + * Definitions needed for Tcl_ParseArgvObj routines. + * Based on tkArgv.c. + * Modifications from the original are copyright (c) Sam Bromley 2006 + */ + +typedef struct { + int type; /* Indicates the option type; see below. */ + const char *keyStr; /* The key string that flags the option in the + * argv array. */ + void *srcPtr; /* Value to be used in setting dst; usage + * depends on type.*/ + void *dstPtr; /* Address of value to be modified; usage + * depends on type.*/ + const char *helpStr; /* Documentation message describing this + * option. */ + void *clientData; /* Word to pass to function callbacks. */ +} Tcl_ArgvInfo; + +/* + * Legal values for the type field of a Tcl_ArgInfo: see the user + * documentation for details. + */ + +#define TCL_ARGV_CONSTANT 15 +#define TCL_ARGV_INT 16 +#define TCL_ARGV_STRING 17 +#define TCL_ARGV_REST 18 +#define TCL_ARGV_FLOAT 19 +#define TCL_ARGV_FUNC 20 +#define TCL_ARGV_GENFUNC 21 +#define TCL_ARGV_HELP 22 +#define TCL_ARGV_END 23 + +/* + * Types of callback functions for the TCL_ARGV_FUNC and TCL_ARGV_GENFUNC + * argument types: + */ + +typedef int (Tcl_ArgvFuncProc)(void *clientData, Tcl_Obj *objPtr, + void *dstPtr); +typedef int (Tcl_ArgvGenFuncProc)(void *clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv, void *dstPtr); + +/* + * Shorthand for commonly used argTable entries. + */ + +#define TCL_ARGV_AUTO_HELP \ + {TCL_ARGV_HELP, "-help", NULL, NULL, \ + "Print summary of command-line options and abort", NULL} +#define TCL_ARGV_AUTO_REST \ + {TCL_ARGV_REST, "--", NULL, NULL, \ + "Marks the end of the options", NULL} +#define TCL_ARGV_TABLE_END \ + {TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL} + +/* + *---------------------------------------------------------------------------- + * Definitions needed for Tcl_Zlib routines. [TIP #234] + * + * Constants for the format flags describing what sort of data format is + * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and + * Tcl_ZlibStreamInit functions. + */ + +#define TCL_ZLIB_FORMAT_RAW 1 +#define TCL_ZLIB_FORMAT_ZLIB 2 +#define TCL_ZLIB_FORMAT_GZIP 4 +#define TCL_ZLIB_FORMAT_AUTO 8 + +/* + * Constants that describe whether the stream is to operate in compressing or + * decompressing mode. + */ + +#define TCL_ZLIB_STREAM_DEFLATE 16 +#define TCL_ZLIB_STREAM_INFLATE 32 + +/* + * Constants giving compression levels. Use of TCL_ZLIB_COMPRESS_DEFAULT is + * recommended. + */ + +#define TCL_ZLIB_COMPRESS_NONE 0 +#define TCL_ZLIB_COMPRESS_FAST 1 +#define TCL_ZLIB_COMPRESS_BEST 9 +#define TCL_ZLIB_COMPRESS_DEFAULT (-1) + +/* + * Constants for types of flushing, used with Tcl_ZlibFlush. + */ + +#define TCL_ZLIB_NO_FLUSH 0 +#define TCL_ZLIB_FLUSH 2 +#define TCL_ZLIB_FULLFLUSH 3 +#define TCL_ZLIB_FINALIZE 4 + +/* + *---------------------------------------------------------------------------- + * Definitions needed for the Tcl_LoadFile function. [TIP #416] + */ + +#define TCL_LOAD_GLOBAL 1 +#define TCL_LOAD_LAZY 2 + +/* + *---------------------------------------------------------------------------- + * Definitions needed for the Tcl_OpenTcpServerEx function. [TIP #456] + */ +#define TCL_TCPSERVER_REUSEADDR (1<<0) +#define TCL_TCPSERVER_REUSEPORT (1<<1) + +/* + * Constants for special Tcl_Size-typed values, see TIP #494 + */ + +#define TCL_IO_FAILURE ((Tcl_Size)-1) +#define TCL_AUTO_LENGTH ((Tcl_Size)-1) +#define TCL_INDEX_NONE ((Tcl_Size)-1) + +/* + *---------------------------------------------------------------------------- + * Single public declaration for NRE. + */ + +typedef int (Tcl_NRPostProc) (void *data[], Tcl_Interp *interp, + int result); + +/* + *---------------------------------------------------------------------------- + * The following constant is used to test for older versions of Tcl in the + * stubs tables. + */ + +#if TCL_MAJOR_VERSION > 8 +# define TCL_STUB_MAGIC ((int) 0xFCA3BACB + (int) sizeof(void *)) +#else +# define TCL_STUB_MAGIC ((int) 0xFCA3BACF) +#endif + +/* + * 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. + */ + +const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version, + int exact, int magic); +const char * TclTomMathInitializeStubs(Tcl_Interp *interp, + const char *version, int epoch, int revision); +const char * TclInitStubTable(const char *version); +void * TclStubCall(void *arg); +#if defined(_WIN32) + TCL_NORETURN1 void Tcl_ConsolePanic(const char *format, ...); +#else +# define Tcl_ConsolePanic NULL +#endif + +#ifdef USE_TCL_STUBS +#if TCL_MAJOR_VERSION < 9 +# if TCL_UTF_MAX < 4 +# define Tcl_InitStubs(interp, version, exact) \ + (Tcl_InitStubs)(interp, version, \ + (exact)|(TCL_MAJOR_VERSION<<8)|(0xFF<<16), \ + TCL_STUB_MAGIC) +# else +# define Tcl_InitStubs(interp, version, exact) \ + (Tcl_InitStubs)(interp, "8.7.0", \ + (exact)|(TCL_MAJOR_VERSION<<8)|(0xFF<<16), \ + TCL_STUB_MAGIC) +# endif +#elif TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE +# define Tcl_InitStubs(interp, version, exact) \ + (Tcl_InitStubs)(interp, version, \ + (exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), \ + TCL_STUB_MAGIC) +#else +# define Tcl_InitStubs(interp, version, exact) \ + (Tcl_InitStubs)(interp, TCL_PATCH_LEVEL, \ + 1|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), \ + TCL_STUB_MAGIC) +#endif +#else +#if TCL_MAJOR_VERSION < 9 +# error "Please define -DUSE_TCL_STUBS" +#elif TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE +# define Tcl_InitStubs(interp, version, exact) \ + Tcl_PkgInitStubsCheck(interp, version, \ + (exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16)) +#else +# define Tcl_InitStubs(interp, version, exact) \ + Tcl_PkgInitStubsCheck(interp, TCL_PATCH_LEVEL, \ + 1|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16)) +#endif +#endif + +/* + * Public functions that are not accessible via the stubs table. + * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171] + */ + +#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ + ((Tcl_SetPanicProc(Tcl_ConsolePanic), Tcl_CreateInterp()))) +EXTERN TCL_NORETURN void Tcl_MainEx(Tcl_Size argc, char **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, + const char *version, int exact); +EXTERN const char * Tcl_InitSubsystems(void); +EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); +EXTERN const char * Tcl_FindExecutable(const char *argv0); +EXTERN const char * Tcl_SetPreInitScript(const char *string); +EXTERN const char * Tcl_SetPanicProc( + TCL_NORETURN1 Tcl_PanicProc *panicProc); +EXTERN void Tcl_StaticLibrary(Tcl_Interp *interp, + const char *prefix, + Tcl_LibraryInitProc *initProc, + Tcl_LibraryInitProc *safeInitProc); +#ifndef TCL_NO_DEPRECATED +# define Tcl_StaticPackage Tcl_StaticLibrary +#endif +EXTERN Tcl_ExitProc *Tcl_SetExitProc(TCL_NORETURN1 Tcl_ExitProc *proc); +#ifdef _WIN32 +EXTERN const char *TclZipfs_AppHook(int *argc, wchar_t ***argv); +#else +EXTERN const char *TclZipfs_AppHook(int *argc, char ***argv); +#endif +#if defined(_WIN32) && defined(UNICODE) +#ifndef USE_TCL_STUBS +# define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg))) +#endif +# define Tcl_MainEx Tcl_MainExW + EXTERN TCL_NORETURN void Tcl_MainExW(Tcl_Size argc, wchar_t **argv, + Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); +#endif +#if defined(USE_TCL_STUBS) && (TCL_MAJOR_VERSION > 8) +#define Tcl_SetPanicProc(panicProc) \ + TclInitStubTable(((const char *(*)(Tcl_PanicProc *))TclStubCall((void *)panicProc))(panicProc)) +#define Tcl_InitSubsystems() \ + TclInitStubTable(((const char *(*)(void))TclStubCall((void *)1))()) +#define Tcl_FindExecutable(argv0) \ + TclInitStubTable(((const char *(*)(const char *))TclStubCall((void *)2))(argv0)) +#define TclZipfs_AppHook(argcp, argvp) \ + TclInitStubTable(((const char *(*)(int *, void *))TclStubCall((void *)3))(argcp, argvp)) +#define Tcl_MainExW(argc, argv, appInitProc, interp) \ + (void)((const char *(*)(Tcl_Size, const void *, Tcl_AppInitProc *, Tcl_Interp *)) \ + TclStubCall((void *)4))(argc, argv, appInitProc, interp) +#if !defined(_WIN32) || !defined(UNICODE) +#define Tcl_MainEx(argc, argv, appInitProc, interp) \ + (void)((const char *(*)(Tcl_Size, const void *, Tcl_AppInitProc *, Tcl_Interp *)) \ + TclStubCall((void *)5))(argc, argv, appInitProc, interp) +#endif +#define Tcl_StaticLibrary(interp, pkgName, initProc, safeInitProc) \ + (void)((const char *(*)(Tcl_Interp *, const char *, Tcl_LibraryInitProc *, Tcl_LibraryInitProc *)) \ + TclStubCall((void *)6))(interp, pkgName, initProc, safeInitProc) +#define Tcl_SetExitProc(proc) \ + ((Tcl_ExitProc *(*)(Tcl_ExitProc *))TclStubCall((void *)7))(proc) +#define Tcl_GetMemoryInfo(dsPtr) \ + (void)((const char *(*)(Tcl_DString *))TclStubCall((void *)8))(dsPtr) +#define Tcl_SetPreInitScript(string) \ + ((const char *(*)(const char *))TclStubCall((void *)9))(string) +#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. Make all TclOO symbols MODULE_SCOPE (which only + * has effect on building it as a shared library). See ticket [3010352]. + */ + +#if defined(BUILD_tcl) +# undef TCLAPI +# define TCLAPI MODULE_SCOPE +#endif + +#include "tclPlatDecls.h" + +/* + *---------------------------------------------------------------------------- + * The following declarations map ckalloc and ckfree to Tcl_Alloc and + * Tcl_Free for use in Tcl-8.x-compatible extensions. + */ + +#ifndef BUILD_tcl +# define ckalloc Tcl_Alloc +# define attemptckalloc Tcl_AttemptAlloc +# ifdef _MSC_VER + /* Silence invalid C4090 warnings */ +# define ckfree(a) Tcl_Free((void *)(a)) +# define ckrealloc(a,b) Tcl_Realloc((void *)(a),(b)) +# define attemptckrealloc(a,b) Tcl_AttemptRealloc((void *)(a),(b)) +# else +# define ckfree Tcl_Free +# define ckrealloc Tcl_Realloc +# define attemptckrealloc Tcl_AttemptRealloc +# endif +#endif + +#ifndef 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. + */ + +# undef Tcl_InitMemory +# define Tcl_InitMemory(x) +# undef Tcl_DumpActiveMemory +# define Tcl_DumpActiveMemory(x) +# undef Tcl_ValidateAllMemory +# define Tcl_ValidateAllMemory(x,y) + +#endif /* !TCL_MEM_DEBUG */ + +#ifdef TCL_MEM_DEBUG +# undef Tcl_IncrRefCount +# define Tcl_IncrRefCount(objPtr) \ + Tcl_DbIncrRefCount(objPtr, __FILE__, __LINE__) +# undef Tcl_DecrRefCount +# define Tcl_DecrRefCount(objPtr) \ + Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__) +# undef Tcl_IsShared +# define Tcl_IsShared(objPtr) \ + Tcl_DbIsShared(objPtr, __FILE__, __LINE__) +/* + * Free the Obj by effectively doing: + * + * Tcl_IncrRefCount(objPtr); + * Tcl_DecrRefCount(objPtr); + * + * This will free the obj if there are no references to the obj. + */ +# define Tcl_BounceRefCount(objPtr) \ + TclBounceRefCount(objPtr, __FILE__, __LINE__) + +static inline void TclBounceRefCount(Tcl_Obj* objPtr, const char* fn, int line) +{ + if (objPtr) { + if ((objPtr)->refCount == 0) { + Tcl_DbDecrRefCount(objPtr, fn, line); + } + } +} +#else +# undef Tcl_IncrRefCount +# define Tcl_IncrRefCount(objPtr) \ + ((void)++(objPtr)->refCount) + /* + * Use do/while0 idiom for optimum correctness without compiler warnings. + * https://wiki.c2.com/?TrivialDoWhileLoop + */ +# undef Tcl_DecrRefCount +# define Tcl_DecrRefCount(objPtr) \ + do { \ + Tcl_Obj *_objPtr = (objPtr); \ + if (_objPtr->refCount-- <= 1) { \ + TclFreeObj(_objPtr); \ + } \ + } while(0) +# undef Tcl_IsShared +# define Tcl_IsShared(objPtr) \ + ((objPtr)->refCount > 1) + +/* + * Declare that obj will no longer be used or referenced. + * This will release the obj if there is no referece count, + * otherwise let it be. + */ +# define Tcl_BounceRefCount(objPtr) \ + TclBounceRefCount(objPtr); + +static inline void TclBounceRefCount(Tcl_Obj* objPtr) +{ + if (objPtr) { + if ((objPtr)->refCount == 0) { + Tcl_DecrRefCount(objPtr); + } + } +} + +#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 functions. + */ + +#ifdef TCL_MEM_DEBUG +# undef Tcl_NewBignumObj +# define Tcl_NewBignumObj(val) \ + Tcl_DbNewBignumObj(val, __FILE__, __LINE__) +# undef Tcl_NewBooleanObj +# define Tcl_NewBooleanObj(val) \ + Tcl_DbNewWideIntObj((val)!=0, __FILE__, __LINE__) +# undef Tcl_NewByteArrayObj +# define Tcl_NewByteArrayObj(bytes, len) \ + Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__) +# undef Tcl_NewDoubleObj +# define Tcl_NewDoubleObj(val) \ + Tcl_DbNewDoubleObj(val, __FILE__, __LINE__) +# undef Tcl_NewListObj +# define Tcl_NewListObj(objc, objv) \ + Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__) +# undef Tcl_NewObj +# define Tcl_NewObj() \ + Tcl_DbNewObj(__FILE__, __LINE__) +# undef Tcl_NewStringObj +# define Tcl_NewStringObj(bytes, len) \ + Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__) +# undef Tcl_NewWideIntObj +# define Tcl_NewWideIntObj(val) \ + Tcl_DbNewWideIntObj(val, __FILE__, __LINE__) +#endif /* TCL_MEM_DEBUG */ + +/* + *---------------------------------------------------------------------------- + * Macros for clients to use to access fields of hash entries: + */ + +#define Tcl_GetHashValue(h) ((h)->clientData) +#define Tcl_SetHashValue(h, value) ((h)->clientData = (void *)(value)) +#define Tcl_GetHashKey(tablePtr, h) \ + ((void *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \ + (tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \ + ? (h)->key.oneWordValue \ + : (h)->key.string)) + +/* + * Macros to use for clients to use to invoke find and create functions for + * hash tables: + */ + +#undef Tcl_FindHashEntry +#define Tcl_FindHashEntry(tablePtr, key) \ + (*((tablePtr)->findProc))(tablePtr, (const char *)(key)) +#undef Tcl_CreateHashEntry +#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ + (*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr) + +#endif /* RC_INVOKED */ + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TCL */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tclDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tclDecls.h new file mode 100644 index 00000000..13d82a03 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tclDecls.h @@ -0,0 +1,4301 @@ +/* + * 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 + +#include /* for size_t */ + +#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 + +#if !defined(BUILD_tcl) +# define TCL_DEPRECATED(msg) EXTERN TCL_DEPRECATED_API(msg) +#elif defined(TCL_NO_DEPRECATED) +# define TCL_DEPRECATED(msg) MODULE_SCOPE +#else +# define TCL_DEPRECATED(msg) EXTERN +#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/tcl.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +/* 0 */ +EXTERN int Tcl_PkgProvideEx(Tcl_Interp *interp, + const char *name, const char *version, + const void *clientData); +/* 1 */ +EXTERN const char * Tcl_PkgRequireEx(Tcl_Interp *interp, + const char *name, const char *version, + int exact, void *clientDataPtr); +/* 2 */ +EXTERN TCL_NORETURN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); +/* 3 */ +EXTERN void * Tcl_Alloc(TCL_HASH_TYPE size); +/* 4 */ +EXTERN void Tcl_Free(void *ptr); +/* 5 */ +EXTERN void * Tcl_Realloc(void *ptr, TCL_HASH_TYPE size); +/* 6 */ +EXTERN void * Tcl_DbCkalloc(TCL_HASH_TYPE size, const char *file, + int line); +/* 7 */ +EXTERN void Tcl_DbCkfree(void *ptr, const char *file, int line); +/* 8 */ +EXTERN void * Tcl_DbCkrealloc(void *ptr, TCL_HASH_TYPE size, + const char *file, int line); +/* 9 */ +EXTERN void Tcl_CreateFileHandler(int fd, int mask, + Tcl_FileProc *proc, void *clientData); +/* 10 */ +EXTERN void Tcl_DeleteFileHandler(int fd); +/* 11 */ +EXTERN void Tcl_SetTimer(const Tcl_Time *timePtr); +/* 12 */ +EXTERN void Tcl_Sleep(int ms); +/* 13 */ +EXTERN int Tcl_WaitForEvent(const Tcl_Time *timePtr); +/* 14 */ +EXTERN int Tcl_AppendAllObjTypes(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 15 */ +EXTERN void Tcl_AppendStringsToObj(Tcl_Obj *objPtr, ...); +/* 16 */ +EXTERN void Tcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes, + Tcl_Size length); +/* 17 */ +EXTERN Tcl_Obj * Tcl_ConcatObj(Tcl_Size objc, Tcl_Obj *const objv[]); +/* 18 */ +EXTERN int Tcl_ConvertToType(Tcl_Interp *interp, + Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); +/* 19 */ +EXTERN void Tcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file, + int line); +/* 20 */ +EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file, + int line); +/* 21 */ +EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, + int line); +/* Slot 22 is reserved */ +/* 23 */ +EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes, + Tcl_Size numBytes, const char *file, + int line); +/* 24 */ +EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue, + const char *file, int line); +/* 25 */ +EXTERN Tcl_Obj * Tcl_DbNewListObj(Tcl_Size objc, Tcl_Obj *const *objv, + const char *file, int line); +/* Slot 26 is reserved */ +/* 27 */ +EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line); +/* 28 */ +EXTERN Tcl_Obj * Tcl_DbNewStringObj(const char *bytes, + Tcl_Size length, const char *file, int line); +/* 29 */ +EXTERN Tcl_Obj * Tcl_DuplicateObj(Tcl_Obj *objPtr); +/* 30 */ +EXTERN void TclFreeObj(Tcl_Obj *objPtr); +/* 31 */ +EXTERN int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, + int *intPtr); +/* 32 */ +EXTERN int Tcl_GetBooleanFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *intPtr); +/* 33 */ +EXTERN unsigned char * Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, + Tcl_Size *numBytesPtr); +/* 34 */ +EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src, + double *doublePtr); +/* 35 */ +EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, double *doublePtr); +/* Slot 36 is reserved */ +/* 37 */ +EXTERN int Tcl_GetInt(Tcl_Interp *interp, const char *src, + int *intPtr); +/* 38 */ +EXTERN int Tcl_GetIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *intPtr); +/* 39 */ +EXTERN int Tcl_GetLongFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, long *longPtr); +/* 40 */ +EXTERN const Tcl_ObjType * Tcl_GetObjType(const char *typeName); +/* 41 */ +EXTERN char * TclGetStringFromObj(Tcl_Obj *objPtr, void *lengthPtr); +/* 42 */ +EXTERN void Tcl_InvalidateStringRep(Tcl_Obj *objPtr); +/* 43 */ +EXTERN int Tcl_ListObjAppendList(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); +/* 44 */ +EXTERN int Tcl_ListObjAppendElement(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Obj *objPtr); +/* 45 */ +EXTERN int TclListObjGetElements(Tcl_Interp *interp, + Tcl_Obj *listPtr, void *objcPtr, + Tcl_Obj ***objvPtr); +/* 46 */ +EXTERN int Tcl_ListObjIndex(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Size index, + Tcl_Obj **objPtrPtr); +/* 47 */ +EXTERN int TclListObjLength(Tcl_Interp *interp, + Tcl_Obj *listPtr, void *lengthPtr); +/* 48 */ +EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Size first, + Tcl_Size count, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* Slot 49 is reserved */ +/* 50 */ +EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes, + Tcl_Size numBytes); +/* 51 */ +EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue); +/* Slot 52 is reserved */ +/* 53 */ +EXTERN Tcl_Obj * Tcl_NewListObj(Tcl_Size objc, Tcl_Obj *const objv[]); +/* Slot 54 is reserved */ +/* 55 */ +EXTERN Tcl_Obj * Tcl_NewObj(void); +/* 56 */ +EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, Tcl_Size length); +/* Slot 57 is reserved */ +/* 58 */ +EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, + Tcl_Size numBytes); +/* 59 */ +EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr, + const unsigned char *bytes, + Tcl_Size numBytes); +/* 60 */ +EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue); +/* Slot 61 is reserved */ +/* 62 */ +EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* Slot 63 is reserved */ +/* 64 */ +EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, Tcl_Size length); +/* 65 */ +EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, + Tcl_Size length); +/* Slot 66 is reserved */ +/* Slot 67 is reserved */ +/* 68 */ +EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp); +/* 69 */ +EXTERN void Tcl_AppendElement(Tcl_Interp *interp, + const char *element); +/* 70 */ +EXTERN void Tcl_AppendResult(Tcl_Interp *interp, ...); +/* 71 */ +EXTERN Tcl_AsyncHandler Tcl_AsyncCreate(Tcl_AsyncProc *proc, + void *clientData); +/* 72 */ +EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async); +/* 73 */ +EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code); +/* 74 */ +EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async); +/* 75 */ +EXTERN int Tcl_AsyncReady(void); +/* Slot 76 is reserved */ +/* Slot 77 is reserved */ +/* 78 */ +EXTERN int Tcl_BadChannelOption(Tcl_Interp *interp, + const char *optionName, + const char *optionList); +/* 79 */ +EXTERN void Tcl_CallWhenDeleted(Tcl_Interp *interp, + Tcl_InterpDeleteProc *proc, void *clientData); +/* 80 */ +EXTERN void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, + void *clientData); +/* 81 */ +EXTERN int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan); +/* 82 */ +EXTERN int Tcl_CommandComplete(const char *cmd); +/* 83 */ +EXTERN char * Tcl_Concat(Tcl_Size argc, const char *const *argv); +/* 84 */ +EXTERN Tcl_Size Tcl_ConvertElement(const char *src, char *dst, + int flags); +/* 85 */ +EXTERN Tcl_Size Tcl_ConvertCountedElement(const char *src, + Tcl_Size length, char *dst, int flags); +/* 86 */ +EXTERN int Tcl_CreateAlias(Tcl_Interp *childInterp, + const char *childCmd, Tcl_Interp *target, + const char *targetCmd, Tcl_Size argc, + const char *const *argv); +/* 87 */ +EXTERN int Tcl_CreateAliasObj(Tcl_Interp *childInterp, + const char *childCmd, Tcl_Interp *target, + const char *targetCmd, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* 88 */ +EXTERN Tcl_Channel Tcl_CreateChannel(const Tcl_ChannelType *typePtr, + const char *chanName, void *instanceData, + int mask); +/* 89 */ +EXTERN void Tcl_CreateChannelHandler(Tcl_Channel chan, int mask, + Tcl_ChannelProc *proc, void *clientData); +/* 90 */ +EXTERN void Tcl_CreateCloseHandler(Tcl_Channel chan, + Tcl_CloseProc *proc, void *clientData); +/* 91 */ +EXTERN Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdProc *proc, + void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 92 */ +EXTERN void Tcl_CreateEventSource(Tcl_EventSetupProc *setupProc, + Tcl_EventCheckProc *checkProc, + void *clientData); +/* 93 */ +EXTERN void Tcl_CreateExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 94 */ +EXTERN Tcl_Interp * Tcl_CreateInterp(void); +/* Slot 95 is reserved */ +/* 96 */ +EXTERN Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc *proc, + void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 97 */ +EXTERN Tcl_Interp * Tcl_CreateChild(Tcl_Interp *interp, const char *name, + int isSafe); +/* 98 */ +EXTERN Tcl_TimerToken Tcl_CreateTimerHandler(int milliseconds, + Tcl_TimerProc *proc, void *clientData); +/* 99 */ +EXTERN Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, Tcl_Size level, + Tcl_CmdTraceProc *proc, void *clientData); +/* 100 */ +EXTERN void Tcl_DeleteAssocData(Tcl_Interp *interp, + const char *name); +/* 101 */ +EXTERN void Tcl_DeleteChannelHandler(Tcl_Channel chan, + Tcl_ChannelProc *proc, void *clientData); +/* 102 */ +EXTERN void Tcl_DeleteCloseHandler(Tcl_Channel chan, + Tcl_CloseProc *proc, void *clientData); +/* 103 */ +EXTERN int Tcl_DeleteCommand(Tcl_Interp *interp, + const char *cmdName); +/* 104 */ +EXTERN int Tcl_DeleteCommandFromToken(Tcl_Interp *interp, + Tcl_Command command); +/* 105 */ +EXTERN void Tcl_DeleteEvents(Tcl_EventDeleteProc *proc, + void *clientData); +/* 106 */ +EXTERN void Tcl_DeleteEventSource(Tcl_EventSetupProc *setupProc, + Tcl_EventCheckProc *checkProc, + void *clientData); +/* 107 */ +EXTERN void Tcl_DeleteExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 108 */ +EXTERN void Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr); +/* 109 */ +EXTERN void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr); +/* 110 */ +EXTERN void Tcl_DeleteInterp(Tcl_Interp *interp); +/* 111 */ +EXTERN void Tcl_DetachPids(Tcl_Size numPids, Tcl_Pid *pidPtr); +/* 112 */ +EXTERN void Tcl_DeleteTimerHandler(Tcl_TimerToken token); +/* 113 */ +EXTERN void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace); +/* 114 */ +EXTERN void Tcl_DontCallWhenDeleted(Tcl_Interp *interp, + Tcl_InterpDeleteProc *proc, void *clientData); +/* 115 */ +EXTERN int Tcl_DoOneEvent(int flags); +/* 116 */ +EXTERN void Tcl_DoWhenIdle(Tcl_IdleProc *proc, void *clientData); +/* 117 */ +EXTERN char * Tcl_DStringAppend(Tcl_DString *dsPtr, + const char *bytes, Tcl_Size length); +/* 118 */ +EXTERN char * Tcl_DStringAppendElement(Tcl_DString *dsPtr, + const char *element); +/* 119 */ +EXTERN void Tcl_DStringEndSublist(Tcl_DString *dsPtr); +/* 120 */ +EXTERN void Tcl_DStringFree(Tcl_DString *dsPtr); +/* 121 */ +EXTERN void Tcl_DStringGetResult(Tcl_Interp *interp, + Tcl_DString *dsPtr); +/* 122 */ +EXTERN void Tcl_DStringInit(Tcl_DString *dsPtr); +/* 123 */ +EXTERN void Tcl_DStringResult(Tcl_Interp *interp, + Tcl_DString *dsPtr); +/* 124 */ +EXTERN void Tcl_DStringSetLength(Tcl_DString *dsPtr, + Tcl_Size length); +/* 125 */ +EXTERN void Tcl_DStringStartSublist(Tcl_DString *dsPtr); +/* 126 */ +EXTERN int Tcl_Eof(Tcl_Channel chan); +/* 127 */ +EXTERN const char * Tcl_ErrnoId(void); +/* 128 */ +EXTERN const char * Tcl_ErrnoMsg(int err); +/* Slot 129 is reserved */ +/* 130 */ +EXTERN int Tcl_EvalFile(Tcl_Interp *interp, + const char *fileName); +/* Slot 131 is reserved */ +/* 132 */ +EXTERN void Tcl_EventuallyFree(void *clientData, + Tcl_FreeProc *freeProc); +/* 133 */ +EXTERN TCL_NORETURN void Tcl_Exit(int status); +/* 134 */ +EXTERN int Tcl_ExposeCommand(Tcl_Interp *interp, + const char *hiddenCmdToken, + const char *cmdName); +/* 135 */ +EXTERN int Tcl_ExprBoolean(Tcl_Interp *interp, const char *expr, + int *ptr); +/* 136 */ +EXTERN int Tcl_ExprBooleanObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int *ptr); +/* 137 */ +EXTERN int Tcl_ExprDouble(Tcl_Interp *interp, const char *expr, + double *ptr); +/* 138 */ +EXTERN int Tcl_ExprDoubleObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, double *ptr); +/* 139 */ +EXTERN int Tcl_ExprLong(Tcl_Interp *interp, const char *expr, + long *ptr); +/* 140 */ +EXTERN int Tcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + long *ptr); +/* 141 */ +EXTERN int Tcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + Tcl_Obj **resultPtrPtr); +/* 142 */ +EXTERN int Tcl_ExprString(Tcl_Interp *interp, const char *expr); +/* 143 */ +EXTERN void Tcl_Finalize(void); +/* Slot 144 is reserved */ +/* 145 */ +EXTERN Tcl_HashEntry * Tcl_FirstHashEntry(Tcl_HashTable *tablePtr, + Tcl_HashSearch *searchPtr); +/* 146 */ +EXTERN int Tcl_Flush(Tcl_Channel chan); +/* Slot 147 is reserved */ +/* 148 */ +EXTERN int Tcl_GetAlias(Tcl_Interp *interp, + const char *childCmd, + Tcl_Interp **targetInterpPtr, + const char **targetCmdPtr, int *argcPtr, + const char ***argvPtr); +/* 149 */ +EXTERN int Tcl_GetAliasObj(Tcl_Interp *interp, + const char *childCmd, + Tcl_Interp **targetInterpPtr, + const char **targetCmdPtr, int *objcPtr, + Tcl_Obj ***objv); +/* 150 */ +EXTERN void * Tcl_GetAssocData(Tcl_Interp *interp, + const char *name, + Tcl_InterpDeleteProc **procPtr); +/* 151 */ +EXTERN Tcl_Channel Tcl_GetChannel(Tcl_Interp *interp, + const char *chanName, int *modePtr); +/* 152 */ +EXTERN Tcl_Size Tcl_GetChannelBufferSize(Tcl_Channel chan); +/* 153 */ +EXTERN int Tcl_GetChannelHandle(Tcl_Channel chan, int direction, + void **handlePtr); +/* 154 */ +EXTERN void * Tcl_GetChannelInstanceData(Tcl_Channel chan); +/* 155 */ +EXTERN int Tcl_GetChannelMode(Tcl_Channel chan); +/* 156 */ +EXTERN const char * Tcl_GetChannelName(Tcl_Channel chan); +/* 157 */ +EXTERN int Tcl_GetChannelOption(Tcl_Interp *interp, + Tcl_Channel chan, const char *optionName, + Tcl_DString *dsPtr); +/* 158 */ +EXTERN const Tcl_ChannelType * Tcl_GetChannelType(Tcl_Channel chan); +/* 159 */ +EXTERN int Tcl_GetCommandInfo(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdInfo *infoPtr); +/* 160 */ +EXTERN const char * Tcl_GetCommandName(Tcl_Interp *interp, + Tcl_Command command); +/* 161 */ +EXTERN int Tcl_GetErrno(void); +/* 162 */ +EXTERN const char * Tcl_GetHostName(void); +/* 163 */ +EXTERN int Tcl_GetInterpPath(Tcl_Interp *interp, + Tcl_Interp *childInterp); +/* 164 */ +EXTERN Tcl_Interp * Tcl_GetParent(Tcl_Interp *interp); +/* 165 */ +EXTERN const char * Tcl_GetNameOfExecutable(void); +/* 166 */ +EXTERN Tcl_Obj * Tcl_GetObjResult(Tcl_Interp *interp); +/* 167 */ +EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, + const char *chanID, int forWriting, + int checkUsage, void **filePtr); +/* 168 */ +EXTERN Tcl_PathType Tcl_GetPathType(const char *path); +/* 169 */ +EXTERN Tcl_Size Tcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr); +/* 170 */ +EXTERN Tcl_Size Tcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr); +/* 171 */ +EXTERN int Tcl_GetServiceMode(void); +/* 172 */ +EXTERN Tcl_Interp * Tcl_GetChild(Tcl_Interp *interp, const char *name); +/* 173 */ +EXTERN Tcl_Channel Tcl_GetStdChannel(int type); +/* Slot 174 is reserved */ +/* Slot 175 is reserved */ +/* 176 */ +EXTERN const char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* Slot 177 is reserved */ +/* Slot 178 is reserved */ +/* 179 */ +EXTERN int Tcl_HideCommand(Tcl_Interp *interp, + const char *cmdName, + const char *hiddenCmdToken); +/* 180 */ +EXTERN int Tcl_Init(Tcl_Interp *interp); +/* 181 */ +EXTERN void Tcl_InitHashTable(Tcl_HashTable *tablePtr, + int keyType); +/* 182 */ +EXTERN int Tcl_InputBlocked(Tcl_Channel chan); +/* 183 */ +EXTERN int Tcl_InputBuffered(Tcl_Channel chan); +/* 184 */ +EXTERN int Tcl_InterpDeleted(Tcl_Interp *interp); +/* 185 */ +EXTERN int Tcl_IsSafe(Tcl_Interp *interp); +/* 186 */ +EXTERN char * Tcl_JoinPath(Tcl_Size argc, const char *const *argv, + Tcl_DString *resultPtr); +/* 187 */ +EXTERN int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, + void *addr, int type); +/* Slot 188 is reserved */ +/* 189 */ +EXTERN Tcl_Channel Tcl_MakeFileChannel(void *handle, int mode); +/* Slot 190 is reserved */ +/* 191 */ +EXTERN Tcl_Channel Tcl_MakeTcpClientChannel(void *tcpSocket); +/* 192 */ +EXTERN char * Tcl_Merge(Tcl_Size argc, const char *const *argv); +/* 193 */ +EXTERN Tcl_HashEntry * Tcl_NextHashEntry(Tcl_HashSearch *searchPtr); +/* 194 */ +EXTERN void Tcl_NotifyChannel(Tcl_Channel channel, int mask); +/* 195 */ +EXTERN Tcl_Obj * Tcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, + Tcl_Obj *part2Ptr, int flags); +/* 196 */ +EXTERN Tcl_Obj * Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, + Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, + int flags); +/* 197 */ +EXTERN Tcl_Channel Tcl_OpenCommandChannel(Tcl_Interp *interp, + Tcl_Size argc, const char **argv, int flags); +/* 198 */ +EXTERN Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp, + const char *fileName, const char *modeString, + int permissions); +/* 199 */ +EXTERN Tcl_Channel Tcl_OpenTcpClient(Tcl_Interp *interp, int port, + const char *address, const char *myaddr, + int myport, int flags); +/* 200 */ +EXTERN Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port, + const char *host, + Tcl_TcpAcceptProc *acceptProc, + void *callbackData); +/* 201 */ +EXTERN void Tcl_Preserve(void *data); +/* 202 */ +EXTERN void Tcl_PrintDouble(Tcl_Interp *interp, double value, + char *dst); +/* 203 */ +EXTERN int Tcl_PutEnv(const char *assignment); +/* 204 */ +EXTERN const char * Tcl_PosixError(Tcl_Interp *interp); +/* 205 */ +EXTERN void Tcl_QueueEvent(Tcl_Event *evPtr, int position); +/* 206 */ +EXTERN Tcl_Size Tcl_Read(Tcl_Channel chan, char *bufPtr, + Tcl_Size toRead); +/* 207 */ +EXTERN void Tcl_ReapDetachedProcs(void); +/* 208 */ +EXTERN int Tcl_RecordAndEval(Tcl_Interp *interp, + const char *cmd, int flags); +/* 209 */ +EXTERN int Tcl_RecordAndEvalObj(Tcl_Interp *interp, + Tcl_Obj *cmdPtr, int flags); +/* 210 */ +EXTERN void Tcl_RegisterChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 211 */ +EXTERN void Tcl_RegisterObjType(const Tcl_ObjType *typePtr); +/* 212 */ +EXTERN Tcl_RegExp Tcl_RegExpCompile(Tcl_Interp *interp, + const char *pattern); +/* 213 */ +EXTERN int Tcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp, + const char *text, const char *start); +/* 214 */ +EXTERN int Tcl_RegExpMatch(Tcl_Interp *interp, const char *text, + const char *pattern); +/* 215 */ +EXTERN void Tcl_RegExpRange(Tcl_RegExp regexp, Tcl_Size index, + const char **startPtr, const char **endPtr); +/* 216 */ +EXTERN void Tcl_Release(void *clientData); +/* 217 */ +EXTERN void Tcl_ResetResult(Tcl_Interp *interp); +/* 218 */ +EXTERN Tcl_Size Tcl_ScanElement(const char *src, int *flagPtr); +/* 219 */ +EXTERN Tcl_Size Tcl_ScanCountedElement(const char *src, + Tcl_Size length, int *flagPtr); +/* Slot 220 is reserved */ +/* 221 */ +EXTERN int Tcl_ServiceAll(void); +/* 222 */ +EXTERN int Tcl_ServiceEvent(int flags); +/* 223 */ +EXTERN void Tcl_SetAssocData(Tcl_Interp *interp, + const char *name, Tcl_InterpDeleteProc *proc, + void *clientData); +/* 224 */ +EXTERN void Tcl_SetChannelBufferSize(Tcl_Channel chan, + Tcl_Size sz); +/* 225 */ +EXTERN int Tcl_SetChannelOption(Tcl_Interp *interp, + Tcl_Channel chan, const char *optionName, + const char *newValue); +/* 226 */ +EXTERN int Tcl_SetCommandInfo(Tcl_Interp *interp, + const char *cmdName, + const Tcl_CmdInfo *infoPtr); +/* 227 */ +EXTERN void Tcl_SetErrno(int err); +/* 228 */ +EXTERN void Tcl_SetErrorCode(Tcl_Interp *interp, ...); +/* 229 */ +EXTERN void Tcl_SetMaxBlockTime(const Tcl_Time *timePtr); +/* Slot 230 is reserved */ +/* 231 */ +EXTERN Tcl_Size Tcl_SetRecursionLimit(Tcl_Interp *interp, + Tcl_Size depth); +/* Slot 232 is reserved */ +/* 233 */ +EXTERN int Tcl_SetServiceMode(int mode); +/* 234 */ +EXTERN void Tcl_SetObjErrorCode(Tcl_Interp *interp, + Tcl_Obj *errorObjPtr); +/* 235 */ +EXTERN void Tcl_SetObjResult(Tcl_Interp *interp, + Tcl_Obj *resultObjPtr); +/* 236 */ +EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type); +/* Slot 237 is reserved */ +/* 238 */ +EXTERN const char * Tcl_SetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, const char *newValue, + int flags); +/* 239 */ +EXTERN const char * Tcl_SignalId(int sig); +/* 240 */ +EXTERN const char * Tcl_SignalMsg(int sig); +/* 241 */ +EXTERN void Tcl_SourceRCFile(Tcl_Interp *interp); +/* 242 */ +EXTERN int TclSplitList(Tcl_Interp *interp, const char *listStr, + void *argcPtr, const char ***argvPtr); +/* 243 */ +EXTERN void TclSplitPath(const char *path, void *argcPtr, + const char ***argvPtr); +/* Slot 244 is reserved */ +/* Slot 245 is reserved */ +/* Slot 246 is reserved */ +/* Slot 247 is reserved */ +/* 248 */ +EXTERN int Tcl_TraceVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags, + Tcl_VarTraceProc *proc, void *clientData); +/* 249 */ +EXTERN char * Tcl_TranslateFileName(Tcl_Interp *interp, + const char *name, Tcl_DString *bufferPtr); +/* 250 */ +EXTERN Tcl_Size Tcl_Ungets(Tcl_Channel chan, const char *str, + Tcl_Size len, int atHead); +/* 251 */ +EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp, + const char *varName); +/* 252 */ +EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* Slot 253 is reserved */ +/* 254 */ +EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* Slot 255 is reserved */ +/* 256 */ +EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags, Tcl_VarTraceProc *proc, + void *clientData); +/* 257 */ +EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp, + const char *varName); +/* Slot 258 is reserved */ +/* 259 */ +EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName, + const char *part1, const char *part2, + const char *localName, int flags); +/* 260 */ +EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...); +/* Slot 261 is reserved */ +/* 262 */ +EXTERN void * Tcl_VarTraceInfo2(Tcl_Interp *interp, + const char *part1, const char *part2, + int flags, Tcl_VarTraceProc *procPtr, + void *prevClientData); +/* 263 */ +EXTERN Tcl_Size Tcl_Write(Tcl_Channel chan, const char *s, + Tcl_Size slen); +/* 264 */ +EXTERN void Tcl_WrongNumArgs(Tcl_Interp *interp, Tcl_Size objc, + Tcl_Obj *const objv[], const char *message); +/* 265 */ +EXTERN int Tcl_DumpActiveMemory(const char *fileName); +/* 266 */ +EXTERN void Tcl_ValidateAllMemory(const char *file, int line); +/* Slot 267 is reserved */ +/* Slot 268 is reserved */ +/* 269 */ +EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr); +/* 270 */ +EXTERN const char * Tcl_ParseVar(Tcl_Interp *interp, const char *start, + const char **termPtr); +/* Slot 271 is reserved */ +/* 272 */ +EXTERN const char * Tcl_PkgPresentEx(Tcl_Interp *interp, + const char *name, const char *version, + int exact, void *clientDataPtr); +/* Slot 273 is reserved */ +/* Slot 274 is reserved */ +/* Slot 275 is reserved */ +/* Slot 276 is reserved */ +/* 277 */ +EXTERN Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options); +/* Slot 278 is reserved */ +/* 279 */ +EXTERN void Tcl_GetVersion(int *major, int *minor, + int *patchLevel, int *type); +/* 280 */ +EXTERN void Tcl_InitMemory(Tcl_Interp *interp); +/* 281 */ +EXTERN Tcl_Channel Tcl_StackChannel(Tcl_Interp *interp, + const Tcl_ChannelType *typePtr, + void *instanceData, int mask, + Tcl_Channel prevChan); +/* 282 */ +EXTERN int Tcl_UnstackChannel(Tcl_Interp *interp, + Tcl_Channel chan); +/* 283 */ +EXTERN Tcl_Channel Tcl_GetStackedChannel(Tcl_Channel chan); +/* 284 */ +EXTERN void Tcl_SetMainLoop(Tcl_MainLoopProc *proc); +/* Slot 285 is reserved */ +/* 286 */ +EXTERN void Tcl_AppendObjToObj(Tcl_Obj *objPtr, + Tcl_Obj *appendObjPtr); +/* 287 */ +EXTERN Tcl_Encoding Tcl_CreateEncoding(const Tcl_EncodingType *typePtr); +/* 288 */ +EXTERN void Tcl_CreateThreadExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* 289 */ +EXTERN void Tcl_DeleteThreadExitHandler(Tcl_ExitProc *proc, + void *clientData); +/* Slot 290 is reserved */ +/* 291 */ +EXTERN int Tcl_EvalEx(Tcl_Interp *interp, const char *script, + Tcl_Size numBytes, int flags); +/* 292 */ +EXTERN int Tcl_EvalObjv(Tcl_Interp *interp, Tcl_Size objc, + Tcl_Obj *const objv[], int flags); +/* 293 */ +EXTERN int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 294 */ +EXTERN TCL_NORETURN void Tcl_ExitThread(int status); +/* 295 */ +EXTERN int Tcl_ExternalToUtf(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, + Tcl_Size dstLen, int *srcReadPtr, + int *dstWrotePtr, int *dstCharsPtr); +/* 296 */ +EXTERN char * Tcl_ExternalToUtfDString(Tcl_Encoding encoding, + const char *src, Tcl_Size srcLen, + Tcl_DString *dsPtr); +/* 297 */ +EXTERN void Tcl_FinalizeThread(void); +/* 298 */ +EXTERN void Tcl_FinalizeNotifier(void *clientData); +/* 299 */ +EXTERN void Tcl_FreeEncoding(Tcl_Encoding encoding); +/* 300 */ +EXTERN Tcl_ThreadId Tcl_GetCurrentThread(void); +/* 301 */ +EXTERN Tcl_Encoding Tcl_GetEncoding(Tcl_Interp *interp, const char *name); +/* 302 */ +EXTERN const char * Tcl_GetEncodingName(Tcl_Encoding encoding); +/* 303 */ +EXTERN void Tcl_GetEncodingNames(Tcl_Interp *interp); +/* 304 */ +EXTERN int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp, + Tcl_Obj *objPtr, const void *tablePtr, + Tcl_Size offset, const char *msg, int flags, + void *indexPtr); +/* 305 */ +EXTERN void * Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, + Tcl_Size size); +/* 306 */ +EXTERN Tcl_Obj * Tcl_GetVar2Ex(Tcl_Interp *interp, const char *part1, + const char *part2, int flags); +/* 307 */ +EXTERN void * Tcl_InitNotifier(void); +/* 308 */ +EXTERN void Tcl_MutexLock(Tcl_Mutex *mutexPtr); +/* 309 */ +EXTERN void Tcl_MutexUnlock(Tcl_Mutex *mutexPtr); +/* 310 */ +EXTERN void Tcl_ConditionNotify(Tcl_Condition *condPtr); +/* 311 */ +EXTERN void Tcl_ConditionWait(Tcl_Condition *condPtr, + Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); +/* 312 */ +EXTERN Tcl_Size TclNumUtfChars(const char *src, Tcl_Size length); +/* 313 */ +EXTERN Tcl_Size Tcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr, + Tcl_Size charsToRead, int appendFlag); +/* Slot 314 is reserved */ +/* Slot 315 is reserved */ +/* 316 */ +EXTERN int Tcl_SetSystemEncoding(Tcl_Interp *interp, + const char *name); +/* 317 */ +EXTERN Tcl_Obj * Tcl_SetVar2Ex(Tcl_Interp *interp, const char *part1, + const char *part2, Tcl_Obj *newValuePtr, + int flags); +/* 318 */ +EXTERN void Tcl_ThreadAlert(Tcl_ThreadId threadId); +/* 319 */ +EXTERN void Tcl_ThreadQueueEvent(Tcl_ThreadId threadId, + Tcl_Event *evPtr, int position); +/* 320 */ +EXTERN int Tcl_UniCharAtIndex(const char *src, Tcl_Size index); +/* 321 */ +EXTERN int Tcl_UniCharToLower(int ch); +/* 322 */ +EXTERN int Tcl_UniCharToTitle(int ch); +/* 323 */ +EXTERN int Tcl_UniCharToUpper(int ch); +/* 324 */ +EXTERN Tcl_Size Tcl_UniCharToUtf(int ch, char *buf); +/* 325 */ +EXTERN const char * TclUtfAtIndex(const char *src, Tcl_Size index); +/* 326 */ +EXTERN int TclUtfCharComplete(const char *src, Tcl_Size length); +/* 327 */ +EXTERN Tcl_Size Tcl_UtfBackslash(const char *src, int *readPtr, + char *dst); +/* 328 */ +EXTERN const char * Tcl_UtfFindFirst(const char *src, int ch); +/* 329 */ +EXTERN const char * Tcl_UtfFindLast(const char *src, int ch); +/* 330 */ +EXTERN const char * TclUtfNext(const char *src); +/* 331 */ +EXTERN const char * TclUtfPrev(const char *src, const char *start); +/* 332 */ +EXTERN int Tcl_UtfToExternal(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, + Tcl_Size dstLen, int *srcReadPtr, + int *dstWrotePtr, int *dstCharsPtr); +/* 333 */ +EXTERN char * Tcl_UtfToExternalDString(Tcl_Encoding encoding, + const char *src, Tcl_Size srcLen, + Tcl_DString *dsPtr); +/* 334 */ +EXTERN Tcl_Size Tcl_UtfToLower(char *src); +/* 335 */ +EXTERN Tcl_Size Tcl_UtfToTitle(char *src); +/* 336 */ +EXTERN Tcl_Size Tcl_UtfToChar16(const char *src, + unsigned short *chPtr); +/* 337 */ +EXTERN Tcl_Size Tcl_UtfToUpper(char *src); +/* 338 */ +EXTERN Tcl_Size Tcl_WriteChars(Tcl_Channel chan, const char *src, + Tcl_Size srcLen); +/* 339 */ +EXTERN Tcl_Size Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr); +/* 340 */ +EXTERN char * Tcl_GetString(Tcl_Obj *objPtr); +/* Slot 341 is reserved */ +/* Slot 342 is reserved */ +/* 343 */ +EXTERN void Tcl_AlertNotifier(void *clientData); +/* 344 */ +EXTERN void Tcl_ServiceModeHook(int mode); +/* 345 */ +EXTERN int Tcl_UniCharIsAlnum(int ch); +/* 346 */ +EXTERN int Tcl_UniCharIsAlpha(int ch); +/* 347 */ +EXTERN int Tcl_UniCharIsDigit(int ch); +/* 348 */ +EXTERN int Tcl_UniCharIsLower(int ch); +/* 349 */ +EXTERN int Tcl_UniCharIsSpace(int ch); +/* 350 */ +EXTERN int Tcl_UniCharIsUpper(int ch); +/* 351 */ +EXTERN int Tcl_UniCharIsWordChar(int ch); +/* 352 */ +EXTERN Tcl_Size Tcl_Char16Len(const unsigned short *uniStr); +/* Slot 353 is reserved */ +/* 354 */ +EXTERN char * Tcl_Char16ToUtfDString(const unsigned short *uniStr, + Tcl_Size uniLength, Tcl_DString *dsPtr); +/* 355 */ +EXTERN unsigned short * Tcl_UtfToChar16DString(const char *src, + Tcl_Size length, Tcl_DString *dsPtr); +/* 356 */ +EXTERN Tcl_RegExp Tcl_GetRegExpFromObj(Tcl_Interp *interp, + Tcl_Obj *patObj, int flags); +/* Slot 357 is reserved */ +/* 358 */ +EXTERN void Tcl_FreeParse(Tcl_Parse *parsePtr); +/* 359 */ +EXTERN void Tcl_LogCommandInfo(Tcl_Interp *interp, + const char *script, const char *command, + Tcl_Size length); +/* 360 */ +EXTERN int Tcl_ParseBraces(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + Tcl_Parse *parsePtr, int append, + const char **termPtr); +/* 361 */ +EXTERN int Tcl_ParseCommand(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + int nested, Tcl_Parse *parsePtr); +/* 362 */ +EXTERN int Tcl_ParseExpr(Tcl_Interp *interp, const char *start, + Tcl_Size numBytes, Tcl_Parse *parsePtr); +/* 363 */ +EXTERN int Tcl_ParseQuotedString(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + Tcl_Parse *parsePtr, int append, + const char **termPtr); +/* 364 */ +EXTERN int Tcl_ParseVarName(Tcl_Interp *interp, + const char *start, Tcl_Size numBytes, + Tcl_Parse *parsePtr, int append); +/* 365 */ +EXTERN char * Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr); +/* 366 */ +EXTERN int Tcl_Chdir(const char *dirName); +/* 367 */ +EXTERN int Tcl_Access(const char *path, int mode); +/* 368 */ +EXTERN int Tcl_Stat(const char *path, struct stat *bufPtr); +/* 369 */ +EXTERN int Tcl_UtfNcmp(const char *s1, const char *s2, size_t n); +/* 370 */ +EXTERN int Tcl_UtfNcasecmp(const char *s1, const char *s2, + size_t n); +/* 371 */ +EXTERN int Tcl_StringCaseMatch(const char *str, + const char *pattern, int nocase); +/* 372 */ +EXTERN int Tcl_UniCharIsControl(int ch); +/* 373 */ +EXTERN int Tcl_UniCharIsGraph(int ch); +/* 374 */ +EXTERN int Tcl_UniCharIsPrint(int ch); +/* 375 */ +EXTERN int Tcl_UniCharIsPunct(int ch); +/* 376 */ +EXTERN int Tcl_RegExpExecObj(Tcl_Interp *interp, + Tcl_RegExp regexp, Tcl_Obj *textObj, + Tcl_Size offset, Tcl_Size nmatches, + int flags); +/* 377 */ +EXTERN void Tcl_RegExpGetInfo(Tcl_RegExp regexp, + Tcl_RegExpInfo *infoPtr); +/* 378 */ +EXTERN Tcl_Obj * Tcl_NewUnicodeObj(const Tcl_UniChar *unicode, + Tcl_Size numChars); +/* 379 */ +EXTERN void Tcl_SetUnicodeObj(Tcl_Obj *objPtr, + const Tcl_UniChar *unicode, + Tcl_Size numChars); +/* 380 */ +EXTERN Tcl_Size TclGetCharLength(Tcl_Obj *objPtr); +/* 381 */ +EXTERN int TclGetUniChar(Tcl_Obj *objPtr, Tcl_Size index); +/* Slot 382 is reserved */ +/* 383 */ +EXTERN Tcl_Obj * TclGetRange(Tcl_Obj *objPtr, Tcl_Size first, + Tcl_Size last); +/* 384 */ +EXTERN void Tcl_AppendUnicodeToObj(Tcl_Obj *objPtr, + const Tcl_UniChar *unicode, Tcl_Size length); +/* 385 */ +EXTERN int Tcl_RegExpMatchObj(Tcl_Interp *interp, + Tcl_Obj *textObj, Tcl_Obj *patternObj); +/* 386 */ +EXTERN void Tcl_SetNotifier( + const Tcl_NotifierProcs *notifierProcPtr); +/* 387 */ +EXTERN Tcl_Mutex * Tcl_GetAllocMutex(void); +/* 388 */ +EXTERN int Tcl_GetChannelNames(Tcl_Interp *interp); +/* 389 */ +EXTERN int Tcl_GetChannelNamesEx(Tcl_Interp *interp, + const char *pattern); +/* 390 */ +EXTERN int Tcl_ProcObjCmd(void *clientData, Tcl_Interp *interp, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 391 */ +EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr); +/* 392 */ +EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex); +/* 393 */ +EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr, + Tcl_ThreadCreateProc *proc, void *clientData, + TCL_HASH_TYPE stackSize, int flags); +/* 394 */ +EXTERN Tcl_Size Tcl_ReadRaw(Tcl_Channel chan, char *dst, + Tcl_Size bytesToRead); +/* 395 */ +EXTERN Tcl_Size Tcl_WriteRaw(Tcl_Channel chan, const char *src, + Tcl_Size srcLen); +/* 396 */ +EXTERN Tcl_Channel Tcl_GetTopChannel(Tcl_Channel chan); +/* 397 */ +EXTERN int Tcl_ChannelBuffered(Tcl_Channel chan); +/* 398 */ +EXTERN const char * Tcl_ChannelName(const Tcl_ChannelType *chanTypePtr); +/* 399 */ +EXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion( + const Tcl_ChannelType *chanTypePtr); +/* 400 */ +EXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc( + const Tcl_ChannelType *chanTypePtr); +/* Slot 401 is reserved */ +/* 402 */ +EXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc( + const Tcl_ChannelType *chanTypePtr); +/* 403 */ +EXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc( + const Tcl_ChannelType *chanTypePtr); +/* 404 */ +EXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc( + const Tcl_ChannelType *chanTypePtr); +/* Slot 405 is reserved */ +/* 406 */ +EXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc( + const Tcl_ChannelType *chanTypePtr); +/* 407 */ +EXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc( + const Tcl_ChannelType *chanTypePtr); +/* 408 */ +EXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc( + const Tcl_ChannelType *chanTypePtr); +/* 409 */ +EXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc( + const Tcl_ChannelType *chanTypePtr); +/* 410 */ +EXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc( + const Tcl_ChannelType *chanTypePtr); +/* 411 */ +EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc( + const Tcl_ChannelType *chanTypePtr); +/* 412 */ +EXTERN int Tcl_JoinThread(Tcl_ThreadId threadId, int *result); +/* 413 */ +EXTERN int Tcl_IsChannelShared(Tcl_Channel channel); +/* 414 */ +EXTERN int Tcl_IsChannelRegistered(Tcl_Interp *interp, + Tcl_Channel channel); +/* 415 */ +EXTERN void Tcl_CutChannel(Tcl_Channel channel); +/* 416 */ +EXTERN void Tcl_SpliceChannel(Tcl_Channel channel); +/* 417 */ +EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel); +/* 418 */ +EXTERN int Tcl_IsChannelExisting(const char *channelName); +/* Slot 419 is reserved */ +/* Slot 420 is reserved */ +/* Slot 421 is reserved */ +/* Slot 422 is reserved */ +/* 423 */ +EXTERN void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, + int keyType, const Tcl_HashKeyType *typePtr); +/* 424 */ +EXTERN void Tcl_InitObjHashTable(Tcl_HashTable *tablePtr); +/* 425 */ +EXTERN void * Tcl_CommandTraceInfo(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *procPtr, + void *prevClientData); +/* 426 */ +EXTERN int Tcl_TraceCommand(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *proc, void *clientData); +/* 427 */ +EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp, + const char *varName, int flags, + Tcl_CommandTraceProc *proc, void *clientData); +/* 428 */ +EXTERN void * Tcl_AttemptAlloc(TCL_HASH_TYPE size); +/* 429 */ +EXTERN void * Tcl_AttemptDbCkalloc(TCL_HASH_TYPE size, + const char *file, int line); +/* 430 */ +EXTERN void * Tcl_AttemptRealloc(void *ptr, TCL_HASH_TYPE size); +/* 431 */ +EXTERN void * Tcl_AttemptDbCkrealloc(void *ptr, TCL_HASH_TYPE size, + const char *file, int line); +/* 432 */ +EXTERN int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, + Tcl_Size length); +/* 433 */ +EXTERN Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel); +/* 434 */ +EXTERN Tcl_UniChar * TclGetUnicodeFromObj(Tcl_Obj *objPtr, + void *lengthPtr); +/* Slot 435 is reserved */ +/* Slot 436 is reserved */ +/* 437 */ +EXTERN Tcl_Obj * Tcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 438 */ +EXTERN int Tcl_DetachChannel(Tcl_Interp *interp, + Tcl_Channel channel); +/* 439 */ +EXTERN int Tcl_IsStandardChannel(Tcl_Channel channel); +/* 440 */ +EXTERN int Tcl_FSCopyFile(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr); +/* 441 */ +EXTERN int Tcl_FSCopyDirectory(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); +/* 442 */ +EXTERN int Tcl_FSCreateDirectory(Tcl_Obj *pathPtr); +/* 443 */ +EXTERN int Tcl_FSDeleteFile(Tcl_Obj *pathPtr); +/* 444 */ +EXTERN int Tcl_FSLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, + const char *sym1, const char *sym2, + Tcl_LibraryInitProc **proc1Ptr, + Tcl_LibraryInitProc **proc2Ptr, + Tcl_LoadHandle *handlePtr, + Tcl_FSUnloadFileProc **unloadProcPtr); +/* 445 */ +EXTERN int Tcl_FSMatchInDirectory(Tcl_Interp *interp, + Tcl_Obj *result, Tcl_Obj *pathPtr, + const char *pattern, Tcl_GlobTypeData *types); +/* 446 */ +EXTERN Tcl_Obj * Tcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr, + int linkAction); +/* 447 */ +EXTERN int Tcl_FSRemoveDirectory(Tcl_Obj *pathPtr, + int recursive, Tcl_Obj **errorPtr); +/* 448 */ +EXTERN int Tcl_FSRenameFile(Tcl_Obj *srcPathPtr, + Tcl_Obj *destPathPtr); +/* 449 */ +EXTERN int Tcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +/* 450 */ +EXTERN int Tcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval); +/* 451 */ +EXTERN int Tcl_FSFileAttrsGet(Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); +/* 452 */ +EXTERN int Tcl_FSFileAttrsSet(Tcl_Interp *interp, int index, + Tcl_Obj *pathPtr, Tcl_Obj *objPtr); +/* 453 */ +EXTERN const char *const * Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr, + Tcl_Obj **objPtrRef); +/* 454 */ +EXTERN int Tcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); +/* 455 */ +EXTERN int Tcl_FSAccess(Tcl_Obj *pathPtr, int mode); +/* 456 */ +EXTERN Tcl_Channel Tcl_FSOpenFileChannel(Tcl_Interp *interp, + Tcl_Obj *pathPtr, const char *modeString, + int permissions); +/* 457 */ +EXTERN Tcl_Obj * Tcl_FSGetCwd(Tcl_Interp *interp); +/* 458 */ +EXTERN int Tcl_FSChdir(Tcl_Obj *pathPtr); +/* 459 */ +EXTERN int Tcl_FSConvertToPathType(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 460 */ +EXTERN Tcl_Obj * Tcl_FSJoinPath(Tcl_Obj *listObj, Tcl_Size elements); +/* 461 */ +EXTERN Tcl_Obj * TclFSSplitPath(Tcl_Obj *pathPtr, void *lenPtr); +/* 462 */ +EXTERN int Tcl_FSEqualPaths(Tcl_Obj *firstPtr, + Tcl_Obj *secondPtr); +/* 463 */ +EXTERN Tcl_Obj * Tcl_FSGetNormalizedPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 464 */ +EXTERN Tcl_Obj * Tcl_FSJoinToPath(Tcl_Obj *pathPtr, Tcl_Size objc, + Tcl_Obj *const objv[]); +/* 465 */ +EXTERN void * Tcl_FSGetInternalRep(Tcl_Obj *pathPtr, + const Tcl_Filesystem *fsPtr); +/* 466 */ +EXTERN Tcl_Obj * Tcl_FSGetTranslatedPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 467 */ +EXTERN int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName); +/* 468 */ +EXTERN Tcl_Obj * Tcl_FSNewNativePath( + const Tcl_Filesystem *fromFilesystem, + void *clientData); +/* 469 */ +EXTERN const void * Tcl_FSGetNativePath(Tcl_Obj *pathPtr); +/* 470 */ +EXTERN Tcl_Obj * Tcl_FSFileSystemInfo(Tcl_Obj *pathPtr); +/* 471 */ +EXTERN Tcl_Obj * Tcl_FSPathSeparator(Tcl_Obj *pathPtr); +/* 472 */ +EXTERN Tcl_Obj * Tcl_FSListVolumes(void); +/* 473 */ +EXTERN int Tcl_FSRegister(void *clientData, + const Tcl_Filesystem *fsPtr); +/* 474 */ +EXTERN int Tcl_FSUnregister(const Tcl_Filesystem *fsPtr); +/* 475 */ +EXTERN void * Tcl_FSData(const Tcl_Filesystem *fsPtr); +/* 476 */ +EXTERN const char * Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp, + Tcl_Obj *pathPtr); +/* 477 */ +EXTERN const Tcl_Filesystem * Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr); +/* 478 */ +EXTERN Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr); +/* 479 */ +EXTERN int Tcl_OutputBuffered(Tcl_Channel chan); +/* 480 */ +EXTERN void Tcl_FSMountsChanged(const Tcl_Filesystem *fsPtr); +/* 481 */ +EXTERN int Tcl_EvalTokensStandard(Tcl_Interp *interp, + Tcl_Token *tokenPtr, Tcl_Size count); +/* 482 */ +EXTERN void Tcl_GetTime(Tcl_Time *timeBuf); +/* 483 */ +EXTERN Tcl_Trace Tcl_CreateObjTrace(Tcl_Interp *interp, + Tcl_Size level, int flags, + Tcl_CmdObjTraceProc *objProc, + void *clientData, + Tcl_CmdObjTraceDeleteProc *delProc); +/* 484 */ +EXTERN int Tcl_GetCommandInfoFromToken(Tcl_Command token, + Tcl_CmdInfo *infoPtr); +/* 485 */ +EXTERN int Tcl_SetCommandInfoFromToken(Tcl_Command token, + const Tcl_CmdInfo *infoPtr); +/* 486 */ +EXTERN Tcl_Obj * Tcl_DbNewWideIntObj(Tcl_WideInt wideValue, + const char *file, int line); +/* 487 */ +EXTERN int Tcl_GetWideIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_WideInt *widePtr); +/* 488 */ +EXTERN Tcl_Obj * Tcl_NewWideIntObj(Tcl_WideInt wideValue); +/* 489 */ +EXTERN void Tcl_SetWideIntObj(Tcl_Obj *objPtr, + Tcl_WideInt wideValue); +/* 490 */ +EXTERN Tcl_StatBuf * Tcl_AllocStatBuf(void); +/* 491 */ +EXTERN long long Tcl_Seek(Tcl_Channel chan, long long offset, + int mode); +/* 492 */ +EXTERN long long Tcl_Tell(Tcl_Channel chan); +/* 493 */ +EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc( + const Tcl_ChannelType *chanTypePtr); +/* 494 */ +EXTERN int Tcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); +/* 495 */ +EXTERN int Tcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); +/* 496 */ +EXTERN int Tcl_DictObjRemove(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); +/* 497 */ +EXTERN int TclDictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr, + void *sizePtr); +/* 498 */ +EXTERN int Tcl_DictObjFirst(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, + Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, + int *donePtr); +/* 499 */ +EXTERN void Tcl_DictObjNext(Tcl_DictSearch *searchPtr, + Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, + int *donePtr); +/* 500 */ +EXTERN void Tcl_DictObjDone(Tcl_DictSearch *searchPtr); +/* 501 */ +EXTERN int Tcl_DictObjPutKeyList(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Size keyc, + Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); +/* 502 */ +EXTERN int Tcl_DictObjRemoveKeyList(Tcl_Interp *interp, + Tcl_Obj *dictPtr, Tcl_Size keyc, + Tcl_Obj *const *keyv); +/* 503 */ +EXTERN Tcl_Obj * Tcl_NewDictObj(void); +/* 504 */ +EXTERN Tcl_Obj * Tcl_DbNewDictObj(const char *file, int line); +/* 505 */ +EXTERN void Tcl_RegisterConfig(Tcl_Interp *interp, + const char *pkgName, + const Tcl_Config *configuration, + const char *valEncoding); +/* 506 */ +EXTERN Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp, + const char *name, void *clientData, + Tcl_NamespaceDeleteProc *deleteProc); +/* 507 */ +EXTERN void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr); +/* 508 */ +EXTERN int Tcl_AppendExportList(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); +/* 509 */ +EXTERN int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr, + const char *pattern, int resetListFirst); +/* 510 */ +EXTERN int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr, + const char *pattern, int allowOverwrite); +/* 511 */ +EXTERN int Tcl_ForgetImport(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, const char *pattern); +/* 512 */ +EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp); +/* 513 */ +EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp); +/* 514 */ +EXTERN Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp, + const char *name, + Tcl_Namespace *contextNsPtr, int flags); +/* 515 */ +EXTERN Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, const char *name, + Tcl_Namespace *contextNsPtr, int flags); +/* 516 */ +EXTERN Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 517 */ +EXTERN void Tcl_GetCommandFullName(Tcl_Interp *interp, + Tcl_Command command, Tcl_Obj *objPtr); +/* 518 */ +EXTERN int Tcl_FSEvalFileEx(Tcl_Interp *interp, + Tcl_Obj *fileName, const char *encodingName); +/* Slot 519 is reserved */ +/* 520 */ +EXTERN void Tcl_LimitAddHandler(Tcl_Interp *interp, int type, + Tcl_LimitHandlerProc *handlerProc, + void *clientData, + Tcl_LimitHandlerDeleteProc *deleteProc); +/* 521 */ +EXTERN void Tcl_LimitRemoveHandler(Tcl_Interp *interp, int type, + Tcl_LimitHandlerProc *handlerProc, + void *clientData); +/* 522 */ +EXTERN int Tcl_LimitReady(Tcl_Interp *interp); +/* 523 */ +EXTERN int Tcl_LimitCheck(Tcl_Interp *interp); +/* 524 */ +EXTERN int Tcl_LimitExceeded(Tcl_Interp *interp); +/* 525 */ +EXTERN void Tcl_LimitSetCommands(Tcl_Interp *interp, + Tcl_Size commandLimit); +/* 526 */ +EXTERN void Tcl_LimitSetTime(Tcl_Interp *interp, + Tcl_Time *timeLimitPtr); +/* 527 */ +EXTERN void Tcl_LimitSetGranularity(Tcl_Interp *interp, int type, + int granularity); +/* 528 */ +EXTERN int Tcl_LimitTypeEnabled(Tcl_Interp *interp, int type); +/* 529 */ +EXTERN int Tcl_LimitTypeExceeded(Tcl_Interp *interp, int type); +/* 530 */ +EXTERN void Tcl_LimitTypeSet(Tcl_Interp *interp, int type); +/* 531 */ +EXTERN void Tcl_LimitTypeReset(Tcl_Interp *interp, int type); +/* 532 */ +EXTERN int Tcl_LimitGetCommands(Tcl_Interp *interp); +/* 533 */ +EXTERN void Tcl_LimitGetTime(Tcl_Interp *interp, + Tcl_Time *timeLimitPtr); +/* 534 */ +EXTERN int Tcl_LimitGetGranularity(Tcl_Interp *interp, int type); +/* 535 */ +EXTERN Tcl_InterpState Tcl_SaveInterpState(Tcl_Interp *interp, int status); +/* 536 */ +EXTERN int Tcl_RestoreInterpState(Tcl_Interp *interp, + Tcl_InterpState state); +/* 537 */ +EXTERN void Tcl_DiscardInterpState(Tcl_InterpState state); +/* 538 */ +EXTERN int Tcl_SetReturnOptions(Tcl_Interp *interp, + Tcl_Obj *options); +/* 539 */ +EXTERN Tcl_Obj * Tcl_GetReturnOptions(Tcl_Interp *interp, int result); +/* 540 */ +EXTERN int Tcl_IsEnsemble(Tcl_Command token); +/* 541 */ +EXTERN Tcl_Command Tcl_CreateEnsemble(Tcl_Interp *interp, + const char *name, + Tcl_Namespace *namespacePtr, int flags); +/* 542 */ +EXTERN Tcl_Command Tcl_FindEnsemble(Tcl_Interp *interp, + Tcl_Obj *cmdNameObj, int flags); +/* 543 */ +EXTERN int Tcl_SetEnsembleSubcommandList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *subcmdList); +/* 544 */ +EXTERN int Tcl_SetEnsembleMappingDict(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *mapDict); +/* 545 */ +EXTERN int Tcl_SetEnsembleUnknownHandler(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *unknownList); +/* 546 */ +EXTERN int Tcl_SetEnsembleFlags(Tcl_Interp *interp, + Tcl_Command token, int flags); +/* 547 */ +EXTERN int Tcl_GetEnsembleSubcommandList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **subcmdListPtr); +/* 548 */ +EXTERN int Tcl_GetEnsembleMappingDict(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **mapDictPtr); +/* 549 */ +EXTERN int Tcl_GetEnsembleUnknownHandler(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **unknownListPtr); +/* 550 */ +EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp, + Tcl_Command token, int *flagsPtr); +/* 551 */ +EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, + Tcl_Command token, + Tcl_Namespace **namespacePtrPtr); +/* 552 */ +EXTERN void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc, + Tcl_ScaleTimeProc *scaleProc, + void *clientData); +/* 553 */ +EXTERN void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc, + Tcl_ScaleTimeProc **scaleProc, + void **clientData); +/* 554 */ +EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc( + const Tcl_ChannelType *chanTypePtr); +/* 555 */ +EXTERN Tcl_Obj * Tcl_NewBignumObj(void *value); +/* 556 */ +EXTERN Tcl_Obj * Tcl_DbNewBignumObj(void *value, const char *file, + int line); +/* 557 */ +EXTERN void Tcl_SetBignumObj(Tcl_Obj *obj, void *value); +/* 558 */ +EXTERN int Tcl_GetBignumFromObj(Tcl_Interp *interp, + Tcl_Obj *obj, void *value); +/* 559 */ +EXTERN int Tcl_TakeBignumFromObj(Tcl_Interp *interp, + Tcl_Obj *obj, void *value); +/* 560 */ +EXTERN int Tcl_TruncateChannel(Tcl_Channel chan, + long long length); +/* 561 */ +EXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc( + const Tcl_ChannelType *chanTypePtr); +/* 562 */ +EXTERN void Tcl_SetChannelErrorInterp(Tcl_Interp *interp, + Tcl_Obj *msg); +/* 563 */ +EXTERN void Tcl_GetChannelErrorInterp(Tcl_Interp *interp, + Tcl_Obj **msg); +/* 564 */ +EXTERN void Tcl_SetChannelError(Tcl_Channel chan, Tcl_Obj *msg); +/* 565 */ +EXTERN void Tcl_GetChannelError(Tcl_Channel chan, Tcl_Obj **msg); +/* 566 */ +EXTERN int Tcl_InitBignumFromDouble(Tcl_Interp *interp, + double initval, void *toInit); +/* 567 */ +EXTERN Tcl_Obj * Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp, + Tcl_Namespace *nsPtr); +/* 568 */ +EXTERN int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp, + Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); +/* 569 */ +EXTERN int Tcl_GetEncodingFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); +/* 570 */ +EXTERN Tcl_Obj * Tcl_GetEncodingSearchPath(void); +/* 571 */ +EXTERN int Tcl_SetEncodingSearchPath(Tcl_Obj *searchPath); +/* 572 */ +EXTERN const char * Tcl_GetEncodingNameFromEnvironment( + Tcl_DString *bufPtr); +/* 573 */ +EXTERN int Tcl_PkgRequireProc(Tcl_Interp *interp, + const char *name, Tcl_Size objc, + Tcl_Obj *const objv[], void *clientDataPtr); +/* 574 */ +EXTERN void Tcl_AppendObjToErrorInfo(Tcl_Interp *interp, + Tcl_Obj *objPtr); +/* 575 */ +EXTERN void Tcl_AppendLimitedToObj(Tcl_Obj *objPtr, + const char *bytes, Tcl_Size length, + Tcl_Size limit, const char *ellipsis); +/* 576 */ +EXTERN Tcl_Obj * Tcl_Format(Tcl_Interp *interp, const char *format, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 577 */ +EXTERN int Tcl_AppendFormatToObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, const char *format, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 578 */ +EXTERN Tcl_Obj * Tcl_ObjPrintf(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); +/* 579 */ +EXTERN void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr, + const char *format, ...) TCL_FORMAT_PRINTF(2, 3); +/* 580 */ +EXTERN int Tcl_CancelEval(Tcl_Interp *interp, + Tcl_Obj *resultObjPtr, void *clientData, + int flags); +/* 581 */ +EXTERN int Tcl_Canceled(Tcl_Interp *interp, int flags); +/* 582 */ +EXTERN int Tcl_CreatePipe(Tcl_Interp *interp, + Tcl_Channel *rchan, Tcl_Channel *wchan, + int flags); +/* 583 */ +EXTERN Tcl_Command Tcl_NRCreateCommand(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc *proc, + Tcl_ObjCmdProc *nreProc, void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 584 */ +EXTERN int Tcl_NREvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 585 */ +EXTERN int Tcl_NREvalObjv(Tcl_Interp *interp, Tcl_Size objc, + Tcl_Obj *const objv[], int flags); +/* 586 */ +EXTERN int Tcl_NRCmdSwap(Tcl_Interp *interp, Tcl_Command cmd, + Tcl_Size objc, Tcl_Obj *const objv[], + int flags); +/* 587 */ +EXTERN void Tcl_NRAddCallback(Tcl_Interp *interp, + Tcl_NRPostProc *postProcPtr, void *data0, + void *data1, void *data2, void *data3); +/* 588 */ +EXTERN int Tcl_NRCallObjProc(Tcl_Interp *interp, + Tcl_ObjCmdProc *objProc, void *clientData, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 589 */ +EXTERN unsigned Tcl_GetFSDeviceFromStat(const Tcl_StatBuf *statPtr); +/* 590 */ +EXTERN unsigned Tcl_GetFSInodeFromStat(const Tcl_StatBuf *statPtr); +/* 591 */ +EXTERN unsigned Tcl_GetModeFromStat(const Tcl_StatBuf *statPtr); +/* 592 */ +EXTERN int Tcl_GetLinkCountFromStat(const Tcl_StatBuf *statPtr); +/* 593 */ +EXTERN int Tcl_GetUserIdFromStat(const Tcl_StatBuf *statPtr); +/* 594 */ +EXTERN int Tcl_GetGroupIdFromStat(const Tcl_StatBuf *statPtr); +/* 595 */ +EXTERN int Tcl_GetDeviceTypeFromStat(const Tcl_StatBuf *statPtr); +/* 596 */ +EXTERN long long Tcl_GetAccessTimeFromStat(const Tcl_StatBuf *statPtr); +/* 597 */ +EXTERN long long Tcl_GetModificationTimeFromStat( + const Tcl_StatBuf *statPtr); +/* 598 */ +EXTERN long long Tcl_GetChangeTimeFromStat(const Tcl_StatBuf *statPtr); +/* 599 */ +EXTERN unsigned long long Tcl_GetSizeFromStat(const Tcl_StatBuf *statPtr); +/* 600 */ +EXTERN unsigned long long Tcl_GetBlocksFromStat(const Tcl_StatBuf *statPtr); +/* 601 */ +EXTERN unsigned Tcl_GetBlockSizeFromStat(const Tcl_StatBuf *statPtr); +/* 602 */ +EXTERN int Tcl_SetEnsembleParameterList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj *paramList); +/* 603 */ +EXTERN int Tcl_GetEnsembleParameterList(Tcl_Interp *interp, + Tcl_Command token, Tcl_Obj **paramListPtr); +/* 604 */ +EXTERN int TclParseArgsObjv(Tcl_Interp *interp, + const Tcl_ArgvInfo *argTable, void *objcPtr, + Tcl_Obj *const *objv, Tcl_Obj ***remObjv); +/* 605 */ +EXTERN int Tcl_GetErrorLine(Tcl_Interp *interp); +/* 606 */ +EXTERN void Tcl_SetErrorLine(Tcl_Interp *interp, int lineNum); +/* 607 */ +EXTERN void Tcl_TransferResult(Tcl_Interp *sourceInterp, + int code, Tcl_Interp *targetInterp); +/* 608 */ +EXTERN int Tcl_InterpActive(Tcl_Interp *interp); +/* 609 */ +EXTERN void Tcl_BackgroundException(Tcl_Interp *interp, int code); +/* 610 */ +EXTERN int Tcl_ZlibDeflate(Tcl_Interp *interp, int format, + Tcl_Obj *data, int level, + Tcl_Obj *gzipHeaderDictObj); +/* 611 */ +EXTERN int Tcl_ZlibInflate(Tcl_Interp *interp, int format, + Tcl_Obj *data, Tcl_Size buffersize, + Tcl_Obj *gzipHeaderDictObj); +/* 612 */ +EXTERN unsigned int Tcl_ZlibCRC32(unsigned int crc, + const unsigned char *buf, Tcl_Size len); +/* 613 */ +EXTERN unsigned int Tcl_ZlibAdler32(unsigned int adler, + const unsigned char *buf, Tcl_Size len); +/* 614 */ +EXTERN int Tcl_ZlibStreamInit(Tcl_Interp *interp, int mode, + int format, int level, Tcl_Obj *dictObj, + Tcl_ZlibStream *zshandle); +/* 615 */ +EXTERN Tcl_Obj * Tcl_ZlibStreamGetCommandName(Tcl_ZlibStream zshandle); +/* 616 */ +EXTERN int Tcl_ZlibStreamEof(Tcl_ZlibStream zshandle); +/* 617 */ +EXTERN int Tcl_ZlibStreamChecksum(Tcl_ZlibStream zshandle); +/* 618 */ +EXTERN int Tcl_ZlibStreamPut(Tcl_ZlibStream zshandle, + Tcl_Obj *data, int flush); +/* 619 */ +EXTERN int Tcl_ZlibStreamGet(Tcl_ZlibStream zshandle, + Tcl_Obj *data, Tcl_Size count); +/* 620 */ +EXTERN int Tcl_ZlibStreamClose(Tcl_ZlibStream zshandle); +/* 621 */ +EXTERN int Tcl_ZlibStreamReset(Tcl_ZlibStream zshandle); +/* 622 */ +EXTERN void Tcl_SetStartupScript(Tcl_Obj *path, + const char *encoding); +/* 623 */ +EXTERN Tcl_Obj * Tcl_GetStartupScript(const char **encodingPtr); +/* 624 */ +EXTERN int Tcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan, + int flags); +/* 625 */ +EXTERN int Tcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + Tcl_Obj *resultPtr); +/* 626 */ +EXTERN int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags); +/* 627 */ +EXTERN int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, + const char *const symv[], int flags, + void *procPtrs, Tcl_LoadHandle *handlePtr); +/* 628 */ +EXTERN void * Tcl_FindSymbol(Tcl_Interp *interp, + Tcl_LoadHandle handle, const char *symbol); +/* 629 */ +EXTERN int Tcl_FSUnloadFile(Tcl_Interp *interp, + Tcl_LoadHandle handlePtr); +/* 630 */ +EXTERN void Tcl_ZlibStreamSetCompressionDictionary( + Tcl_ZlibStream zhandle, + Tcl_Obj *compressionDictionaryObj); +/* 631 */ +EXTERN Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp, + const char *service, const char *host, + unsigned int flags, int backlog, + Tcl_TcpAcceptProc *acceptProc, + void *callbackData); +/* 632 */ +EXTERN int TclZipfs_Mount(Tcl_Interp *interp, + const char *zipname, const char *mountPoint, + const char *passwd); +/* 633 */ +EXTERN int TclZipfs_Unmount(Tcl_Interp *interp, + const char *mountPoint); +/* 634 */ +EXTERN Tcl_Obj * TclZipfs_TclLibrary(void); +/* 635 */ +EXTERN int TclZipfs_MountBuffer(Tcl_Interp *interp, + const void *data, size_t datalen, + const char *mountPoint, int copy); +/* 636 */ +EXTERN void Tcl_FreeInternalRep(Tcl_Obj *objPtr); +/* 637 */ +EXTERN char * Tcl_InitStringRep(Tcl_Obj *objPtr, const char *bytes, + TCL_HASH_TYPE numBytes); +/* 638 */ +EXTERN Tcl_ObjInternalRep * Tcl_FetchInternalRep(Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr); +/* 639 */ +EXTERN void Tcl_StoreInternalRep(Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr, + const Tcl_ObjInternalRep *irPtr); +/* 640 */ +EXTERN int Tcl_HasStringRep(Tcl_Obj *objPtr); +/* 641 */ +EXTERN void Tcl_IncrRefCount(Tcl_Obj *objPtr); +/* 642 */ +EXTERN void Tcl_DecrRefCount(Tcl_Obj *objPtr); +/* 643 */ +EXTERN int Tcl_IsShared(Tcl_Obj *objPtr); +/* 644 */ +EXTERN int Tcl_LinkArray(Tcl_Interp *interp, + const char *varName, void *addr, int type, + Tcl_Size size); +/* 645 */ +EXTERN int Tcl_GetIntForIndex(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Size endValue, + Tcl_Size *indexPtr); +/* 646 */ +EXTERN Tcl_Size Tcl_UtfToUniChar(const char *src, int *chPtr); +/* 647 */ +EXTERN char * Tcl_UniCharToUtfDString(const int *uniStr, + Tcl_Size uniLength, Tcl_DString *dsPtr); +/* 648 */ +EXTERN int * Tcl_UtfToUniCharDString(const char *src, + Tcl_Size length, Tcl_DString *dsPtr); +/* 649 */ +EXTERN unsigned char * TclGetBytesFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, void *numBytesPtr); +/* 650 */ +EXTERN unsigned char * Tcl_GetBytesFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Size *numBytesPtr); +/* 651 */ +EXTERN char * Tcl_GetStringFromObj(Tcl_Obj *objPtr, + Tcl_Size *lengthPtr); +/* 652 */ +EXTERN Tcl_UniChar * Tcl_GetUnicodeFromObj(Tcl_Obj *objPtr, + Tcl_Size *lengthPtr); +/* 653 */ +EXTERN int Tcl_GetSizeIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Size *sizePtr); +/* 654 */ +EXTERN int Tcl_UtfCharComplete(const char *src, Tcl_Size length); +/* 655 */ +EXTERN const char * Tcl_UtfNext(const char *src); +/* 656 */ +EXTERN const char * Tcl_UtfPrev(const char *src, const char *start); +/* 657 */ +EXTERN int Tcl_UniCharIsUnicode(int ch); +/* 658 */ +EXTERN int Tcl_ExternalToUtfDStringEx(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_DString *dsPtr, + Tcl_Size *errorLocationPtr); +/* 659 */ +EXTERN int Tcl_UtfToExternalDStringEx(Tcl_Interp *interp, + Tcl_Encoding encoding, const char *src, + Tcl_Size srcLen, int flags, + Tcl_DString *dsPtr, + Tcl_Size *errorLocationPtr); +/* 660 */ +EXTERN int Tcl_AsyncMarkFromSignal(Tcl_AsyncHandler async, + int sigNumber); +/* 661 */ +EXTERN int Tcl_ListObjGetElements(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Size *objcPtr, + Tcl_Obj ***objvPtr); +/* 662 */ +EXTERN int Tcl_ListObjLength(Tcl_Interp *interp, + Tcl_Obj *listPtr, Tcl_Size *lengthPtr); +/* 663 */ +EXTERN int Tcl_DictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr, + Tcl_Size *sizePtr); +/* 664 */ +EXTERN int Tcl_SplitList(Tcl_Interp *interp, + const char *listStr, Tcl_Size *argcPtr, + const char ***argvPtr); +/* 665 */ +EXTERN void Tcl_SplitPath(const char *path, Tcl_Size *argcPtr, + const char ***argvPtr); +/* 666 */ +EXTERN Tcl_Obj * Tcl_FSSplitPath(Tcl_Obj *pathPtr, Tcl_Size *lenPtr); +/* 667 */ +EXTERN int Tcl_ParseArgsObjv(Tcl_Interp *interp, + const Tcl_ArgvInfo *argTable, + Tcl_Size *objcPtr, Tcl_Obj *const *objv, + Tcl_Obj ***remObjv); +/* 668 */ +EXTERN Tcl_Size Tcl_UniCharLen(const int *uniStr); +/* 669 */ +EXTERN Tcl_Size Tcl_NumUtfChars(const char *src, Tcl_Size length); +/* 670 */ +EXTERN Tcl_Size Tcl_GetCharLength(Tcl_Obj *objPtr); +/* 671 */ +EXTERN const char * Tcl_UtfAtIndex(const char *src, Tcl_Size index); +/* 672 */ +EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, Tcl_Size first, + Tcl_Size last); +/* 673 */ +EXTERN int Tcl_GetUniChar(Tcl_Obj *objPtr, Tcl_Size index); +/* 674 */ +EXTERN int Tcl_GetBool(Tcl_Interp *interp, const char *src, + int flags, char *charPtr); +/* 675 */ +EXTERN int Tcl_GetBoolFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int flags, char *charPtr); +/* 676 */ +EXTERN Tcl_Command Tcl_CreateObjCommand2(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc2 *proc2, + void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 677 */ +EXTERN Tcl_Trace Tcl_CreateObjTrace2(Tcl_Interp *interp, + Tcl_Size level, int flags, + Tcl_CmdObjTraceProc2 *objProc2, + void *clientData, + Tcl_CmdObjTraceDeleteProc *delProc); +/* 678 */ +EXTERN Tcl_Command Tcl_NRCreateCommand2(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc2 *proc, + Tcl_ObjCmdProc2 *nreProc2, void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 679 */ +EXTERN int Tcl_NRCallObjProc2(Tcl_Interp *interp, + Tcl_ObjCmdProc2 *objProc2, void *clientData, + Tcl_Size objc, Tcl_Obj *const objv[]); +/* 680 */ +EXTERN int Tcl_GetNumberFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, void **clientDataPtr, + int *typePtr); +/* 681 */ +EXTERN int Tcl_GetNumber(Tcl_Interp *interp, const char *bytes, + Tcl_Size numBytes, void **clientDataPtr, + int *typePtr); +/* 682 */ +EXTERN int Tcl_RemoveChannelMode(Tcl_Interp *interp, + Tcl_Channel chan, int mode); +/* 683 */ +EXTERN Tcl_Size Tcl_GetEncodingNulLength(Tcl_Encoding encoding); +/* 684 */ +EXTERN int Tcl_GetWideUIntFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr); +/* 685 */ +EXTERN Tcl_Obj * Tcl_DStringToObj(Tcl_DString *dsPtr); +/* Slot 686 is reserved */ +/* Slot 687 is reserved */ +/* 688 */ +EXTERN void TclUnusedStubEntry(void); + +typedef struct { + const struct TclPlatStubs *tclPlatStubs; + const struct TclIntStubs *tclIntStubs; + const struct TclIntPlatStubs *tclIntPlatStubs; +} TclStubHooks; + +typedef struct TclStubs { + int magic; + const TclStubHooks *hooks; + + int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */ + const char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */ + TCL_NORETURN1 void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */ + void * (*tcl_Alloc) (TCL_HASH_TYPE size); /* 3 */ + void (*tcl_Free) (void *ptr); /* 4 */ + void * (*tcl_Realloc) (void *ptr, TCL_HASH_TYPE size); /* 5 */ + void * (*tcl_DbCkalloc) (TCL_HASH_TYPE size, const char *file, int line); /* 6 */ + void (*tcl_DbCkfree) (void *ptr, const char *file, int line); /* 7 */ + void * (*tcl_DbCkrealloc) (void *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 8 */ + void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, void *clientData); /* 9 */ + void (*tcl_DeleteFileHandler) (int fd); /* 10 */ + void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */ + void (*tcl_Sleep) (int ms); /* 12 */ + int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */ + int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */ + void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */ + void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* 16 */ + Tcl_Obj * (*tcl_ConcatObj) (Tcl_Size objc, Tcl_Obj *const objv[]); /* 17 */ + int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */ + void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */ + void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */ + int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */ + void (*reserved22)(void); + Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, Tcl_Size numBytes, const char *file, int line); /* 23 */ + Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */ + Tcl_Obj * (*tcl_DbNewListObj) (Tcl_Size objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */ + void (*reserved26)(void); + Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */ + Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, Tcl_Size length, const char *file, int line); /* 28 */ + Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */ + void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */ + int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *intPtr); /* 31 */ + int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 32 */ + unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, Tcl_Size *numBytesPtr); /* 33 */ + int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */ + int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */ + void (*reserved36)(void); + int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */ + int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */ + int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */ + const Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */ + char * (*tclGetStringFromObj) (Tcl_Obj *objPtr, void *lengthPtr); /* 41 */ + void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */ + int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */ + int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */ + int (*tclListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, void *objcPtr, Tcl_Obj ***objvPtr); /* 45 */ + int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size index, Tcl_Obj **objPtrPtr); /* 46 */ + int (*tclListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, void *lengthPtr); /* 47 */ + int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first, Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[]); /* 48 */ + void (*reserved49)(void); + Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, Tcl_Size numBytes); /* 50 */ + Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */ + void (*reserved52)(void); + Tcl_Obj * (*tcl_NewListObj) (Tcl_Size objc, Tcl_Obj *const objv[]); /* 53 */ + void (*reserved54)(void); + Tcl_Obj * (*tcl_NewObj) (void); /* 55 */ + Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, Tcl_Size length); /* 56 */ + void (*reserved57)(void); + unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, Tcl_Size numBytes); /* 58 */ + void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, Tcl_Size numBytes); /* 59 */ + void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */ + void (*reserved61)(void); + void (*tcl_SetListObj) (Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[]); /* 62 */ + void (*reserved63)(void); + void (*tcl_SetObjLength) (Tcl_Obj *objPtr, Tcl_Size length); /* 64 */ + void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* 65 */ + void (*reserved66)(void); + void (*reserved67)(void); + void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */ + void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */ + void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */ + Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, void *clientData); /* 71 */ + void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */ + int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */ + void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */ + int (*tcl_AsyncReady) (void); /* 75 */ + void (*reserved76)(void); + void (*reserved77)(void); + int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */ + void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, void *clientData); /* 79 */ + void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, void *clientData); /* 80 */ + int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */ + int (*tcl_CommandComplete) (const char *cmd); /* 82 */ + char * (*tcl_Concat) (Tcl_Size argc, const char *const *argv); /* 83 */ + Tcl_Size (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */ + Tcl_Size (*tcl_ConvertCountedElement) (const char *src, Tcl_Size length, char *dst, int flags); /* 85 */ + int (*tcl_CreateAlias) (Tcl_Interp *childInterp, const char *childCmd, Tcl_Interp *target, const char *targetCmd, Tcl_Size argc, const char *const *argv); /* 86 */ + int (*tcl_CreateAliasObj) (Tcl_Interp *childInterp, const char *childCmd, Tcl_Interp *target, const char *targetCmd, Tcl_Size objc, Tcl_Obj *const objv[]); /* 87 */ + Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, void *instanceData, int mask); /* 88 */ + void (*tcl_CreateChannelHandler) (Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, void *clientData); /* 89 */ + void (*tcl_CreateCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, void *clientData); /* 90 */ + Tcl_Command (*tcl_CreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 91 */ + void (*tcl_CreateEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, void *clientData); /* 92 */ + void (*tcl_CreateExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 93 */ + Tcl_Interp * (*tcl_CreateInterp) (void); /* 94 */ + void (*reserved95)(void); + Tcl_Command (*tcl_CreateObjCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 96 */ + Tcl_Interp * (*tcl_CreateChild) (Tcl_Interp *interp, const char *name, int isSafe); /* 97 */ + Tcl_TimerToken (*tcl_CreateTimerHandler) (int milliseconds, Tcl_TimerProc *proc, void *clientData); /* 98 */ + Tcl_Trace (*tcl_CreateTrace) (Tcl_Interp *interp, Tcl_Size level, Tcl_CmdTraceProc *proc, void *clientData); /* 99 */ + void (*tcl_DeleteAssocData) (Tcl_Interp *interp, const char *name); /* 100 */ + void (*tcl_DeleteChannelHandler) (Tcl_Channel chan, Tcl_ChannelProc *proc, void *clientData); /* 101 */ + void (*tcl_DeleteCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, void *clientData); /* 102 */ + int (*tcl_DeleteCommand) (Tcl_Interp *interp, const char *cmdName); /* 103 */ + int (*tcl_DeleteCommandFromToken) (Tcl_Interp *interp, Tcl_Command command); /* 104 */ + void (*tcl_DeleteEvents) (Tcl_EventDeleteProc *proc, void *clientData); /* 105 */ + void (*tcl_DeleteEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, void *clientData); /* 106 */ + void (*tcl_DeleteExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 107 */ + void (*tcl_DeleteHashEntry) (Tcl_HashEntry *entryPtr); /* 108 */ + void (*tcl_DeleteHashTable) (Tcl_HashTable *tablePtr); /* 109 */ + void (*tcl_DeleteInterp) (Tcl_Interp *interp); /* 110 */ + void (*tcl_DetachPids) (Tcl_Size numPids, Tcl_Pid *pidPtr); /* 111 */ + void (*tcl_DeleteTimerHandler) (Tcl_TimerToken token); /* 112 */ + void (*tcl_DeleteTrace) (Tcl_Interp *interp, Tcl_Trace trace); /* 113 */ + void (*tcl_DontCallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, void *clientData); /* 114 */ + int (*tcl_DoOneEvent) (int flags); /* 115 */ + void (*tcl_DoWhenIdle) (Tcl_IdleProc *proc, void *clientData); /* 116 */ + char * (*tcl_DStringAppend) (Tcl_DString *dsPtr, const char *bytes, Tcl_Size length); /* 117 */ + char * (*tcl_DStringAppendElement) (Tcl_DString *dsPtr, const char *element); /* 118 */ + void (*tcl_DStringEndSublist) (Tcl_DString *dsPtr); /* 119 */ + void (*tcl_DStringFree) (Tcl_DString *dsPtr); /* 120 */ + void (*tcl_DStringGetResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 121 */ + void (*tcl_DStringInit) (Tcl_DString *dsPtr); /* 122 */ + void (*tcl_DStringResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 123 */ + void (*tcl_DStringSetLength) (Tcl_DString *dsPtr, Tcl_Size length); /* 124 */ + void (*tcl_DStringStartSublist) (Tcl_DString *dsPtr); /* 125 */ + int (*tcl_Eof) (Tcl_Channel chan); /* 126 */ + const char * (*tcl_ErrnoId) (void); /* 127 */ + const char * (*tcl_ErrnoMsg) (int err); /* 128 */ + void (*reserved129)(void); + int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */ + void (*reserved131)(void); + void (*tcl_EventuallyFree) (void *clientData, Tcl_FreeProc *freeProc); /* 132 */ + TCL_NORETURN1 void (*tcl_Exit) (int status); /* 133 */ + int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */ + int (*tcl_ExprBoolean) (Tcl_Interp *interp, const char *expr, int *ptr); /* 135 */ + int (*tcl_ExprBooleanObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 136 */ + int (*tcl_ExprDouble) (Tcl_Interp *interp, const char *expr, double *ptr); /* 137 */ + int (*tcl_ExprDoubleObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 138 */ + int (*tcl_ExprLong) (Tcl_Interp *interp, const char *expr, long *ptr); /* 139 */ + int (*tcl_ExprLongObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 140 */ + int (*tcl_ExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 141 */ + int (*tcl_ExprString) (Tcl_Interp *interp, const char *expr); /* 142 */ + void (*tcl_Finalize) (void); /* 143 */ + void (*reserved144)(void); + Tcl_HashEntry * (*tcl_FirstHashEntry) (Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 145 */ + int (*tcl_Flush) (Tcl_Channel chan); /* 146 */ + void (*reserved147)(void); + int (*tcl_GetAlias) (Tcl_Interp *interp, const char *childCmd, Tcl_Interp **targetInterpPtr, const char **targetCmdPtr, int *argcPtr, const char ***argvPtr); /* 148 */ + int (*tcl_GetAliasObj) (Tcl_Interp *interp, const char *childCmd, Tcl_Interp **targetInterpPtr, const char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 149 */ + void * (*tcl_GetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 150 */ + Tcl_Channel (*tcl_GetChannel) (Tcl_Interp *interp, const char *chanName, int *modePtr); /* 151 */ + Tcl_Size (*tcl_GetChannelBufferSize) (Tcl_Channel chan); /* 152 */ + int (*tcl_GetChannelHandle) (Tcl_Channel chan, int direction, void **handlePtr); /* 153 */ + void * (*tcl_GetChannelInstanceData) (Tcl_Channel chan); /* 154 */ + int (*tcl_GetChannelMode) (Tcl_Channel chan); /* 155 */ + const char * (*tcl_GetChannelName) (Tcl_Channel chan); /* 156 */ + int (*tcl_GetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 157 */ + const Tcl_ChannelType * (*tcl_GetChannelType) (Tcl_Channel chan); /* 158 */ + int (*tcl_GetCommandInfo) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 159 */ + const char * (*tcl_GetCommandName) (Tcl_Interp *interp, Tcl_Command command); /* 160 */ + int (*tcl_GetErrno) (void); /* 161 */ + const char * (*tcl_GetHostName) (void); /* 162 */ + int (*tcl_GetInterpPath) (Tcl_Interp *interp, Tcl_Interp *childInterp); /* 163 */ + Tcl_Interp * (*tcl_GetParent) (Tcl_Interp *interp); /* 164 */ + const char * (*tcl_GetNameOfExecutable) (void); /* 165 */ + Tcl_Obj * (*tcl_GetObjResult) (Tcl_Interp *interp); /* 166 */ + int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, void **filePtr); /* 167 */ + Tcl_PathType (*tcl_GetPathType) (const char *path); /* 168 */ + Tcl_Size (*tcl_Gets) (Tcl_Channel chan, Tcl_DString *dsPtr); /* 169 */ + Tcl_Size (*tcl_GetsObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 170 */ + int (*tcl_GetServiceMode) (void); /* 171 */ + Tcl_Interp * (*tcl_GetChild) (Tcl_Interp *interp, const char *name); /* 172 */ + Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */ + void (*reserved174)(void); + void (*reserved175)(void); + const char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */ + void (*reserved177)(void); + void (*reserved178)(void); + int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */ + int (*tcl_Init) (Tcl_Interp *interp); /* 180 */ + void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */ + int (*tcl_InputBlocked) (Tcl_Channel chan); /* 182 */ + int (*tcl_InputBuffered) (Tcl_Channel chan); /* 183 */ + int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */ + int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */ + char * (*tcl_JoinPath) (Tcl_Size argc, const char *const *argv, Tcl_DString *resultPtr); /* 186 */ + int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, void *addr, int type); /* 187 */ + void (*reserved188)(void); + Tcl_Channel (*tcl_MakeFileChannel) (void *handle, int mode); /* 189 */ + void (*reserved190)(void); + Tcl_Channel (*tcl_MakeTcpClientChannel) (void *tcpSocket); /* 191 */ + char * (*tcl_Merge) (Tcl_Size argc, const char *const *argv); /* 192 */ + Tcl_HashEntry * (*tcl_NextHashEntry) (Tcl_HashSearch *searchPtr); /* 193 */ + void (*tcl_NotifyChannel) (Tcl_Channel channel, int mask); /* 194 */ + Tcl_Obj * (*tcl_ObjGetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 195 */ + Tcl_Obj * (*tcl_ObjSetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 196 */ + Tcl_Channel (*tcl_OpenCommandChannel) (Tcl_Interp *interp, Tcl_Size argc, const char **argv, int flags); /* 197 */ + Tcl_Channel (*tcl_OpenFileChannel) (Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 198 */ + Tcl_Channel (*tcl_OpenTcpClient) (Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int flags); /* 199 */ + Tcl_Channel (*tcl_OpenTcpServer) (Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, void *callbackData); /* 200 */ + void (*tcl_Preserve) (void *data); /* 201 */ + void (*tcl_PrintDouble) (Tcl_Interp *interp, double value, char *dst); /* 202 */ + int (*tcl_PutEnv) (const char *assignment); /* 203 */ + const char * (*tcl_PosixError) (Tcl_Interp *interp); /* 204 */ + void (*tcl_QueueEvent) (Tcl_Event *evPtr, int position); /* 205 */ + Tcl_Size (*tcl_Read) (Tcl_Channel chan, char *bufPtr, Tcl_Size toRead); /* 206 */ + void (*tcl_ReapDetachedProcs) (void); /* 207 */ + int (*tcl_RecordAndEval) (Tcl_Interp *interp, const char *cmd, int flags); /* 208 */ + int (*tcl_RecordAndEvalObj) (Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 209 */ + void (*tcl_RegisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 210 */ + void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */ + Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */ + int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */ + int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */ + void (*tcl_RegExpRange) (Tcl_RegExp regexp, Tcl_Size index, const char **startPtr, const char **endPtr); /* 215 */ + void (*tcl_Release) (void *clientData); /* 216 */ + void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */ + Tcl_Size (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */ + Tcl_Size (*tcl_ScanCountedElement) (const char *src, Tcl_Size length, int *flagPtr); /* 219 */ + void (*reserved220)(void); + int (*tcl_ServiceAll) (void); /* 221 */ + int (*tcl_ServiceEvent) (int flags); /* 222 */ + void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, void *clientData); /* 223 */ + void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, Tcl_Size sz); /* 224 */ + int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */ + int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */ + void (*tcl_SetErrno) (int err); /* 227 */ + void (*tcl_SetErrorCode) (Tcl_Interp *interp, ...); /* 228 */ + void (*tcl_SetMaxBlockTime) (const Tcl_Time *timePtr); /* 229 */ + void (*reserved230)(void); + Tcl_Size (*tcl_SetRecursionLimit) (Tcl_Interp *interp, Tcl_Size depth); /* 231 */ + void (*reserved232)(void); + int (*tcl_SetServiceMode) (int mode); /* 233 */ + void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */ + void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */ + void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */ + void (*reserved237)(void); + const char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */ + const char * (*tcl_SignalId) (int sig); /* 239 */ + const char * (*tcl_SignalMsg) (int sig); /* 240 */ + void (*tcl_SourceRCFile) (Tcl_Interp *interp); /* 241 */ + int (*tclSplitList) (Tcl_Interp *interp, const char *listStr, void *argcPtr, const char ***argvPtr); /* 242 */ + void (*tclSplitPath) (const char *path, void *argcPtr, const char ***argvPtr); /* 243 */ + void (*reserved244)(void); + void (*reserved245)(void); + void (*reserved246)(void); + void (*reserved247)(void); + int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, void *clientData); /* 248 */ + char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */ + Tcl_Size (*tcl_Ungets) (Tcl_Channel chan, const char *str, Tcl_Size len, int atHead); /* 250 */ + void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */ + int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */ + void (*reserved253)(void); + int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */ + void (*reserved255)(void); + void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, void *clientData); /* 256 */ + void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */ + void (*reserved258)(void); + int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */ + int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */ + void (*reserved261)(void); + void * (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, void *prevClientData); /* 262 */ + Tcl_Size (*tcl_Write) (Tcl_Channel chan, const char *s, Tcl_Size slen); /* 263 */ + void (*tcl_WrongNumArgs) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], const char *message); /* 264 */ + int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */ + void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */ + void (*reserved267)(void); + void (*reserved268)(void); + char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */ + const char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, const char **termPtr); /* 270 */ + void (*reserved271)(void); + const char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */ + void (*reserved273)(void); + void (*reserved274)(void); + void (*reserved275)(void); + void (*reserved276)(void); + Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */ + void (*reserved278)(void); + void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */ + void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */ + Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, void *instanceData, int mask, Tcl_Channel prevChan); /* 281 */ + int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */ + Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */ + void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */ + void (*reserved285)(void); + void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */ + Tcl_Encoding (*tcl_CreateEncoding) (const Tcl_EncodingType *typePtr); /* 287 */ + void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 288 */ + void (*tcl_DeleteThreadExitHandler) (Tcl_ExitProc *proc, void *clientData); /* 289 */ + void (*reserved290)(void); + int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, Tcl_Size numBytes, int flags); /* 291 */ + int (*tcl_EvalObjv) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 292 */ + int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */ + TCL_NORETURN1 void (*tcl_ExitThread) (int status); /* 294 */ + int (*tcl_ExternalToUtf) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, Tcl_Size dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 295 */ + char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, Tcl_DString *dsPtr); /* 296 */ + void (*tcl_FinalizeThread) (void); /* 297 */ + void (*tcl_FinalizeNotifier) (void *clientData); /* 298 */ + void (*tcl_FreeEncoding) (Tcl_Encoding encoding); /* 299 */ + Tcl_ThreadId (*tcl_GetCurrentThread) (void); /* 300 */ + Tcl_Encoding (*tcl_GetEncoding) (Tcl_Interp *interp, const char *name); /* 301 */ + const char * (*tcl_GetEncodingName) (Tcl_Encoding encoding); /* 302 */ + void (*tcl_GetEncodingNames) (Tcl_Interp *interp); /* 303 */ + int (*tcl_GetIndexFromObjStruct) (Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, Tcl_Size offset, const char *msg, int flags, void *indexPtr); /* 304 */ + void * (*tcl_GetThreadData) (Tcl_ThreadDataKey *keyPtr, Tcl_Size size); /* 305 */ + Tcl_Obj * (*tcl_GetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 306 */ + void * (*tcl_InitNotifier) (void); /* 307 */ + void (*tcl_MutexLock) (Tcl_Mutex *mutexPtr); /* 308 */ + void (*tcl_MutexUnlock) (Tcl_Mutex *mutexPtr); /* 309 */ + void (*tcl_ConditionNotify) (Tcl_Condition *condPtr); /* 310 */ + void (*tcl_ConditionWait) (Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 311 */ + Tcl_Size (*tclNumUtfChars) (const char *src, Tcl_Size length); /* 312 */ + Tcl_Size (*tcl_ReadChars) (Tcl_Channel channel, Tcl_Obj *objPtr, Tcl_Size charsToRead, int appendFlag); /* 313 */ + void (*reserved314)(void); + void (*reserved315)(void); + int (*tcl_SetSystemEncoding) (Tcl_Interp *interp, const char *name); /* 316 */ + Tcl_Obj * (*tcl_SetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 317 */ + void (*tcl_ThreadAlert) (Tcl_ThreadId threadId); /* 318 */ + void (*tcl_ThreadQueueEvent) (Tcl_ThreadId threadId, Tcl_Event *evPtr, int position); /* 319 */ + int (*tcl_UniCharAtIndex) (const char *src, Tcl_Size index); /* 320 */ + int (*tcl_UniCharToLower) (int ch); /* 321 */ + int (*tcl_UniCharToTitle) (int ch); /* 322 */ + int (*tcl_UniCharToUpper) (int ch); /* 323 */ + Tcl_Size (*tcl_UniCharToUtf) (int ch, char *buf); /* 324 */ + const char * (*tclUtfAtIndex) (const char *src, Tcl_Size index); /* 325 */ + int (*tclUtfCharComplete) (const char *src, Tcl_Size length); /* 326 */ + Tcl_Size (*tcl_UtfBackslash) (const char *src, int *readPtr, char *dst); /* 327 */ + const char * (*tcl_UtfFindFirst) (const char *src, int ch); /* 328 */ + const char * (*tcl_UtfFindLast) (const char *src, int ch); /* 329 */ + const char * (*tclUtfNext) (const char *src); /* 330 */ + const char * (*tclUtfPrev) (const char *src, const char *start); /* 331 */ + int (*tcl_UtfToExternal) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, Tcl_Size dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 332 */ + char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, Tcl_DString *dsPtr); /* 333 */ + Tcl_Size (*tcl_UtfToLower) (char *src); /* 334 */ + Tcl_Size (*tcl_UtfToTitle) (char *src); /* 335 */ + Tcl_Size (*tcl_UtfToChar16) (const char *src, unsigned short *chPtr); /* 336 */ + Tcl_Size (*tcl_UtfToUpper) (char *src); /* 337 */ + Tcl_Size (*tcl_WriteChars) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 338 */ + Tcl_Size (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */ + char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */ + void (*reserved341)(void); + void (*reserved342)(void); + void (*tcl_AlertNotifier) (void *clientData); /* 343 */ + void (*tcl_ServiceModeHook) (int mode); /* 344 */ + int (*tcl_UniCharIsAlnum) (int ch); /* 345 */ + int (*tcl_UniCharIsAlpha) (int ch); /* 346 */ + int (*tcl_UniCharIsDigit) (int ch); /* 347 */ + int (*tcl_UniCharIsLower) (int ch); /* 348 */ + int (*tcl_UniCharIsSpace) (int ch); /* 349 */ + int (*tcl_UniCharIsUpper) (int ch); /* 350 */ + int (*tcl_UniCharIsWordChar) (int ch); /* 351 */ + Tcl_Size (*tcl_Char16Len) (const unsigned short *uniStr); /* 352 */ + void (*reserved353)(void); + char * (*tcl_Char16ToUtfDString) (const unsigned short *uniStr, Tcl_Size uniLength, Tcl_DString *dsPtr); /* 354 */ + unsigned short * (*tcl_UtfToChar16DString) (const char *src, Tcl_Size length, Tcl_DString *dsPtr); /* 355 */ + Tcl_RegExp (*tcl_GetRegExpFromObj) (Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 356 */ + void (*reserved357)(void); + void (*tcl_FreeParse) (Tcl_Parse *parsePtr); /* 358 */ + void (*tcl_LogCommandInfo) (Tcl_Interp *interp, const char *script, const char *command, Tcl_Size length); /* 359 */ + int (*tcl_ParseBraces) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr, int append, const char **termPtr); /* 360 */ + int (*tcl_ParseCommand) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, int nested, Tcl_Parse *parsePtr); /* 361 */ + int (*tcl_ParseExpr) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr); /* 362 */ + int (*tcl_ParseQuotedString) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr, int append, const char **termPtr); /* 363 */ + int (*tcl_ParseVarName) (Tcl_Interp *interp, const char *start, Tcl_Size numBytes, Tcl_Parse *parsePtr, int append); /* 364 */ + char * (*tcl_GetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 365 */ + int (*tcl_Chdir) (const char *dirName); /* 366 */ + int (*tcl_Access) (const char *path, int mode); /* 367 */ + int (*tcl_Stat) (const char *path, struct stat *bufPtr); /* 368 */ + int (*tcl_UtfNcmp) (const char *s1, const char *s2, size_t n); /* 369 */ + int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, size_t n); /* 370 */ + int (*tcl_StringCaseMatch) (const char *str, const char *pattern, int nocase); /* 371 */ + int (*tcl_UniCharIsControl) (int ch); /* 372 */ + int (*tcl_UniCharIsGraph) (int ch); /* 373 */ + int (*tcl_UniCharIsPrint) (int ch); /* 374 */ + int (*tcl_UniCharIsPunct) (int ch); /* 375 */ + int (*tcl_RegExpExecObj) (Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, Tcl_Size offset, Tcl_Size nmatches, int flags); /* 376 */ + void (*tcl_RegExpGetInfo) (Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 377 */ + Tcl_Obj * (*tcl_NewUnicodeObj) (const Tcl_UniChar *unicode, Tcl_Size numChars); /* 378 */ + void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, Tcl_Size numChars); /* 379 */ + Tcl_Size (*tclGetCharLength) (Tcl_Obj *objPtr); /* 380 */ + int (*tclGetUniChar) (Tcl_Obj *objPtr, Tcl_Size index); /* 381 */ + void (*reserved382)(void); + Tcl_Obj * (*tclGetRange) (Tcl_Obj *objPtr, Tcl_Size first, Tcl_Size last); /* 383 */ + void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, Tcl_Size length); /* 384 */ + int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */ + void (*tcl_SetNotifier) (const Tcl_NotifierProcs *notifierProcPtr); /* 386 */ + Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */ + int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */ + int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */ + int (*tcl_ProcObjCmd) (void *clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); /* 390 */ + void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */ + void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */ + int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, TCL_HASH_TYPE stackSize, int flags); /* 393 */ + Tcl_Size (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, Tcl_Size bytesToRead); /* 394 */ + Tcl_Size (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 395 */ + Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */ + int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */ + const char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */ + Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */ + Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */ + void (*reserved401)(void); + Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) (const Tcl_ChannelType *chanTypePtr); /* 402 */ + Tcl_DriverInputProc * (*tcl_ChannelInputProc) (const Tcl_ChannelType *chanTypePtr); /* 403 */ + Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) (const Tcl_ChannelType *chanTypePtr); /* 404 */ + void (*reserved405)(void); + Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 406 */ + Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 407 */ + Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) (const Tcl_ChannelType *chanTypePtr); /* 408 */ + Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) (const Tcl_ChannelType *chanTypePtr); /* 409 */ + Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) (const Tcl_ChannelType *chanTypePtr); /* 410 */ + Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) (const Tcl_ChannelType *chanTypePtr); /* 411 */ + int (*tcl_JoinThread) (Tcl_ThreadId threadId, int *result); /* 412 */ + int (*tcl_IsChannelShared) (Tcl_Channel channel); /* 413 */ + int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */ + void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */ + void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */ + void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */ + int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */ + void (*reserved419)(void); + void (*reserved420)(void); + void (*reserved421)(void); + void (*reserved422)(void); + void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */ + void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */ + void * (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, void *prevClientData); /* 425 */ + int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 426 */ + void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 427 */ + void * (*tcl_AttemptAlloc) (TCL_HASH_TYPE size); /* 428 */ + void * (*tcl_AttemptDbCkalloc) (TCL_HASH_TYPE size, const char *file, int line); /* 429 */ + void * (*tcl_AttemptRealloc) (void *ptr, TCL_HASH_TYPE size); /* 430 */ + void * (*tcl_AttemptDbCkrealloc) (void *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 431 */ + int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, Tcl_Size length); /* 432 */ + Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */ + Tcl_UniChar * (*tclGetUnicodeFromObj) (Tcl_Obj *objPtr, void *lengthPtr); /* 434 */ + void (*reserved435)(void); + void (*reserved436)(void); + Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */ + int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */ + int (*tcl_IsStandardChannel) (Tcl_Channel channel); /* 439 */ + int (*tcl_FSCopyFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 440 */ + int (*tcl_FSCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 441 */ + int (*tcl_FSCreateDirectory) (Tcl_Obj *pathPtr); /* 442 */ + int (*tcl_FSDeleteFile) (Tcl_Obj *pathPtr); /* 443 */ + int (*tcl_FSLoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *sym1, const char *sym2, Tcl_LibraryInitProc **proc1Ptr, Tcl_LibraryInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); /* 444 */ + int (*tcl_FSMatchInDirectory) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 445 */ + Tcl_Obj * (*tcl_FSLink) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 446 */ + int (*tcl_FSRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 447 */ + int (*tcl_FSRenameFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 448 */ + int (*tcl_FSLstat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 449 */ + int (*tcl_FSUtime) (Tcl_Obj *pathPtr, struct utimbuf *tval); /* 450 */ + int (*tcl_FSFileAttrsGet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 451 */ + int (*tcl_FSFileAttrsSet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 452 */ + const char *const * (*tcl_FSFileAttrStrings) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 453 */ + int (*tcl_FSStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 454 */ + int (*tcl_FSAccess) (Tcl_Obj *pathPtr, int mode); /* 455 */ + Tcl_Channel (*tcl_FSOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 456 */ + Tcl_Obj * (*tcl_FSGetCwd) (Tcl_Interp *interp); /* 457 */ + int (*tcl_FSChdir) (Tcl_Obj *pathPtr); /* 458 */ + int (*tcl_FSConvertToPathType) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 459 */ + Tcl_Obj * (*tcl_FSJoinPath) (Tcl_Obj *listObj, Tcl_Size elements); /* 460 */ + Tcl_Obj * (*tclFSSplitPath) (Tcl_Obj *pathPtr, void *lenPtr); /* 461 */ + int (*tcl_FSEqualPaths) (Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 462 */ + Tcl_Obj * (*tcl_FSGetNormalizedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 463 */ + Tcl_Obj * (*tcl_FSJoinToPath) (Tcl_Obj *pathPtr, Tcl_Size objc, Tcl_Obj *const objv[]); /* 464 */ + void * (*tcl_FSGetInternalRep) (Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 465 */ + Tcl_Obj * (*tcl_FSGetTranslatedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 466 */ + int (*tcl_FSEvalFile) (Tcl_Interp *interp, Tcl_Obj *fileName); /* 467 */ + Tcl_Obj * (*tcl_FSNewNativePath) (const Tcl_Filesystem *fromFilesystem, void *clientData); /* 468 */ + const void * (*tcl_FSGetNativePath) (Tcl_Obj *pathPtr); /* 469 */ + Tcl_Obj * (*tcl_FSFileSystemInfo) (Tcl_Obj *pathPtr); /* 470 */ + Tcl_Obj * (*tcl_FSPathSeparator) (Tcl_Obj *pathPtr); /* 471 */ + Tcl_Obj * (*tcl_FSListVolumes) (void); /* 472 */ + int (*tcl_FSRegister) (void *clientData, const Tcl_Filesystem *fsPtr); /* 473 */ + int (*tcl_FSUnregister) (const Tcl_Filesystem *fsPtr); /* 474 */ + void * (*tcl_FSData) (const Tcl_Filesystem *fsPtr); /* 475 */ + const char * (*tcl_FSGetTranslatedStringPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 476 */ + const Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) (Tcl_Obj *pathPtr); /* 477 */ + Tcl_PathType (*tcl_FSGetPathType) (Tcl_Obj *pathPtr); /* 478 */ + int (*tcl_OutputBuffered) (Tcl_Channel chan); /* 479 */ + void (*tcl_FSMountsChanged) (const Tcl_Filesystem *fsPtr); /* 480 */ + int (*tcl_EvalTokensStandard) (Tcl_Interp *interp, Tcl_Token *tokenPtr, Tcl_Size count); /* 481 */ + void (*tcl_GetTime) (Tcl_Time *timeBuf); /* 482 */ + Tcl_Trace (*tcl_CreateObjTrace) (Tcl_Interp *interp, Tcl_Size level, int flags, Tcl_CmdObjTraceProc *objProc, void *clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 483 */ + int (*tcl_GetCommandInfoFromToken) (Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 484 */ + int (*tcl_SetCommandInfoFromToken) (Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 485 */ + Tcl_Obj * (*tcl_DbNewWideIntObj) (Tcl_WideInt wideValue, const char *file, int line); /* 486 */ + int (*tcl_GetWideIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 487 */ + Tcl_Obj * (*tcl_NewWideIntObj) (Tcl_WideInt wideValue); /* 488 */ + void (*tcl_SetWideIntObj) (Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 489 */ + Tcl_StatBuf * (*tcl_AllocStatBuf) (void); /* 490 */ + long long (*tcl_Seek) (Tcl_Channel chan, long long offset, int mode); /* 491 */ + long long (*tcl_Tell) (Tcl_Channel chan); /* 492 */ + Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 493 */ + int (*tcl_DictObjPut) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 494 */ + int (*tcl_DictObjGet) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 495 */ + int (*tcl_DictObjRemove) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 496 */ + int (*tclDictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, void *sizePtr); /* 497 */ + int (*tcl_DictObjFirst) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 498 */ + void (*tcl_DictObjNext) (Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */ + void (*tcl_DictObjDone) (Tcl_DictSearch *searchPtr); /* 500 */ + int (*tcl_DictObjPutKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Size keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 501 */ + int (*tcl_DictObjRemoveKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Size keyc, Tcl_Obj *const *keyv); /* 502 */ + Tcl_Obj * (*tcl_NewDictObj) (void); /* 503 */ + Tcl_Obj * (*tcl_DbNewDictObj) (const char *file, int line); /* 504 */ + void (*tcl_RegisterConfig) (Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 505 */ + Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, const char *name, void *clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 506 */ + void (*tcl_DeleteNamespace) (Tcl_Namespace *nsPtr); /* 507 */ + int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 508 */ + int (*tcl_Export) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 509 */ + int (*tcl_Import) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 510 */ + int (*tcl_ForgetImport) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 511 */ + Tcl_Namespace * (*tcl_GetCurrentNamespace) (Tcl_Interp *interp); /* 512 */ + Tcl_Namespace * (*tcl_GetGlobalNamespace) (Tcl_Interp *interp); /* 513 */ + Tcl_Namespace * (*tcl_FindNamespace) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 514 */ + Tcl_Command (*tcl_FindCommand) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */ + Tcl_Command (*tcl_GetCommandFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 516 */ + void (*tcl_GetCommandFullName) (Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 517 */ + int (*tcl_FSEvalFileEx) (Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 518 */ + void (*reserved519)(void); + void (*tcl_LimitAddHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, void *clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 520 */ + void (*tcl_LimitRemoveHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, void *clientData); /* 521 */ + int (*tcl_LimitReady) (Tcl_Interp *interp); /* 522 */ + int (*tcl_LimitCheck) (Tcl_Interp *interp); /* 523 */ + int (*tcl_LimitExceeded) (Tcl_Interp *interp); /* 524 */ + void (*tcl_LimitSetCommands) (Tcl_Interp *interp, Tcl_Size commandLimit); /* 525 */ + void (*tcl_LimitSetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 526 */ + void (*tcl_LimitSetGranularity) (Tcl_Interp *interp, int type, int granularity); /* 527 */ + int (*tcl_LimitTypeEnabled) (Tcl_Interp *interp, int type); /* 528 */ + int (*tcl_LimitTypeExceeded) (Tcl_Interp *interp, int type); /* 529 */ + void (*tcl_LimitTypeSet) (Tcl_Interp *interp, int type); /* 530 */ + void (*tcl_LimitTypeReset) (Tcl_Interp *interp, int type); /* 531 */ + int (*tcl_LimitGetCommands) (Tcl_Interp *interp); /* 532 */ + void (*tcl_LimitGetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 533 */ + int (*tcl_LimitGetGranularity) (Tcl_Interp *interp, int type); /* 534 */ + Tcl_InterpState (*tcl_SaveInterpState) (Tcl_Interp *interp, int status); /* 535 */ + int (*tcl_RestoreInterpState) (Tcl_Interp *interp, Tcl_InterpState state); /* 536 */ + void (*tcl_DiscardInterpState) (Tcl_InterpState state); /* 537 */ + int (*tcl_SetReturnOptions) (Tcl_Interp *interp, Tcl_Obj *options); /* 538 */ + Tcl_Obj * (*tcl_GetReturnOptions) (Tcl_Interp *interp, int result); /* 539 */ + int (*tcl_IsEnsemble) (Tcl_Command token); /* 540 */ + Tcl_Command (*tcl_CreateEnsemble) (Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 541 */ + Tcl_Command (*tcl_FindEnsemble) (Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 542 */ + int (*tcl_SetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 543 */ + int (*tcl_SetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 544 */ + int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */ + int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */ + int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */ + int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */ + int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */ + int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */ + int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */ + void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, void *clientData); /* 552 */ + void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, void **clientData); /* 553 */ + Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */ + Tcl_Obj * (*tcl_NewBignumObj) (void *value); /* 555 */ + Tcl_Obj * (*tcl_DbNewBignumObj) (void *value, const char *file, int line); /* 556 */ + void (*tcl_SetBignumObj) (Tcl_Obj *obj, void *value); /* 557 */ + int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, void *value); /* 558 */ + int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, void *value); /* 559 */ + int (*tcl_TruncateChannel) (Tcl_Channel chan, long long length); /* 560 */ + Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) (const Tcl_ChannelType *chanTypePtr); /* 561 */ + void (*tcl_SetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj *msg); /* 562 */ + void (*tcl_GetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj **msg); /* 563 */ + void (*tcl_SetChannelError) (Tcl_Channel chan, Tcl_Obj *msg); /* 564 */ + void (*tcl_GetChannelError) (Tcl_Channel chan, Tcl_Obj **msg); /* 565 */ + int (*tcl_InitBignumFromDouble) (Tcl_Interp *interp, double initval, void *toInit); /* 566 */ + Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 567 */ + int (*tcl_SetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 568 */ + int (*tcl_GetEncodingFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 569 */ + Tcl_Obj * (*tcl_GetEncodingSearchPath) (void); /* 570 */ + int (*tcl_SetEncodingSearchPath) (Tcl_Obj *searchPath); /* 571 */ + const char * (*tcl_GetEncodingNameFromEnvironment) (Tcl_DString *bufPtr); /* 572 */ + int (*tcl_PkgRequireProc) (Tcl_Interp *interp, const char *name, Tcl_Size objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 573 */ + void (*tcl_AppendObjToErrorInfo) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 574 */ + void (*tcl_AppendLimitedToObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length, Tcl_Size limit, const char *ellipsis); /* 575 */ + Tcl_Obj * (*tcl_Format) (Tcl_Interp *interp, const char *format, Tcl_Size objc, Tcl_Obj *const objv[]); /* 576 */ + int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, Tcl_Size objc, Tcl_Obj *const objv[]); /* 577 */ + Tcl_Obj * (*tcl_ObjPrintf) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 578 */ + void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 579 */ + int (*tcl_CancelEval) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr, void *clientData, int flags); /* 580 */ + int (*tcl_Canceled) (Tcl_Interp *interp, int flags); /* 581 */ + int (*tcl_CreatePipe) (Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 582 */ + Tcl_Command (*tcl_NRCreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 583 */ + int (*tcl_NREvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 584 */ + int (*tcl_NREvalObjv) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 585 */ + int (*tcl_NRCmdSwap) (Tcl_Interp *interp, Tcl_Command cmd, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 586 */ + void (*tcl_NRAddCallback) (Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, void *data0, void *data1, void *data2, void *data3); /* 587 */ + int (*tcl_NRCallObjProc) (Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, void *clientData, Tcl_Size objc, Tcl_Obj *const objv[]); /* 588 */ + unsigned (*tcl_GetFSDeviceFromStat) (const Tcl_StatBuf *statPtr); /* 589 */ + unsigned (*tcl_GetFSInodeFromStat) (const Tcl_StatBuf *statPtr); /* 590 */ + unsigned (*tcl_GetModeFromStat) (const Tcl_StatBuf *statPtr); /* 591 */ + int (*tcl_GetLinkCountFromStat) (const Tcl_StatBuf *statPtr); /* 592 */ + int (*tcl_GetUserIdFromStat) (const Tcl_StatBuf *statPtr); /* 593 */ + int (*tcl_GetGroupIdFromStat) (const Tcl_StatBuf *statPtr); /* 594 */ + int (*tcl_GetDeviceTypeFromStat) (const Tcl_StatBuf *statPtr); /* 595 */ + long long (*tcl_GetAccessTimeFromStat) (const Tcl_StatBuf *statPtr); /* 596 */ + long long (*tcl_GetModificationTimeFromStat) (const Tcl_StatBuf *statPtr); /* 597 */ + long long (*tcl_GetChangeTimeFromStat) (const Tcl_StatBuf *statPtr); /* 598 */ + unsigned long long (*tcl_GetSizeFromStat) (const Tcl_StatBuf *statPtr); /* 599 */ + unsigned long long (*tcl_GetBlocksFromStat) (const Tcl_StatBuf *statPtr); /* 600 */ + unsigned (*tcl_GetBlockSizeFromStat) (const Tcl_StatBuf *statPtr); /* 601 */ + int (*tcl_SetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 602 */ + int (*tcl_GetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 603 */ + int (*tclParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, void *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 604 */ + int (*tcl_GetErrorLine) (Tcl_Interp *interp); /* 605 */ + void (*tcl_SetErrorLine) (Tcl_Interp *interp, int lineNum); /* 606 */ + void (*tcl_TransferResult) (Tcl_Interp *sourceInterp, int code, Tcl_Interp *targetInterp); /* 607 */ + int (*tcl_InterpActive) (Tcl_Interp *interp); /* 608 */ + void (*tcl_BackgroundException) (Tcl_Interp *interp, int code); /* 609 */ + int (*tcl_ZlibDeflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 610 */ + int (*tcl_ZlibInflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, Tcl_Size buffersize, Tcl_Obj *gzipHeaderDictObj); /* 611 */ + unsigned int (*tcl_ZlibCRC32) (unsigned int crc, const unsigned char *buf, Tcl_Size len); /* 612 */ + unsigned int (*tcl_ZlibAdler32) (unsigned int adler, const unsigned char *buf, Tcl_Size len); /* 613 */ + int (*tcl_ZlibStreamInit) (Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 614 */ + Tcl_Obj * (*tcl_ZlibStreamGetCommandName) (Tcl_ZlibStream zshandle); /* 615 */ + int (*tcl_ZlibStreamEof) (Tcl_ZlibStream zshandle); /* 616 */ + int (*tcl_ZlibStreamChecksum) (Tcl_ZlibStream zshandle); /* 617 */ + int (*tcl_ZlibStreamPut) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 618 */ + int (*tcl_ZlibStreamGet) (Tcl_ZlibStream zshandle, Tcl_Obj *data, Tcl_Size count); /* 619 */ + int (*tcl_ZlibStreamClose) (Tcl_ZlibStream zshandle); /* 620 */ + int (*tcl_ZlibStreamReset) (Tcl_ZlibStream zshandle); /* 621 */ + void (*tcl_SetStartupScript) (Tcl_Obj *path, const char *encoding); /* 622 */ + Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */ + int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */ + int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */ + int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */ + int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */ + void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */ + int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */ + void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */ + Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned int flags, int backlog, Tcl_TcpAcceptProc *acceptProc, void *callbackData); /* 631 */ + int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *zipname, const char *mountPoint, const char *passwd); /* 632 */ + int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *mountPoint); /* 633 */ + Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */ + int (*tclZipfs_MountBuffer) (Tcl_Interp *interp, const void *data, size_t datalen, const char *mountPoint, int copy); /* 635 */ + void (*tcl_FreeInternalRep) (Tcl_Obj *objPtr); /* 636 */ + char * (*tcl_InitStringRep) (Tcl_Obj *objPtr, const char *bytes, TCL_HASH_TYPE numBytes); /* 637 */ + Tcl_ObjInternalRep * (*tcl_FetchInternalRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 638 */ + void (*tcl_StoreInternalRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr, const Tcl_ObjInternalRep *irPtr); /* 639 */ + int (*tcl_HasStringRep) (Tcl_Obj *objPtr); /* 640 */ + void (*tcl_IncrRefCount) (Tcl_Obj *objPtr); /* 641 */ + void (*tcl_DecrRefCount) (Tcl_Obj *objPtr); /* 642 */ + int (*tcl_IsShared) (Tcl_Obj *objPtr); /* 643 */ + int (*tcl_LinkArray) (Tcl_Interp *interp, const char *varName, void *addr, int type, Tcl_Size size); /* 644 */ + int (*tcl_GetIntForIndex) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Size endValue, Tcl_Size *indexPtr); /* 645 */ + Tcl_Size (*tcl_UtfToUniChar) (const char *src, int *chPtr); /* 646 */ + char * (*tcl_UniCharToUtfDString) (const int *uniStr, Tcl_Size uniLength, Tcl_DString *dsPtr); /* 647 */ + int * (*tcl_UtfToUniCharDString) (const char *src, Tcl_Size length, Tcl_DString *dsPtr); /* 648 */ + unsigned char * (*tclGetBytesFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, void *numBytesPtr); /* 649 */ + unsigned char * (*tcl_GetBytesFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Size *numBytesPtr); /* 650 */ + char * (*tcl_GetStringFromObj) (Tcl_Obj *objPtr, Tcl_Size *lengthPtr); /* 651 */ + Tcl_UniChar * (*tcl_GetUnicodeFromObj) (Tcl_Obj *objPtr, Tcl_Size *lengthPtr); /* 652 */ + int (*tcl_GetSizeIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Size *sizePtr); /* 653 */ + int (*tcl_UtfCharComplete) (const char *src, Tcl_Size length); /* 654 */ + const char * (*tcl_UtfNext) (const char *src); /* 655 */ + const char * (*tcl_UtfPrev) (const char *src, const char *start); /* 656 */ + int (*tcl_UniCharIsUnicode) (int ch); /* 657 */ + int (*tcl_ExternalToUtfDStringEx) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_DString *dsPtr, Tcl_Size *errorLocationPtr); /* 658 */ + int (*tcl_UtfToExternalDStringEx) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_DString *dsPtr, Tcl_Size *errorLocationPtr); /* 659 */ + int (*tcl_AsyncMarkFromSignal) (Tcl_AsyncHandler async, int sigNumber); /* 660 */ + int (*tcl_ListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size *objcPtr, Tcl_Obj ***objvPtr); /* 661 */ + int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size *lengthPtr); /* 662 */ + int (*tcl_DictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Size *sizePtr); /* 663 */ + int (*tcl_SplitList) (Tcl_Interp *interp, const char *listStr, Tcl_Size *argcPtr, const char ***argvPtr); /* 664 */ + void (*tcl_SplitPath) (const char *path, Tcl_Size *argcPtr, const char ***argvPtr); /* 665 */ + Tcl_Obj * (*tcl_FSSplitPath) (Tcl_Obj *pathPtr, Tcl_Size *lenPtr); /* 666 */ + int (*tcl_ParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, Tcl_Size *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 667 */ + Tcl_Size (*tcl_UniCharLen) (const int *uniStr); /* 668 */ + Tcl_Size (*tcl_NumUtfChars) (const char *src, Tcl_Size length); /* 669 */ + Tcl_Size (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 670 */ + const char * (*tcl_UtfAtIndex) (const char *src, Tcl_Size index); /* 671 */ + Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, Tcl_Size first, Tcl_Size last); /* 672 */ + int (*tcl_GetUniChar) (Tcl_Obj *objPtr, Tcl_Size index); /* 673 */ + int (*tcl_GetBool) (Tcl_Interp *interp, const char *src, int flags, char *charPtr); /* 674 */ + int (*tcl_GetBoolFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, char *charPtr); /* 675 */ + Tcl_Command (*tcl_CreateObjCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 676 */ + Tcl_Trace (*tcl_CreateObjTrace2) (Tcl_Interp *interp, Tcl_Size level, int flags, Tcl_CmdObjTraceProc2 *objProc2, void *clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 677 */ + Tcl_Command (*tcl_NRCreateCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc, Tcl_ObjCmdProc2 *nreProc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 678 */ + int (*tcl_NRCallObjProc2) (Tcl_Interp *interp, Tcl_ObjCmdProc2 *objProc2, void *clientData, Tcl_Size objc, Tcl_Obj *const objv[]); /* 679 */ + int (*tcl_GetNumberFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, void **clientDataPtr, int *typePtr); /* 680 */ + int (*tcl_GetNumber) (Tcl_Interp *interp, const char *bytes, Tcl_Size numBytes, void **clientDataPtr, int *typePtr); /* 681 */ + int (*tcl_RemoveChannelMode) (Tcl_Interp *interp, Tcl_Channel chan, int mode); /* 682 */ + Tcl_Size (*tcl_GetEncodingNulLength) (Tcl_Encoding encoding); /* 683 */ + int (*tcl_GetWideUIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr); /* 684 */ + Tcl_Obj * (*tcl_DStringToObj) (Tcl_DString *dsPtr); /* 685 */ + void (*reserved686)(void); + void (*reserved687)(void); + void (*tclUnusedStubEntry) (void); /* 688 */ +} TclStubs; + +extern const TclStubs *tclStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +#define Tcl_PkgProvideEx \ + (tclStubsPtr->tcl_PkgProvideEx) /* 0 */ +#define Tcl_PkgRequireEx \ + (tclStubsPtr->tcl_PkgRequireEx) /* 1 */ +#define Tcl_Panic \ + (tclStubsPtr->tcl_Panic) /* 2 */ +#define Tcl_Alloc \ + (tclStubsPtr->tcl_Alloc) /* 3 */ +#define Tcl_Free \ + (tclStubsPtr->tcl_Free) /* 4 */ +#define Tcl_Realloc \ + (tclStubsPtr->tcl_Realloc) /* 5 */ +#define Tcl_DbCkalloc \ + (tclStubsPtr->tcl_DbCkalloc) /* 6 */ +#define Tcl_DbCkfree \ + (tclStubsPtr->tcl_DbCkfree) /* 7 */ +#define Tcl_DbCkrealloc \ + (tclStubsPtr->tcl_DbCkrealloc) /* 8 */ +#define Tcl_CreateFileHandler \ + (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ +#define Tcl_DeleteFileHandler \ + (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ +#define Tcl_SetTimer \ + (tclStubsPtr->tcl_SetTimer) /* 11 */ +#define Tcl_Sleep \ + (tclStubsPtr->tcl_Sleep) /* 12 */ +#define Tcl_WaitForEvent \ + (tclStubsPtr->tcl_WaitForEvent) /* 13 */ +#define Tcl_AppendAllObjTypes \ + (tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */ +#define Tcl_AppendStringsToObj \ + (tclStubsPtr->tcl_AppendStringsToObj) /* 15 */ +#define Tcl_AppendToObj \ + (tclStubsPtr->tcl_AppendToObj) /* 16 */ +#define Tcl_ConcatObj \ + (tclStubsPtr->tcl_ConcatObj) /* 17 */ +#define Tcl_ConvertToType \ + (tclStubsPtr->tcl_ConvertToType) /* 18 */ +#define Tcl_DbDecrRefCount \ + (tclStubsPtr->tcl_DbDecrRefCount) /* 19 */ +#define Tcl_DbIncrRefCount \ + (tclStubsPtr->tcl_DbIncrRefCount) /* 20 */ +#define Tcl_DbIsShared \ + (tclStubsPtr->tcl_DbIsShared) /* 21 */ +/* Slot 22 is reserved */ +#define Tcl_DbNewByteArrayObj \ + (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ +#define Tcl_DbNewDoubleObj \ + (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ +#define Tcl_DbNewListObj \ + (tclStubsPtr->tcl_DbNewListObj) /* 25 */ +/* Slot 26 is reserved */ +#define Tcl_DbNewObj \ + (tclStubsPtr->tcl_DbNewObj) /* 27 */ +#define Tcl_DbNewStringObj \ + (tclStubsPtr->tcl_DbNewStringObj) /* 28 */ +#define Tcl_DuplicateObj \ + (tclStubsPtr->tcl_DuplicateObj) /* 29 */ +#define TclFreeObj \ + (tclStubsPtr->tclFreeObj) /* 30 */ +#define Tcl_GetBoolean \ + (tclStubsPtr->tcl_GetBoolean) /* 31 */ +#define Tcl_GetBooleanFromObj \ + (tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */ +#define Tcl_GetByteArrayFromObj \ + (tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */ +#define Tcl_GetDouble \ + (tclStubsPtr->tcl_GetDouble) /* 34 */ +#define Tcl_GetDoubleFromObj \ + (tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */ +/* Slot 36 is reserved */ +#define Tcl_GetInt \ + (tclStubsPtr->tcl_GetInt) /* 37 */ +#define Tcl_GetIntFromObj \ + (tclStubsPtr->tcl_GetIntFromObj) /* 38 */ +#define Tcl_GetLongFromObj \ + (tclStubsPtr->tcl_GetLongFromObj) /* 39 */ +#define Tcl_GetObjType \ + (tclStubsPtr->tcl_GetObjType) /* 40 */ +#define TclGetStringFromObj \ + (tclStubsPtr->tclGetStringFromObj) /* 41 */ +#define Tcl_InvalidateStringRep \ + (tclStubsPtr->tcl_InvalidateStringRep) /* 42 */ +#define Tcl_ListObjAppendList \ + (tclStubsPtr->tcl_ListObjAppendList) /* 43 */ +#define Tcl_ListObjAppendElement \ + (tclStubsPtr->tcl_ListObjAppendElement) /* 44 */ +#define TclListObjGetElements \ + (tclStubsPtr->tclListObjGetElements) /* 45 */ +#define Tcl_ListObjIndex \ + (tclStubsPtr->tcl_ListObjIndex) /* 46 */ +#define TclListObjLength \ + (tclStubsPtr->tclListObjLength) /* 47 */ +#define Tcl_ListObjReplace \ + (tclStubsPtr->tcl_ListObjReplace) /* 48 */ +/* Slot 49 is reserved */ +#define Tcl_NewByteArrayObj \ + (tclStubsPtr->tcl_NewByteArrayObj) /* 50 */ +#define Tcl_NewDoubleObj \ + (tclStubsPtr->tcl_NewDoubleObj) /* 51 */ +/* Slot 52 is reserved */ +#define Tcl_NewListObj \ + (tclStubsPtr->tcl_NewListObj) /* 53 */ +/* Slot 54 is reserved */ +#define Tcl_NewObj \ + (tclStubsPtr->tcl_NewObj) /* 55 */ +#define Tcl_NewStringObj \ + (tclStubsPtr->tcl_NewStringObj) /* 56 */ +/* Slot 57 is reserved */ +#define Tcl_SetByteArrayLength \ + (tclStubsPtr->tcl_SetByteArrayLength) /* 58 */ +#define Tcl_SetByteArrayObj \ + (tclStubsPtr->tcl_SetByteArrayObj) /* 59 */ +#define Tcl_SetDoubleObj \ + (tclStubsPtr->tcl_SetDoubleObj) /* 60 */ +/* Slot 61 is reserved */ +#define Tcl_SetListObj \ + (tclStubsPtr->tcl_SetListObj) /* 62 */ +/* Slot 63 is reserved */ +#define Tcl_SetObjLength \ + (tclStubsPtr->tcl_SetObjLength) /* 64 */ +#define Tcl_SetStringObj \ + (tclStubsPtr->tcl_SetStringObj) /* 65 */ +/* Slot 66 is reserved */ +/* Slot 67 is reserved */ +#define Tcl_AllowExceptions \ + (tclStubsPtr->tcl_AllowExceptions) /* 68 */ +#define Tcl_AppendElement \ + (tclStubsPtr->tcl_AppendElement) /* 69 */ +#define Tcl_AppendResult \ + (tclStubsPtr->tcl_AppendResult) /* 70 */ +#define Tcl_AsyncCreate \ + (tclStubsPtr->tcl_AsyncCreate) /* 71 */ +#define Tcl_AsyncDelete \ + (tclStubsPtr->tcl_AsyncDelete) /* 72 */ +#define Tcl_AsyncInvoke \ + (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ +#define Tcl_AsyncMark \ + (tclStubsPtr->tcl_AsyncMark) /* 74 */ +#define Tcl_AsyncReady \ + (tclStubsPtr->tcl_AsyncReady) /* 75 */ +/* Slot 76 is reserved */ +/* Slot 77 is reserved */ +#define Tcl_BadChannelOption \ + (tclStubsPtr->tcl_BadChannelOption) /* 78 */ +#define Tcl_CallWhenDeleted \ + (tclStubsPtr->tcl_CallWhenDeleted) /* 79 */ +#define Tcl_CancelIdleCall \ + (tclStubsPtr->tcl_CancelIdleCall) /* 80 */ +#define Tcl_Close \ + (tclStubsPtr->tcl_Close) /* 81 */ +#define Tcl_CommandComplete \ + (tclStubsPtr->tcl_CommandComplete) /* 82 */ +#define Tcl_Concat \ + (tclStubsPtr->tcl_Concat) /* 83 */ +#define Tcl_ConvertElement \ + (tclStubsPtr->tcl_ConvertElement) /* 84 */ +#define Tcl_ConvertCountedElement \ + (tclStubsPtr->tcl_ConvertCountedElement) /* 85 */ +#define Tcl_CreateAlias \ + (tclStubsPtr->tcl_CreateAlias) /* 86 */ +#define Tcl_CreateAliasObj \ + (tclStubsPtr->tcl_CreateAliasObj) /* 87 */ +#define Tcl_CreateChannel \ + (tclStubsPtr->tcl_CreateChannel) /* 88 */ +#define Tcl_CreateChannelHandler \ + (tclStubsPtr->tcl_CreateChannelHandler) /* 89 */ +#define Tcl_CreateCloseHandler \ + (tclStubsPtr->tcl_CreateCloseHandler) /* 90 */ +#define Tcl_CreateCommand \ + (tclStubsPtr->tcl_CreateCommand) /* 91 */ +#define Tcl_CreateEventSource \ + (tclStubsPtr->tcl_CreateEventSource) /* 92 */ +#define Tcl_CreateExitHandler \ + (tclStubsPtr->tcl_CreateExitHandler) /* 93 */ +#define Tcl_CreateInterp \ + (tclStubsPtr->tcl_CreateInterp) /* 94 */ +/* Slot 95 is reserved */ +#define Tcl_CreateObjCommand \ + (tclStubsPtr->tcl_CreateObjCommand) /* 96 */ +#define Tcl_CreateChild \ + (tclStubsPtr->tcl_CreateChild) /* 97 */ +#define Tcl_CreateTimerHandler \ + (tclStubsPtr->tcl_CreateTimerHandler) /* 98 */ +#define Tcl_CreateTrace \ + (tclStubsPtr->tcl_CreateTrace) /* 99 */ +#define Tcl_DeleteAssocData \ + (tclStubsPtr->tcl_DeleteAssocData) /* 100 */ +#define Tcl_DeleteChannelHandler \ + (tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */ +#define Tcl_DeleteCloseHandler \ + (tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */ +#define Tcl_DeleteCommand \ + (tclStubsPtr->tcl_DeleteCommand) /* 103 */ +#define Tcl_DeleteCommandFromToken \ + (tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */ +#define Tcl_DeleteEvents \ + (tclStubsPtr->tcl_DeleteEvents) /* 105 */ +#define Tcl_DeleteEventSource \ + (tclStubsPtr->tcl_DeleteEventSource) /* 106 */ +#define Tcl_DeleteExitHandler \ + (tclStubsPtr->tcl_DeleteExitHandler) /* 107 */ +#define Tcl_DeleteHashEntry \ + (tclStubsPtr->tcl_DeleteHashEntry) /* 108 */ +#define Tcl_DeleteHashTable \ + (tclStubsPtr->tcl_DeleteHashTable) /* 109 */ +#define Tcl_DeleteInterp \ + (tclStubsPtr->tcl_DeleteInterp) /* 110 */ +#define Tcl_DetachPids \ + (tclStubsPtr->tcl_DetachPids) /* 111 */ +#define Tcl_DeleteTimerHandler \ + (tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */ +#define Tcl_DeleteTrace \ + (tclStubsPtr->tcl_DeleteTrace) /* 113 */ +#define Tcl_DontCallWhenDeleted \ + (tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */ +#define Tcl_DoOneEvent \ + (tclStubsPtr->tcl_DoOneEvent) /* 115 */ +#define Tcl_DoWhenIdle \ + (tclStubsPtr->tcl_DoWhenIdle) /* 116 */ +#define Tcl_DStringAppend \ + (tclStubsPtr->tcl_DStringAppend) /* 117 */ +#define Tcl_DStringAppendElement \ + (tclStubsPtr->tcl_DStringAppendElement) /* 118 */ +#define Tcl_DStringEndSublist \ + (tclStubsPtr->tcl_DStringEndSublist) /* 119 */ +#define Tcl_DStringFree \ + (tclStubsPtr->tcl_DStringFree) /* 120 */ +#define Tcl_DStringGetResult \ + (tclStubsPtr->tcl_DStringGetResult) /* 121 */ +#define Tcl_DStringInit \ + (tclStubsPtr->tcl_DStringInit) /* 122 */ +#define Tcl_DStringResult \ + (tclStubsPtr->tcl_DStringResult) /* 123 */ +#define Tcl_DStringSetLength \ + (tclStubsPtr->tcl_DStringSetLength) /* 124 */ +#define Tcl_DStringStartSublist \ + (tclStubsPtr->tcl_DStringStartSublist) /* 125 */ +#define Tcl_Eof \ + (tclStubsPtr->tcl_Eof) /* 126 */ +#define Tcl_ErrnoId \ + (tclStubsPtr->tcl_ErrnoId) /* 127 */ +#define Tcl_ErrnoMsg \ + (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ +/* Slot 129 is reserved */ +#define Tcl_EvalFile \ + (tclStubsPtr->tcl_EvalFile) /* 130 */ +/* Slot 131 is reserved */ +#define Tcl_EventuallyFree \ + (tclStubsPtr->tcl_EventuallyFree) /* 132 */ +#define Tcl_Exit \ + (tclStubsPtr->tcl_Exit) /* 133 */ +#define Tcl_ExposeCommand \ + (tclStubsPtr->tcl_ExposeCommand) /* 134 */ +#define Tcl_ExprBoolean \ + (tclStubsPtr->tcl_ExprBoolean) /* 135 */ +#define Tcl_ExprBooleanObj \ + (tclStubsPtr->tcl_ExprBooleanObj) /* 136 */ +#define Tcl_ExprDouble \ + (tclStubsPtr->tcl_ExprDouble) /* 137 */ +#define Tcl_ExprDoubleObj \ + (tclStubsPtr->tcl_ExprDoubleObj) /* 138 */ +#define Tcl_ExprLong \ + (tclStubsPtr->tcl_ExprLong) /* 139 */ +#define Tcl_ExprLongObj \ + (tclStubsPtr->tcl_ExprLongObj) /* 140 */ +#define Tcl_ExprObj \ + (tclStubsPtr->tcl_ExprObj) /* 141 */ +#define Tcl_ExprString \ + (tclStubsPtr->tcl_ExprString) /* 142 */ +#define Tcl_Finalize \ + (tclStubsPtr->tcl_Finalize) /* 143 */ +/* Slot 144 is reserved */ +#define Tcl_FirstHashEntry \ + (tclStubsPtr->tcl_FirstHashEntry) /* 145 */ +#define Tcl_Flush \ + (tclStubsPtr->tcl_Flush) /* 146 */ +/* Slot 147 is reserved */ +#define Tcl_GetAlias \ + (tclStubsPtr->tcl_GetAlias) /* 148 */ +#define Tcl_GetAliasObj \ + (tclStubsPtr->tcl_GetAliasObj) /* 149 */ +#define Tcl_GetAssocData \ + (tclStubsPtr->tcl_GetAssocData) /* 150 */ +#define Tcl_GetChannel \ + (tclStubsPtr->tcl_GetChannel) /* 151 */ +#define Tcl_GetChannelBufferSize \ + (tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */ +#define Tcl_GetChannelHandle \ + (tclStubsPtr->tcl_GetChannelHandle) /* 153 */ +#define Tcl_GetChannelInstanceData \ + (tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */ +#define Tcl_GetChannelMode \ + (tclStubsPtr->tcl_GetChannelMode) /* 155 */ +#define Tcl_GetChannelName \ + (tclStubsPtr->tcl_GetChannelName) /* 156 */ +#define Tcl_GetChannelOption \ + (tclStubsPtr->tcl_GetChannelOption) /* 157 */ +#define Tcl_GetChannelType \ + (tclStubsPtr->tcl_GetChannelType) /* 158 */ +#define Tcl_GetCommandInfo \ + (tclStubsPtr->tcl_GetCommandInfo) /* 159 */ +#define Tcl_GetCommandName \ + (tclStubsPtr->tcl_GetCommandName) /* 160 */ +#define Tcl_GetErrno \ + (tclStubsPtr->tcl_GetErrno) /* 161 */ +#define Tcl_GetHostName \ + (tclStubsPtr->tcl_GetHostName) /* 162 */ +#define Tcl_GetInterpPath \ + (tclStubsPtr->tcl_GetInterpPath) /* 163 */ +#define Tcl_GetParent \ + (tclStubsPtr->tcl_GetParent) /* 164 */ +#define Tcl_GetNameOfExecutable \ + (tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */ +#define Tcl_GetObjResult \ + (tclStubsPtr->tcl_GetObjResult) /* 166 */ +#define Tcl_GetOpenFile \ + (tclStubsPtr->tcl_GetOpenFile) /* 167 */ +#define Tcl_GetPathType \ + (tclStubsPtr->tcl_GetPathType) /* 168 */ +#define Tcl_Gets \ + (tclStubsPtr->tcl_Gets) /* 169 */ +#define Tcl_GetsObj \ + (tclStubsPtr->tcl_GetsObj) /* 170 */ +#define Tcl_GetServiceMode \ + (tclStubsPtr->tcl_GetServiceMode) /* 171 */ +#define Tcl_GetChild \ + (tclStubsPtr->tcl_GetChild) /* 172 */ +#define Tcl_GetStdChannel \ + (tclStubsPtr->tcl_GetStdChannel) /* 173 */ +/* Slot 174 is reserved */ +/* Slot 175 is reserved */ +#define Tcl_GetVar2 \ + (tclStubsPtr->tcl_GetVar2) /* 176 */ +/* Slot 177 is reserved */ +/* Slot 178 is reserved */ +#define Tcl_HideCommand \ + (tclStubsPtr->tcl_HideCommand) /* 179 */ +#define Tcl_Init \ + (tclStubsPtr->tcl_Init) /* 180 */ +#define Tcl_InitHashTable \ + (tclStubsPtr->tcl_InitHashTable) /* 181 */ +#define Tcl_InputBlocked \ + (tclStubsPtr->tcl_InputBlocked) /* 182 */ +#define Tcl_InputBuffered \ + (tclStubsPtr->tcl_InputBuffered) /* 183 */ +#define Tcl_InterpDeleted \ + (tclStubsPtr->tcl_InterpDeleted) /* 184 */ +#define Tcl_IsSafe \ + (tclStubsPtr->tcl_IsSafe) /* 185 */ +#define Tcl_JoinPath \ + (tclStubsPtr->tcl_JoinPath) /* 186 */ +#define Tcl_LinkVar \ + (tclStubsPtr->tcl_LinkVar) /* 187 */ +/* Slot 188 is reserved */ +#define Tcl_MakeFileChannel \ + (tclStubsPtr->tcl_MakeFileChannel) /* 189 */ +/* Slot 190 is reserved */ +#define Tcl_MakeTcpClientChannel \ + (tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */ +#define Tcl_Merge \ + (tclStubsPtr->tcl_Merge) /* 192 */ +#define Tcl_NextHashEntry \ + (tclStubsPtr->tcl_NextHashEntry) /* 193 */ +#define Tcl_NotifyChannel \ + (tclStubsPtr->tcl_NotifyChannel) /* 194 */ +#define Tcl_ObjGetVar2 \ + (tclStubsPtr->tcl_ObjGetVar2) /* 195 */ +#define Tcl_ObjSetVar2 \ + (tclStubsPtr->tcl_ObjSetVar2) /* 196 */ +#define Tcl_OpenCommandChannel \ + (tclStubsPtr->tcl_OpenCommandChannel) /* 197 */ +#define Tcl_OpenFileChannel \ + (tclStubsPtr->tcl_OpenFileChannel) /* 198 */ +#define Tcl_OpenTcpClient \ + (tclStubsPtr->tcl_OpenTcpClient) /* 199 */ +#define Tcl_OpenTcpServer \ + (tclStubsPtr->tcl_OpenTcpServer) /* 200 */ +#define Tcl_Preserve \ + (tclStubsPtr->tcl_Preserve) /* 201 */ +#define Tcl_PrintDouble \ + (tclStubsPtr->tcl_PrintDouble) /* 202 */ +#define Tcl_PutEnv \ + (tclStubsPtr->tcl_PutEnv) /* 203 */ +#define Tcl_PosixError \ + (tclStubsPtr->tcl_PosixError) /* 204 */ +#define Tcl_QueueEvent \ + (tclStubsPtr->tcl_QueueEvent) /* 205 */ +#define Tcl_Read \ + (tclStubsPtr->tcl_Read) /* 206 */ +#define Tcl_ReapDetachedProcs \ + (tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */ +#define Tcl_RecordAndEval \ + (tclStubsPtr->tcl_RecordAndEval) /* 208 */ +#define Tcl_RecordAndEvalObj \ + (tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */ +#define Tcl_RegisterChannel \ + (tclStubsPtr->tcl_RegisterChannel) /* 210 */ +#define Tcl_RegisterObjType \ + (tclStubsPtr->tcl_RegisterObjType) /* 211 */ +#define Tcl_RegExpCompile \ + (tclStubsPtr->tcl_RegExpCompile) /* 212 */ +#define Tcl_RegExpExec \ + (tclStubsPtr->tcl_RegExpExec) /* 213 */ +#define Tcl_RegExpMatch \ + (tclStubsPtr->tcl_RegExpMatch) /* 214 */ +#define Tcl_RegExpRange \ + (tclStubsPtr->tcl_RegExpRange) /* 215 */ +#define Tcl_Release \ + (tclStubsPtr->tcl_Release) /* 216 */ +#define Tcl_ResetResult \ + (tclStubsPtr->tcl_ResetResult) /* 217 */ +#define Tcl_ScanElement \ + (tclStubsPtr->tcl_ScanElement) /* 218 */ +#define Tcl_ScanCountedElement \ + (tclStubsPtr->tcl_ScanCountedElement) /* 219 */ +/* Slot 220 is reserved */ +#define Tcl_ServiceAll \ + (tclStubsPtr->tcl_ServiceAll) /* 221 */ +#define Tcl_ServiceEvent \ + (tclStubsPtr->tcl_ServiceEvent) /* 222 */ +#define Tcl_SetAssocData \ + (tclStubsPtr->tcl_SetAssocData) /* 223 */ +#define Tcl_SetChannelBufferSize \ + (tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */ +#define Tcl_SetChannelOption \ + (tclStubsPtr->tcl_SetChannelOption) /* 225 */ +#define Tcl_SetCommandInfo \ + (tclStubsPtr->tcl_SetCommandInfo) /* 226 */ +#define Tcl_SetErrno \ + (tclStubsPtr->tcl_SetErrno) /* 227 */ +#define Tcl_SetErrorCode \ + (tclStubsPtr->tcl_SetErrorCode) /* 228 */ +#define Tcl_SetMaxBlockTime \ + (tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */ +/* Slot 230 is reserved */ +#define Tcl_SetRecursionLimit \ + (tclStubsPtr->tcl_SetRecursionLimit) /* 231 */ +/* Slot 232 is reserved */ +#define Tcl_SetServiceMode \ + (tclStubsPtr->tcl_SetServiceMode) /* 233 */ +#define Tcl_SetObjErrorCode \ + (tclStubsPtr->tcl_SetObjErrorCode) /* 234 */ +#define Tcl_SetObjResult \ + (tclStubsPtr->tcl_SetObjResult) /* 235 */ +#define Tcl_SetStdChannel \ + (tclStubsPtr->tcl_SetStdChannel) /* 236 */ +/* Slot 237 is reserved */ +#define Tcl_SetVar2 \ + (tclStubsPtr->tcl_SetVar2) /* 238 */ +#define Tcl_SignalId \ + (tclStubsPtr->tcl_SignalId) /* 239 */ +#define Tcl_SignalMsg \ + (tclStubsPtr->tcl_SignalMsg) /* 240 */ +#define Tcl_SourceRCFile \ + (tclStubsPtr->tcl_SourceRCFile) /* 241 */ +#define TclSplitList \ + (tclStubsPtr->tclSplitList) /* 242 */ +#define TclSplitPath \ + (tclStubsPtr->tclSplitPath) /* 243 */ +/* Slot 244 is reserved */ +/* Slot 245 is reserved */ +/* Slot 246 is reserved */ +/* Slot 247 is reserved */ +#define Tcl_TraceVar2 \ + (tclStubsPtr->tcl_TraceVar2) /* 248 */ +#define Tcl_TranslateFileName \ + (tclStubsPtr->tcl_TranslateFileName) /* 249 */ +#define Tcl_Ungets \ + (tclStubsPtr->tcl_Ungets) /* 250 */ +#define Tcl_UnlinkVar \ + (tclStubsPtr->tcl_UnlinkVar) /* 251 */ +#define Tcl_UnregisterChannel \ + (tclStubsPtr->tcl_UnregisterChannel) /* 252 */ +/* Slot 253 is reserved */ +#define Tcl_UnsetVar2 \ + (tclStubsPtr->tcl_UnsetVar2) /* 254 */ +/* Slot 255 is reserved */ +#define Tcl_UntraceVar2 \ + (tclStubsPtr->tcl_UntraceVar2) /* 256 */ +#define Tcl_UpdateLinkedVar \ + (tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */ +/* Slot 258 is reserved */ +#define Tcl_UpVar2 \ + (tclStubsPtr->tcl_UpVar2) /* 259 */ +#define Tcl_VarEval \ + (tclStubsPtr->tcl_VarEval) /* 260 */ +/* Slot 261 is reserved */ +#define Tcl_VarTraceInfo2 \ + (tclStubsPtr->tcl_VarTraceInfo2) /* 262 */ +#define Tcl_Write \ + (tclStubsPtr->tcl_Write) /* 263 */ +#define Tcl_WrongNumArgs \ + (tclStubsPtr->tcl_WrongNumArgs) /* 264 */ +#define Tcl_DumpActiveMemory \ + (tclStubsPtr->tcl_DumpActiveMemory) /* 265 */ +#define Tcl_ValidateAllMemory \ + (tclStubsPtr->tcl_ValidateAllMemory) /* 266 */ +/* Slot 267 is reserved */ +/* Slot 268 is reserved */ +#define Tcl_HashStats \ + (tclStubsPtr->tcl_HashStats) /* 269 */ +#define Tcl_ParseVar \ + (tclStubsPtr->tcl_ParseVar) /* 270 */ +/* Slot 271 is reserved */ +#define Tcl_PkgPresentEx \ + (tclStubsPtr->tcl_PkgPresentEx) /* 272 */ +/* Slot 273 is reserved */ +/* Slot 274 is reserved */ +/* Slot 275 is reserved */ +/* Slot 276 is reserved */ +#define Tcl_WaitPid \ + (tclStubsPtr->tcl_WaitPid) /* 277 */ +/* Slot 278 is reserved */ +#define Tcl_GetVersion \ + (tclStubsPtr->tcl_GetVersion) /* 279 */ +#define Tcl_InitMemory \ + (tclStubsPtr->tcl_InitMemory) /* 280 */ +#define Tcl_StackChannel \ + (tclStubsPtr->tcl_StackChannel) /* 281 */ +#define Tcl_UnstackChannel \ + (tclStubsPtr->tcl_UnstackChannel) /* 282 */ +#define Tcl_GetStackedChannel \ + (tclStubsPtr->tcl_GetStackedChannel) /* 283 */ +#define Tcl_SetMainLoop \ + (tclStubsPtr->tcl_SetMainLoop) /* 284 */ +/* Slot 285 is reserved */ +#define Tcl_AppendObjToObj \ + (tclStubsPtr->tcl_AppendObjToObj) /* 286 */ +#define Tcl_CreateEncoding \ + (tclStubsPtr->tcl_CreateEncoding) /* 287 */ +#define Tcl_CreateThreadExitHandler \ + (tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */ +#define Tcl_DeleteThreadExitHandler \ + (tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */ +/* Slot 290 is reserved */ +#define Tcl_EvalEx \ + (tclStubsPtr->tcl_EvalEx) /* 291 */ +#define Tcl_EvalObjv \ + (tclStubsPtr->tcl_EvalObjv) /* 292 */ +#define Tcl_EvalObjEx \ + (tclStubsPtr->tcl_EvalObjEx) /* 293 */ +#define Tcl_ExitThread \ + (tclStubsPtr->tcl_ExitThread) /* 294 */ +#define Tcl_ExternalToUtf \ + (tclStubsPtr->tcl_ExternalToUtf) /* 295 */ +#define Tcl_ExternalToUtfDString \ + (tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */ +#define Tcl_FinalizeThread \ + (tclStubsPtr->tcl_FinalizeThread) /* 297 */ +#define Tcl_FinalizeNotifier \ + (tclStubsPtr->tcl_FinalizeNotifier) /* 298 */ +#define Tcl_FreeEncoding \ + (tclStubsPtr->tcl_FreeEncoding) /* 299 */ +#define Tcl_GetCurrentThread \ + (tclStubsPtr->tcl_GetCurrentThread) /* 300 */ +#define Tcl_GetEncoding \ + (tclStubsPtr->tcl_GetEncoding) /* 301 */ +#define Tcl_GetEncodingName \ + (tclStubsPtr->tcl_GetEncodingName) /* 302 */ +#define Tcl_GetEncodingNames \ + (tclStubsPtr->tcl_GetEncodingNames) /* 303 */ +#define Tcl_GetIndexFromObjStruct \ + (tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */ +#define Tcl_GetThreadData \ + (tclStubsPtr->tcl_GetThreadData) /* 305 */ +#define Tcl_GetVar2Ex \ + (tclStubsPtr->tcl_GetVar2Ex) /* 306 */ +#define Tcl_InitNotifier \ + (tclStubsPtr->tcl_InitNotifier) /* 307 */ +#define Tcl_MutexLock \ + (tclStubsPtr->tcl_MutexLock) /* 308 */ +#define Tcl_MutexUnlock \ + (tclStubsPtr->tcl_MutexUnlock) /* 309 */ +#define Tcl_ConditionNotify \ + (tclStubsPtr->tcl_ConditionNotify) /* 310 */ +#define Tcl_ConditionWait \ + (tclStubsPtr->tcl_ConditionWait) /* 311 */ +#define TclNumUtfChars \ + (tclStubsPtr->tclNumUtfChars) /* 312 */ +#define Tcl_ReadChars \ + (tclStubsPtr->tcl_ReadChars) /* 313 */ +/* Slot 314 is reserved */ +/* Slot 315 is reserved */ +#define Tcl_SetSystemEncoding \ + (tclStubsPtr->tcl_SetSystemEncoding) /* 316 */ +#define Tcl_SetVar2Ex \ + (tclStubsPtr->tcl_SetVar2Ex) /* 317 */ +#define Tcl_ThreadAlert \ + (tclStubsPtr->tcl_ThreadAlert) /* 318 */ +#define Tcl_ThreadQueueEvent \ + (tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */ +#define Tcl_UniCharAtIndex \ + (tclStubsPtr->tcl_UniCharAtIndex) /* 320 */ +#define Tcl_UniCharToLower \ + (tclStubsPtr->tcl_UniCharToLower) /* 321 */ +#define Tcl_UniCharToTitle \ + (tclStubsPtr->tcl_UniCharToTitle) /* 322 */ +#define Tcl_UniCharToUpper \ + (tclStubsPtr->tcl_UniCharToUpper) /* 323 */ +#define Tcl_UniCharToUtf \ + (tclStubsPtr->tcl_UniCharToUtf) /* 324 */ +#define TclUtfAtIndex \ + (tclStubsPtr->tclUtfAtIndex) /* 325 */ +#define TclUtfCharComplete \ + (tclStubsPtr->tclUtfCharComplete) /* 326 */ +#define Tcl_UtfBackslash \ + (tclStubsPtr->tcl_UtfBackslash) /* 327 */ +#define Tcl_UtfFindFirst \ + (tclStubsPtr->tcl_UtfFindFirst) /* 328 */ +#define Tcl_UtfFindLast \ + (tclStubsPtr->tcl_UtfFindLast) /* 329 */ +#define TclUtfNext \ + (tclStubsPtr->tclUtfNext) /* 330 */ +#define TclUtfPrev \ + (tclStubsPtr->tclUtfPrev) /* 331 */ +#define Tcl_UtfToExternal \ + (tclStubsPtr->tcl_UtfToExternal) /* 332 */ +#define Tcl_UtfToExternalDString \ + (tclStubsPtr->tcl_UtfToExternalDString) /* 333 */ +#define Tcl_UtfToLower \ + (tclStubsPtr->tcl_UtfToLower) /* 334 */ +#define Tcl_UtfToTitle \ + (tclStubsPtr->tcl_UtfToTitle) /* 335 */ +#define Tcl_UtfToChar16 \ + (tclStubsPtr->tcl_UtfToChar16) /* 336 */ +#define Tcl_UtfToUpper \ + (tclStubsPtr->tcl_UtfToUpper) /* 337 */ +#define Tcl_WriteChars \ + (tclStubsPtr->tcl_WriteChars) /* 338 */ +#define Tcl_WriteObj \ + (tclStubsPtr->tcl_WriteObj) /* 339 */ +#define Tcl_GetString \ + (tclStubsPtr->tcl_GetString) /* 340 */ +/* Slot 341 is reserved */ +/* Slot 342 is reserved */ +#define Tcl_AlertNotifier \ + (tclStubsPtr->tcl_AlertNotifier) /* 343 */ +#define Tcl_ServiceModeHook \ + (tclStubsPtr->tcl_ServiceModeHook) /* 344 */ +#define Tcl_UniCharIsAlnum \ + (tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */ +#define Tcl_UniCharIsAlpha \ + (tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */ +#define Tcl_UniCharIsDigit \ + (tclStubsPtr->tcl_UniCharIsDigit) /* 347 */ +#define Tcl_UniCharIsLower \ + (tclStubsPtr->tcl_UniCharIsLower) /* 348 */ +#define Tcl_UniCharIsSpace \ + (tclStubsPtr->tcl_UniCharIsSpace) /* 349 */ +#define Tcl_UniCharIsUpper \ + (tclStubsPtr->tcl_UniCharIsUpper) /* 350 */ +#define Tcl_UniCharIsWordChar \ + (tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */ +#define Tcl_Char16Len \ + (tclStubsPtr->tcl_Char16Len) /* 352 */ +/* Slot 353 is reserved */ +#define Tcl_Char16ToUtfDString \ + (tclStubsPtr->tcl_Char16ToUtfDString) /* 354 */ +#define Tcl_UtfToChar16DString \ + (tclStubsPtr->tcl_UtfToChar16DString) /* 355 */ +#define Tcl_GetRegExpFromObj \ + (tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */ +/* Slot 357 is reserved */ +#define Tcl_FreeParse \ + (tclStubsPtr->tcl_FreeParse) /* 358 */ +#define Tcl_LogCommandInfo \ + (tclStubsPtr->tcl_LogCommandInfo) /* 359 */ +#define Tcl_ParseBraces \ + (tclStubsPtr->tcl_ParseBraces) /* 360 */ +#define Tcl_ParseCommand \ + (tclStubsPtr->tcl_ParseCommand) /* 361 */ +#define Tcl_ParseExpr \ + (tclStubsPtr->tcl_ParseExpr) /* 362 */ +#define Tcl_ParseQuotedString \ + (tclStubsPtr->tcl_ParseQuotedString) /* 363 */ +#define Tcl_ParseVarName \ + (tclStubsPtr->tcl_ParseVarName) /* 364 */ +#define Tcl_GetCwd \ + (tclStubsPtr->tcl_GetCwd) /* 365 */ +#define Tcl_Chdir \ + (tclStubsPtr->tcl_Chdir) /* 366 */ +#define Tcl_Access \ + (tclStubsPtr->tcl_Access) /* 367 */ +#define Tcl_Stat \ + (tclStubsPtr->tcl_Stat) /* 368 */ +#define Tcl_UtfNcmp \ + (tclStubsPtr->tcl_UtfNcmp) /* 369 */ +#define Tcl_UtfNcasecmp \ + (tclStubsPtr->tcl_UtfNcasecmp) /* 370 */ +#define Tcl_StringCaseMatch \ + (tclStubsPtr->tcl_StringCaseMatch) /* 371 */ +#define Tcl_UniCharIsControl \ + (tclStubsPtr->tcl_UniCharIsControl) /* 372 */ +#define Tcl_UniCharIsGraph \ + (tclStubsPtr->tcl_UniCharIsGraph) /* 373 */ +#define Tcl_UniCharIsPrint \ + (tclStubsPtr->tcl_UniCharIsPrint) /* 374 */ +#define Tcl_UniCharIsPunct \ + (tclStubsPtr->tcl_UniCharIsPunct) /* 375 */ +#define Tcl_RegExpExecObj \ + (tclStubsPtr->tcl_RegExpExecObj) /* 376 */ +#define Tcl_RegExpGetInfo \ + (tclStubsPtr->tcl_RegExpGetInfo) /* 377 */ +#define Tcl_NewUnicodeObj \ + (tclStubsPtr->tcl_NewUnicodeObj) /* 378 */ +#define Tcl_SetUnicodeObj \ + (tclStubsPtr->tcl_SetUnicodeObj) /* 379 */ +#define TclGetCharLength \ + (tclStubsPtr->tclGetCharLength) /* 380 */ +#define TclGetUniChar \ + (tclStubsPtr->tclGetUniChar) /* 381 */ +/* Slot 382 is reserved */ +#define TclGetRange \ + (tclStubsPtr->tclGetRange) /* 383 */ +#define Tcl_AppendUnicodeToObj \ + (tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */ +#define Tcl_RegExpMatchObj \ + (tclStubsPtr->tcl_RegExpMatchObj) /* 385 */ +#define Tcl_SetNotifier \ + (tclStubsPtr->tcl_SetNotifier) /* 386 */ +#define Tcl_GetAllocMutex \ + (tclStubsPtr->tcl_GetAllocMutex) /* 387 */ +#define Tcl_GetChannelNames \ + (tclStubsPtr->tcl_GetChannelNames) /* 388 */ +#define Tcl_GetChannelNamesEx \ + (tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */ +#define Tcl_ProcObjCmd \ + (tclStubsPtr->tcl_ProcObjCmd) /* 390 */ +#define Tcl_ConditionFinalize \ + (tclStubsPtr->tcl_ConditionFinalize) /* 391 */ +#define Tcl_MutexFinalize \ + (tclStubsPtr->tcl_MutexFinalize) /* 392 */ +#define Tcl_CreateThread \ + (tclStubsPtr->tcl_CreateThread) /* 393 */ +#define Tcl_ReadRaw \ + (tclStubsPtr->tcl_ReadRaw) /* 394 */ +#define Tcl_WriteRaw \ + (tclStubsPtr->tcl_WriteRaw) /* 395 */ +#define Tcl_GetTopChannel \ + (tclStubsPtr->tcl_GetTopChannel) /* 396 */ +#define Tcl_ChannelBuffered \ + (tclStubsPtr->tcl_ChannelBuffered) /* 397 */ +#define Tcl_ChannelName \ + (tclStubsPtr->tcl_ChannelName) /* 398 */ +#define Tcl_ChannelVersion \ + (tclStubsPtr->tcl_ChannelVersion) /* 399 */ +#define Tcl_ChannelBlockModeProc \ + (tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */ +/* Slot 401 is reserved */ +#define Tcl_ChannelClose2Proc \ + (tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */ +#define Tcl_ChannelInputProc \ + (tclStubsPtr->tcl_ChannelInputProc) /* 403 */ +#define Tcl_ChannelOutputProc \ + (tclStubsPtr->tcl_ChannelOutputProc) /* 404 */ +/* Slot 405 is reserved */ +#define Tcl_ChannelSetOptionProc \ + (tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */ +#define Tcl_ChannelGetOptionProc \ + (tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */ +#define Tcl_ChannelWatchProc \ + (tclStubsPtr->tcl_ChannelWatchProc) /* 408 */ +#define Tcl_ChannelGetHandleProc \ + (tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */ +#define Tcl_ChannelFlushProc \ + (tclStubsPtr->tcl_ChannelFlushProc) /* 410 */ +#define Tcl_ChannelHandlerProc \ + (tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */ +#define Tcl_JoinThread \ + (tclStubsPtr->tcl_JoinThread) /* 412 */ +#define Tcl_IsChannelShared \ + (tclStubsPtr->tcl_IsChannelShared) /* 413 */ +#define Tcl_IsChannelRegistered \ + (tclStubsPtr->tcl_IsChannelRegistered) /* 414 */ +#define Tcl_CutChannel \ + (tclStubsPtr->tcl_CutChannel) /* 415 */ +#define Tcl_SpliceChannel \ + (tclStubsPtr->tcl_SpliceChannel) /* 416 */ +#define Tcl_ClearChannelHandlers \ + (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ +#define Tcl_IsChannelExisting \ + (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ +/* Slot 419 is reserved */ +/* Slot 420 is reserved */ +/* Slot 421 is reserved */ +/* Slot 422 is reserved */ +#define Tcl_InitCustomHashTable \ + (tclStubsPtr->tcl_InitCustomHashTable) /* 423 */ +#define Tcl_InitObjHashTable \ + (tclStubsPtr->tcl_InitObjHashTable) /* 424 */ +#define Tcl_CommandTraceInfo \ + (tclStubsPtr->tcl_CommandTraceInfo) /* 425 */ +#define Tcl_TraceCommand \ + (tclStubsPtr->tcl_TraceCommand) /* 426 */ +#define Tcl_UntraceCommand \ + (tclStubsPtr->tcl_UntraceCommand) /* 427 */ +#define Tcl_AttemptAlloc \ + (tclStubsPtr->tcl_AttemptAlloc) /* 428 */ +#define Tcl_AttemptDbCkalloc \ + (tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */ +#define Tcl_AttemptRealloc \ + (tclStubsPtr->tcl_AttemptRealloc) /* 430 */ +#define Tcl_AttemptDbCkrealloc \ + (tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */ +#define Tcl_AttemptSetObjLength \ + (tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */ +#define Tcl_GetChannelThread \ + (tclStubsPtr->tcl_GetChannelThread) /* 433 */ +#define TclGetUnicodeFromObj \ + (tclStubsPtr->tclGetUnicodeFromObj) /* 434 */ +/* Slot 435 is reserved */ +/* Slot 436 is reserved */ +#define Tcl_SubstObj \ + (tclStubsPtr->tcl_SubstObj) /* 437 */ +#define Tcl_DetachChannel \ + (tclStubsPtr->tcl_DetachChannel) /* 438 */ +#define Tcl_IsStandardChannel \ + (tclStubsPtr->tcl_IsStandardChannel) /* 439 */ +#define Tcl_FSCopyFile \ + (tclStubsPtr->tcl_FSCopyFile) /* 440 */ +#define Tcl_FSCopyDirectory \ + (tclStubsPtr->tcl_FSCopyDirectory) /* 441 */ +#define Tcl_FSCreateDirectory \ + (tclStubsPtr->tcl_FSCreateDirectory) /* 442 */ +#define Tcl_FSDeleteFile \ + (tclStubsPtr->tcl_FSDeleteFile) /* 443 */ +#define Tcl_FSLoadFile \ + (tclStubsPtr->tcl_FSLoadFile) /* 444 */ +#define Tcl_FSMatchInDirectory \ + (tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */ +#define Tcl_FSLink \ + (tclStubsPtr->tcl_FSLink) /* 446 */ +#define Tcl_FSRemoveDirectory \ + (tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */ +#define Tcl_FSRenameFile \ + (tclStubsPtr->tcl_FSRenameFile) /* 448 */ +#define Tcl_FSLstat \ + (tclStubsPtr->tcl_FSLstat) /* 449 */ +#define Tcl_FSUtime \ + (tclStubsPtr->tcl_FSUtime) /* 450 */ +#define Tcl_FSFileAttrsGet \ + (tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */ +#define Tcl_FSFileAttrsSet \ + (tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */ +#define Tcl_FSFileAttrStrings \ + (tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */ +#define Tcl_FSStat \ + (tclStubsPtr->tcl_FSStat) /* 454 */ +#define Tcl_FSAccess \ + (tclStubsPtr->tcl_FSAccess) /* 455 */ +#define Tcl_FSOpenFileChannel \ + (tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */ +#define Tcl_FSGetCwd \ + (tclStubsPtr->tcl_FSGetCwd) /* 457 */ +#define Tcl_FSChdir \ + (tclStubsPtr->tcl_FSChdir) /* 458 */ +#define Tcl_FSConvertToPathType \ + (tclStubsPtr->tcl_FSConvertToPathType) /* 459 */ +#define Tcl_FSJoinPath \ + (tclStubsPtr->tcl_FSJoinPath) /* 460 */ +#define TclFSSplitPath \ + (tclStubsPtr->tclFSSplitPath) /* 461 */ +#define Tcl_FSEqualPaths \ + (tclStubsPtr->tcl_FSEqualPaths) /* 462 */ +#define Tcl_FSGetNormalizedPath \ + (tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */ +#define Tcl_FSJoinToPath \ + (tclStubsPtr->tcl_FSJoinToPath) /* 464 */ +#define Tcl_FSGetInternalRep \ + (tclStubsPtr->tcl_FSGetInternalRep) /* 465 */ +#define Tcl_FSGetTranslatedPath \ + (tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */ +#define Tcl_FSEvalFile \ + (tclStubsPtr->tcl_FSEvalFile) /* 467 */ +#define Tcl_FSNewNativePath \ + (tclStubsPtr->tcl_FSNewNativePath) /* 468 */ +#define Tcl_FSGetNativePath \ + (tclStubsPtr->tcl_FSGetNativePath) /* 469 */ +#define Tcl_FSFileSystemInfo \ + (tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */ +#define Tcl_FSPathSeparator \ + (tclStubsPtr->tcl_FSPathSeparator) /* 471 */ +#define Tcl_FSListVolumes \ + (tclStubsPtr->tcl_FSListVolumes) /* 472 */ +#define Tcl_FSRegister \ + (tclStubsPtr->tcl_FSRegister) /* 473 */ +#define Tcl_FSUnregister \ + (tclStubsPtr->tcl_FSUnregister) /* 474 */ +#define Tcl_FSData \ + (tclStubsPtr->tcl_FSData) /* 475 */ +#define Tcl_FSGetTranslatedStringPath \ + (tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */ +#define Tcl_FSGetFileSystemForPath \ + (tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */ +#define Tcl_FSGetPathType \ + (tclStubsPtr->tcl_FSGetPathType) /* 478 */ +#define Tcl_OutputBuffered \ + (tclStubsPtr->tcl_OutputBuffered) /* 479 */ +#define Tcl_FSMountsChanged \ + (tclStubsPtr->tcl_FSMountsChanged) /* 480 */ +#define Tcl_EvalTokensStandard \ + (tclStubsPtr->tcl_EvalTokensStandard) /* 481 */ +#define Tcl_GetTime \ + (tclStubsPtr->tcl_GetTime) /* 482 */ +#define Tcl_CreateObjTrace \ + (tclStubsPtr->tcl_CreateObjTrace) /* 483 */ +#define Tcl_GetCommandInfoFromToken \ + (tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */ +#define Tcl_SetCommandInfoFromToken \ + (tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */ +#define Tcl_DbNewWideIntObj \ + (tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */ +#define Tcl_GetWideIntFromObj \ + (tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */ +#define Tcl_NewWideIntObj \ + (tclStubsPtr->tcl_NewWideIntObj) /* 488 */ +#define Tcl_SetWideIntObj \ + (tclStubsPtr->tcl_SetWideIntObj) /* 489 */ +#define Tcl_AllocStatBuf \ + (tclStubsPtr->tcl_AllocStatBuf) /* 490 */ +#define Tcl_Seek \ + (tclStubsPtr->tcl_Seek) /* 491 */ +#define Tcl_Tell \ + (tclStubsPtr->tcl_Tell) /* 492 */ +#define Tcl_ChannelWideSeekProc \ + (tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */ +#define Tcl_DictObjPut \ + (tclStubsPtr->tcl_DictObjPut) /* 494 */ +#define Tcl_DictObjGet \ + (tclStubsPtr->tcl_DictObjGet) /* 495 */ +#define Tcl_DictObjRemove \ + (tclStubsPtr->tcl_DictObjRemove) /* 496 */ +#define TclDictObjSize \ + (tclStubsPtr->tclDictObjSize) /* 497 */ +#define Tcl_DictObjFirst \ + (tclStubsPtr->tcl_DictObjFirst) /* 498 */ +#define Tcl_DictObjNext \ + (tclStubsPtr->tcl_DictObjNext) /* 499 */ +#define Tcl_DictObjDone \ + (tclStubsPtr->tcl_DictObjDone) /* 500 */ +#define Tcl_DictObjPutKeyList \ + (tclStubsPtr->tcl_DictObjPutKeyList) /* 501 */ +#define Tcl_DictObjRemoveKeyList \ + (tclStubsPtr->tcl_DictObjRemoveKeyList) /* 502 */ +#define Tcl_NewDictObj \ + (tclStubsPtr->tcl_NewDictObj) /* 503 */ +#define Tcl_DbNewDictObj \ + (tclStubsPtr->tcl_DbNewDictObj) /* 504 */ +#define Tcl_RegisterConfig \ + (tclStubsPtr->tcl_RegisterConfig) /* 505 */ +#define Tcl_CreateNamespace \ + (tclStubsPtr->tcl_CreateNamespace) /* 506 */ +#define Tcl_DeleteNamespace \ + (tclStubsPtr->tcl_DeleteNamespace) /* 507 */ +#define Tcl_AppendExportList \ + (tclStubsPtr->tcl_AppendExportList) /* 508 */ +#define Tcl_Export \ + (tclStubsPtr->tcl_Export) /* 509 */ +#define Tcl_Import \ + (tclStubsPtr->tcl_Import) /* 510 */ +#define Tcl_ForgetImport \ + (tclStubsPtr->tcl_ForgetImport) /* 511 */ +#define Tcl_GetCurrentNamespace \ + (tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */ +#define Tcl_GetGlobalNamespace \ + (tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */ +#define Tcl_FindNamespace \ + (tclStubsPtr->tcl_FindNamespace) /* 514 */ +#define Tcl_FindCommand \ + (tclStubsPtr->tcl_FindCommand) /* 515 */ +#define Tcl_GetCommandFromObj \ + (tclStubsPtr->tcl_GetCommandFromObj) /* 516 */ +#define Tcl_GetCommandFullName \ + (tclStubsPtr->tcl_GetCommandFullName) /* 517 */ +#define Tcl_FSEvalFileEx \ + (tclStubsPtr->tcl_FSEvalFileEx) /* 518 */ +/* Slot 519 is reserved */ +#define Tcl_LimitAddHandler \ + (tclStubsPtr->tcl_LimitAddHandler) /* 520 */ +#define Tcl_LimitRemoveHandler \ + (tclStubsPtr->tcl_LimitRemoveHandler) /* 521 */ +#define Tcl_LimitReady \ + (tclStubsPtr->tcl_LimitReady) /* 522 */ +#define Tcl_LimitCheck \ + (tclStubsPtr->tcl_LimitCheck) /* 523 */ +#define Tcl_LimitExceeded \ + (tclStubsPtr->tcl_LimitExceeded) /* 524 */ +#define Tcl_LimitSetCommands \ + (tclStubsPtr->tcl_LimitSetCommands) /* 525 */ +#define Tcl_LimitSetTime \ + (tclStubsPtr->tcl_LimitSetTime) /* 526 */ +#define Tcl_LimitSetGranularity \ + (tclStubsPtr->tcl_LimitSetGranularity) /* 527 */ +#define Tcl_LimitTypeEnabled \ + (tclStubsPtr->tcl_LimitTypeEnabled) /* 528 */ +#define Tcl_LimitTypeExceeded \ + (tclStubsPtr->tcl_LimitTypeExceeded) /* 529 */ +#define Tcl_LimitTypeSet \ + (tclStubsPtr->tcl_LimitTypeSet) /* 530 */ +#define Tcl_LimitTypeReset \ + (tclStubsPtr->tcl_LimitTypeReset) /* 531 */ +#define Tcl_LimitGetCommands \ + (tclStubsPtr->tcl_LimitGetCommands) /* 532 */ +#define Tcl_LimitGetTime \ + (tclStubsPtr->tcl_LimitGetTime) /* 533 */ +#define Tcl_LimitGetGranularity \ + (tclStubsPtr->tcl_LimitGetGranularity) /* 534 */ +#define Tcl_SaveInterpState \ + (tclStubsPtr->tcl_SaveInterpState) /* 535 */ +#define Tcl_RestoreInterpState \ + (tclStubsPtr->tcl_RestoreInterpState) /* 536 */ +#define Tcl_DiscardInterpState \ + (tclStubsPtr->tcl_DiscardInterpState) /* 537 */ +#define Tcl_SetReturnOptions \ + (tclStubsPtr->tcl_SetReturnOptions) /* 538 */ +#define Tcl_GetReturnOptions \ + (tclStubsPtr->tcl_GetReturnOptions) /* 539 */ +#define Tcl_IsEnsemble \ + (tclStubsPtr->tcl_IsEnsemble) /* 540 */ +#define Tcl_CreateEnsemble \ + (tclStubsPtr->tcl_CreateEnsemble) /* 541 */ +#define Tcl_FindEnsemble \ + (tclStubsPtr->tcl_FindEnsemble) /* 542 */ +#define Tcl_SetEnsembleSubcommandList \ + (tclStubsPtr->tcl_SetEnsembleSubcommandList) /* 543 */ +#define Tcl_SetEnsembleMappingDict \ + (tclStubsPtr->tcl_SetEnsembleMappingDict) /* 544 */ +#define Tcl_SetEnsembleUnknownHandler \ + (tclStubsPtr->tcl_SetEnsembleUnknownHandler) /* 545 */ +#define Tcl_SetEnsembleFlags \ + (tclStubsPtr->tcl_SetEnsembleFlags) /* 546 */ +#define Tcl_GetEnsembleSubcommandList \ + (tclStubsPtr->tcl_GetEnsembleSubcommandList) /* 547 */ +#define Tcl_GetEnsembleMappingDict \ + (tclStubsPtr->tcl_GetEnsembleMappingDict) /* 548 */ +#define Tcl_GetEnsembleUnknownHandler \ + (tclStubsPtr->tcl_GetEnsembleUnknownHandler) /* 549 */ +#define Tcl_GetEnsembleFlags \ + (tclStubsPtr->tcl_GetEnsembleFlags) /* 550 */ +#define Tcl_GetEnsembleNamespace \ + (tclStubsPtr->tcl_GetEnsembleNamespace) /* 551 */ +#define Tcl_SetTimeProc \ + (tclStubsPtr->tcl_SetTimeProc) /* 552 */ +#define Tcl_QueryTimeProc \ + (tclStubsPtr->tcl_QueryTimeProc) /* 553 */ +#define Tcl_ChannelThreadActionProc \ + (tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */ +#define Tcl_NewBignumObj \ + (tclStubsPtr->tcl_NewBignumObj) /* 555 */ +#define Tcl_DbNewBignumObj \ + (tclStubsPtr->tcl_DbNewBignumObj) /* 556 */ +#define Tcl_SetBignumObj \ + (tclStubsPtr->tcl_SetBignumObj) /* 557 */ +#define Tcl_GetBignumFromObj \ + (tclStubsPtr->tcl_GetBignumFromObj) /* 558 */ +#define Tcl_TakeBignumFromObj \ + (tclStubsPtr->tcl_TakeBignumFromObj) /* 559 */ +#define Tcl_TruncateChannel \ + (tclStubsPtr->tcl_TruncateChannel) /* 560 */ +#define Tcl_ChannelTruncateProc \ + (tclStubsPtr->tcl_ChannelTruncateProc) /* 561 */ +#define Tcl_SetChannelErrorInterp \ + (tclStubsPtr->tcl_SetChannelErrorInterp) /* 562 */ +#define Tcl_GetChannelErrorInterp \ + (tclStubsPtr->tcl_GetChannelErrorInterp) /* 563 */ +#define Tcl_SetChannelError \ + (tclStubsPtr->tcl_SetChannelError) /* 564 */ +#define Tcl_GetChannelError \ + (tclStubsPtr->tcl_GetChannelError) /* 565 */ +#define Tcl_InitBignumFromDouble \ + (tclStubsPtr->tcl_InitBignumFromDouble) /* 566 */ +#define Tcl_GetNamespaceUnknownHandler \ + (tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 567 */ +#define Tcl_SetNamespaceUnknownHandler \ + (tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 568 */ +#define Tcl_GetEncodingFromObj \ + (tclStubsPtr->tcl_GetEncodingFromObj) /* 569 */ +#define Tcl_GetEncodingSearchPath \ + (tclStubsPtr->tcl_GetEncodingSearchPath) /* 570 */ +#define Tcl_SetEncodingSearchPath \ + (tclStubsPtr->tcl_SetEncodingSearchPath) /* 571 */ +#define Tcl_GetEncodingNameFromEnvironment \ + (tclStubsPtr->tcl_GetEncodingNameFromEnvironment) /* 572 */ +#define Tcl_PkgRequireProc \ + (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ +#define Tcl_AppendObjToErrorInfo \ + (tclStubsPtr->tcl_AppendObjToErrorInfo) /* 574 */ +#define Tcl_AppendLimitedToObj \ + (tclStubsPtr->tcl_AppendLimitedToObj) /* 575 */ +#define Tcl_Format \ + (tclStubsPtr->tcl_Format) /* 576 */ +#define Tcl_AppendFormatToObj \ + (tclStubsPtr->tcl_AppendFormatToObj) /* 577 */ +#define Tcl_ObjPrintf \ + (tclStubsPtr->tcl_ObjPrintf) /* 578 */ +#define Tcl_AppendPrintfToObj \ + (tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */ +#define Tcl_CancelEval \ + (tclStubsPtr->tcl_CancelEval) /* 580 */ +#define Tcl_Canceled \ + (tclStubsPtr->tcl_Canceled) /* 581 */ +#define Tcl_CreatePipe \ + (tclStubsPtr->tcl_CreatePipe) /* 582 */ +#define Tcl_NRCreateCommand \ + (tclStubsPtr->tcl_NRCreateCommand) /* 583 */ +#define Tcl_NREvalObj \ + (tclStubsPtr->tcl_NREvalObj) /* 584 */ +#define Tcl_NREvalObjv \ + (tclStubsPtr->tcl_NREvalObjv) /* 585 */ +#define Tcl_NRCmdSwap \ + (tclStubsPtr->tcl_NRCmdSwap) /* 586 */ +#define Tcl_NRAddCallback \ + (tclStubsPtr->tcl_NRAddCallback) /* 587 */ +#define Tcl_NRCallObjProc \ + (tclStubsPtr->tcl_NRCallObjProc) /* 588 */ +#define Tcl_GetFSDeviceFromStat \ + (tclStubsPtr->tcl_GetFSDeviceFromStat) /* 589 */ +#define Tcl_GetFSInodeFromStat \ + (tclStubsPtr->tcl_GetFSInodeFromStat) /* 590 */ +#define Tcl_GetModeFromStat \ + (tclStubsPtr->tcl_GetModeFromStat) /* 591 */ +#define Tcl_GetLinkCountFromStat \ + (tclStubsPtr->tcl_GetLinkCountFromStat) /* 592 */ +#define Tcl_GetUserIdFromStat \ + (tclStubsPtr->tcl_GetUserIdFromStat) /* 593 */ +#define Tcl_GetGroupIdFromStat \ + (tclStubsPtr->tcl_GetGroupIdFromStat) /* 594 */ +#define Tcl_GetDeviceTypeFromStat \ + (tclStubsPtr->tcl_GetDeviceTypeFromStat) /* 595 */ +#define Tcl_GetAccessTimeFromStat \ + (tclStubsPtr->tcl_GetAccessTimeFromStat) /* 596 */ +#define Tcl_GetModificationTimeFromStat \ + (tclStubsPtr->tcl_GetModificationTimeFromStat) /* 597 */ +#define Tcl_GetChangeTimeFromStat \ + (tclStubsPtr->tcl_GetChangeTimeFromStat) /* 598 */ +#define Tcl_GetSizeFromStat \ + (tclStubsPtr->tcl_GetSizeFromStat) /* 599 */ +#define Tcl_GetBlocksFromStat \ + (tclStubsPtr->tcl_GetBlocksFromStat) /* 600 */ +#define Tcl_GetBlockSizeFromStat \ + (tclStubsPtr->tcl_GetBlockSizeFromStat) /* 601 */ +#define Tcl_SetEnsembleParameterList \ + (tclStubsPtr->tcl_SetEnsembleParameterList) /* 602 */ +#define Tcl_GetEnsembleParameterList \ + (tclStubsPtr->tcl_GetEnsembleParameterList) /* 603 */ +#define TclParseArgsObjv \ + (tclStubsPtr->tclParseArgsObjv) /* 604 */ +#define Tcl_GetErrorLine \ + (tclStubsPtr->tcl_GetErrorLine) /* 605 */ +#define Tcl_SetErrorLine \ + (tclStubsPtr->tcl_SetErrorLine) /* 606 */ +#define Tcl_TransferResult \ + (tclStubsPtr->tcl_TransferResult) /* 607 */ +#define Tcl_InterpActive \ + (tclStubsPtr->tcl_InterpActive) /* 608 */ +#define Tcl_BackgroundException \ + (tclStubsPtr->tcl_BackgroundException) /* 609 */ +#define Tcl_ZlibDeflate \ + (tclStubsPtr->tcl_ZlibDeflate) /* 610 */ +#define Tcl_ZlibInflate \ + (tclStubsPtr->tcl_ZlibInflate) /* 611 */ +#define Tcl_ZlibCRC32 \ + (tclStubsPtr->tcl_ZlibCRC32) /* 612 */ +#define Tcl_ZlibAdler32 \ + (tclStubsPtr->tcl_ZlibAdler32) /* 613 */ +#define Tcl_ZlibStreamInit \ + (tclStubsPtr->tcl_ZlibStreamInit) /* 614 */ +#define Tcl_ZlibStreamGetCommandName \ + (tclStubsPtr->tcl_ZlibStreamGetCommandName) /* 615 */ +#define Tcl_ZlibStreamEof \ + (tclStubsPtr->tcl_ZlibStreamEof) /* 616 */ +#define Tcl_ZlibStreamChecksum \ + (tclStubsPtr->tcl_ZlibStreamChecksum) /* 617 */ +#define Tcl_ZlibStreamPut \ + (tclStubsPtr->tcl_ZlibStreamPut) /* 618 */ +#define Tcl_ZlibStreamGet \ + (tclStubsPtr->tcl_ZlibStreamGet) /* 619 */ +#define Tcl_ZlibStreamClose \ + (tclStubsPtr->tcl_ZlibStreamClose) /* 620 */ +#define Tcl_ZlibStreamReset \ + (tclStubsPtr->tcl_ZlibStreamReset) /* 621 */ +#define Tcl_SetStartupScript \ + (tclStubsPtr->tcl_SetStartupScript) /* 622 */ +#define Tcl_GetStartupScript \ + (tclStubsPtr->tcl_GetStartupScript) /* 623 */ +#define Tcl_CloseEx \ + (tclStubsPtr->tcl_CloseEx) /* 624 */ +#define Tcl_NRExprObj \ + (tclStubsPtr->tcl_NRExprObj) /* 625 */ +#define Tcl_NRSubstObj \ + (tclStubsPtr->tcl_NRSubstObj) /* 626 */ +#define Tcl_LoadFile \ + (tclStubsPtr->tcl_LoadFile) /* 627 */ +#define Tcl_FindSymbol \ + (tclStubsPtr->tcl_FindSymbol) /* 628 */ +#define Tcl_FSUnloadFile \ + (tclStubsPtr->tcl_FSUnloadFile) /* 629 */ +#define Tcl_ZlibStreamSetCompressionDictionary \ + (tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */ +#define Tcl_OpenTcpServerEx \ + (tclStubsPtr->tcl_OpenTcpServerEx) /* 631 */ +#define TclZipfs_Mount \ + (tclStubsPtr->tclZipfs_Mount) /* 632 */ +#define TclZipfs_Unmount \ + (tclStubsPtr->tclZipfs_Unmount) /* 633 */ +#define TclZipfs_TclLibrary \ + (tclStubsPtr->tclZipfs_TclLibrary) /* 634 */ +#define TclZipfs_MountBuffer \ + (tclStubsPtr->tclZipfs_MountBuffer) /* 635 */ +#define Tcl_FreeInternalRep \ + (tclStubsPtr->tcl_FreeInternalRep) /* 636 */ +#define Tcl_InitStringRep \ + (tclStubsPtr->tcl_InitStringRep) /* 637 */ +#define Tcl_FetchInternalRep \ + (tclStubsPtr->tcl_FetchInternalRep) /* 638 */ +#define Tcl_StoreInternalRep \ + (tclStubsPtr->tcl_StoreInternalRep) /* 639 */ +#define Tcl_HasStringRep \ + (tclStubsPtr->tcl_HasStringRep) /* 640 */ +#define Tcl_IncrRefCount \ + (tclStubsPtr->tcl_IncrRefCount) /* 641 */ +#define Tcl_DecrRefCount \ + (tclStubsPtr->tcl_DecrRefCount) /* 642 */ +#define Tcl_IsShared \ + (tclStubsPtr->tcl_IsShared) /* 643 */ +#define Tcl_LinkArray \ + (tclStubsPtr->tcl_LinkArray) /* 644 */ +#define Tcl_GetIntForIndex \ + (tclStubsPtr->tcl_GetIntForIndex) /* 645 */ +#define Tcl_UtfToUniChar \ + (tclStubsPtr->tcl_UtfToUniChar) /* 646 */ +#define Tcl_UniCharToUtfDString \ + (tclStubsPtr->tcl_UniCharToUtfDString) /* 647 */ +#define Tcl_UtfToUniCharDString \ + (tclStubsPtr->tcl_UtfToUniCharDString) /* 648 */ +#define TclGetBytesFromObj \ + (tclStubsPtr->tclGetBytesFromObj) /* 649 */ +#define Tcl_GetBytesFromObj \ + (tclStubsPtr->tcl_GetBytesFromObj) /* 650 */ +#define Tcl_GetStringFromObj \ + (tclStubsPtr->tcl_GetStringFromObj) /* 651 */ +#define Tcl_GetUnicodeFromObj \ + (tclStubsPtr->tcl_GetUnicodeFromObj) /* 652 */ +#define Tcl_GetSizeIntFromObj \ + (tclStubsPtr->tcl_GetSizeIntFromObj) /* 653 */ +#define Tcl_UtfCharComplete \ + (tclStubsPtr->tcl_UtfCharComplete) /* 654 */ +#define Tcl_UtfNext \ + (tclStubsPtr->tcl_UtfNext) /* 655 */ +#define Tcl_UtfPrev \ + (tclStubsPtr->tcl_UtfPrev) /* 656 */ +#define Tcl_UniCharIsUnicode \ + (tclStubsPtr->tcl_UniCharIsUnicode) /* 657 */ +#define Tcl_ExternalToUtfDStringEx \ + (tclStubsPtr->tcl_ExternalToUtfDStringEx) /* 658 */ +#define Tcl_UtfToExternalDStringEx \ + (tclStubsPtr->tcl_UtfToExternalDStringEx) /* 659 */ +#define Tcl_AsyncMarkFromSignal \ + (tclStubsPtr->tcl_AsyncMarkFromSignal) /* 660 */ +#define Tcl_ListObjGetElements \ + (tclStubsPtr->tcl_ListObjGetElements) /* 661 */ +#define Tcl_ListObjLength \ + (tclStubsPtr->tcl_ListObjLength) /* 662 */ +#define Tcl_DictObjSize \ + (tclStubsPtr->tcl_DictObjSize) /* 663 */ +#define Tcl_SplitList \ + (tclStubsPtr->tcl_SplitList) /* 664 */ +#define Tcl_SplitPath \ + (tclStubsPtr->tcl_SplitPath) /* 665 */ +#define Tcl_FSSplitPath \ + (tclStubsPtr->tcl_FSSplitPath) /* 666 */ +#define Tcl_ParseArgsObjv \ + (tclStubsPtr->tcl_ParseArgsObjv) /* 667 */ +#define Tcl_UniCharLen \ + (tclStubsPtr->tcl_UniCharLen) /* 668 */ +#define Tcl_NumUtfChars \ + (tclStubsPtr->tcl_NumUtfChars) /* 669 */ +#define Tcl_GetCharLength \ + (tclStubsPtr->tcl_GetCharLength) /* 670 */ +#define Tcl_UtfAtIndex \ + (tclStubsPtr->tcl_UtfAtIndex) /* 671 */ +#define Tcl_GetRange \ + (tclStubsPtr->tcl_GetRange) /* 672 */ +#define Tcl_GetUniChar \ + (tclStubsPtr->tcl_GetUniChar) /* 673 */ +#define Tcl_GetBool \ + (tclStubsPtr->tcl_GetBool) /* 674 */ +#define Tcl_GetBoolFromObj \ + (tclStubsPtr->tcl_GetBoolFromObj) /* 675 */ +#define Tcl_CreateObjCommand2 \ + (tclStubsPtr->tcl_CreateObjCommand2) /* 676 */ +#define Tcl_CreateObjTrace2 \ + (tclStubsPtr->tcl_CreateObjTrace2) /* 677 */ +#define Tcl_NRCreateCommand2 \ + (tclStubsPtr->tcl_NRCreateCommand2) /* 678 */ +#define Tcl_NRCallObjProc2 \ + (tclStubsPtr->tcl_NRCallObjProc2) /* 679 */ +#define Tcl_GetNumberFromObj \ + (tclStubsPtr->tcl_GetNumberFromObj) /* 680 */ +#define Tcl_GetNumber \ + (tclStubsPtr->tcl_GetNumber) /* 681 */ +#define Tcl_RemoveChannelMode \ + (tclStubsPtr->tcl_RemoveChannelMode) /* 682 */ +#define Tcl_GetEncodingNulLength \ + (tclStubsPtr->tcl_GetEncodingNulLength) /* 683 */ +#define Tcl_GetWideUIntFromObj \ + (tclStubsPtr->tcl_GetWideUIntFromObj) /* 684 */ +#define Tcl_DStringToObj \ + (tclStubsPtr->tcl_DStringToObj) /* 685 */ +/* Slot 686 is reserved */ +/* Slot 687 is reserved */ +#define TclUnusedStubEntry \ + (tclStubsPtr->tclUnusedStubEntry) /* 688 */ + +#endif /* defined(USE_TCL_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#undef TclUnusedStubEntry + +#ifdef _WIN32 +# undef Tcl_CreateFileHandler +# undef Tcl_DeleteFileHandler +# undef Tcl_GetOpenFile +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#define Tcl_PkgPresent(interp, name, version, exact) \ + Tcl_PkgPresentEx(interp, name, version, exact, NULL) +#define Tcl_PkgProvide(interp, name, version) \ + Tcl_PkgProvideEx(interp, name, version, NULL) +#define Tcl_PkgRequire(interp, name, version, exact) \ + Tcl_PkgRequireEx(interp, name, version, exact, NULL) +#define Tcl_GetIndexFromObj(interp, objPtr, tablePtr, msg, flags, indexPtr) \ + Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, \ + sizeof(char *), msg, flags, indexPtr) +#define Tcl_NewBooleanObj(intValue) \ + Tcl_NewWideIntObj((intValue)!=0) +#define Tcl_DbNewBooleanObj(intValue, file, line) \ + Tcl_DbNewWideIntObj((intValue)!=0, file, line) +#define Tcl_SetBooleanObj(objPtr, intValue) \ + Tcl_SetWideIntObj(objPtr, (intValue)!=0) +#define Tcl_SetVar(interp, varName, newValue, flags) \ + Tcl_SetVar2(interp, varName, NULL, newValue, flags) +#define Tcl_UnsetVar(interp, varName, flags) \ + Tcl_UnsetVar2(interp, varName, NULL, flags) +#define Tcl_GetVar(interp, varName, flags) \ + Tcl_GetVar2(interp, varName, NULL, flags) +#define Tcl_TraceVar(interp, varName, flags, proc, clientData) \ + Tcl_TraceVar2(interp, varName, NULL, flags, proc, clientData) +#define Tcl_UntraceVar(interp, varName, flags, proc, clientData) \ + Tcl_UntraceVar2(interp, varName, NULL, flags, proc, clientData) +#define Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData) \ + Tcl_VarTraceInfo2(interp, varName, NULL, flags, proc, prevClientData) +#define Tcl_UpVar(interp, frameName, varName, localName, flags) \ + Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags) +#define Tcl_AddErrorInfo(interp, message) \ + Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, -1)) +#define Tcl_AddObjErrorInfo(interp, message, length) \ + Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, length)) +#define Tcl_Eval(interp, objPtr) \ + Tcl_EvalEx(interp, objPtr, TCL_INDEX_NONE, 0) +#define Tcl_GlobalEval(interp, objPtr) \ + Tcl_EvalEx(interp, objPtr, TCL_INDEX_NONE, TCL_EVAL_GLOBAL) +#define Tcl_GetStringResult(interp) Tcl_GetString(Tcl_GetObjResult(interp)) +#define Tcl_SetResult(interp, result, freeProc) \ + do { \ + const char *__result = result; \ + Tcl_FreeProc *__freeProc = freeProc; \ + Tcl_SetObjResult(interp, Tcl_NewStringObj(__result, -1)); \ + if (__result != NULL && __freeProc != NULL && __freeProc != TCL_VOLATILE) { \ + if (__freeProc == TCL_DYNAMIC) { \ + Tcl_Free((char *)__result); \ + } else { \ + (*__freeProc)((char *)__result); \ + } \ + } \ + } while(0) + +#if defined(USE_TCL_STUBS) +# if defined(_WIN32) && defined(_WIN64) && TCL_MAJOR_VERSION < 9 +# undef Tcl_GetTime +/* Handle Win64 tk.dll being loaded in Cygwin64 (only needed for Tcl 8). */ +# define Tcl_GetTime(t) \ + do { \ + struct { \ + Tcl_Time now; \ + long long reserved; \ + } _t; \ + _t.reserved = -1; \ + tclStubsPtr->tcl_GetTime((&_t.now)); \ + if (_t.reserved != -1) { \ + _t.now.usec = (long) _t.reserved; \ + } \ + *(t) = _t.now; \ + } while (0) +# endif +# 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_GetLongFromObj +# undef Tcl_ExprLong +# undef Tcl_ExprLongObj +# define Tcl_GetLongFromObj ((int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetWideIntFromObj) +# 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; + } +# endif +#endif + +#undef Tcl_GetString +#undef Tcl_GetUnicode +#define Tcl_GetString(objPtr) \ + Tcl_GetStringFromObj(objPtr, (Tcl_Size *)NULL) +#define Tcl_GetUnicode(objPtr) \ + Tcl_GetUnicodeFromObj(objPtr, (Tcl_Size *)NULL) +#undef Tcl_GetIndexFromObjStruct +#undef Tcl_GetBooleanFromObj +#undef Tcl_GetBoolean +#ifdef __GNUC__ + /* If this gives: "error: size of array ‘_bool_Var’ is negative", it means that sizeof(*boolPtr)>sizeof(int), which is not allowed */ +# define TCLBOOLWARNING(boolPtr) ({__attribute__((unused)) char _bool_Var[sizeof(*(boolPtr)) > sizeof(int) ? -1 : 1];}), +#else +# define TCLBOOLWARNING(boolPtr) +#endif +#if defined(USE_TCL_STUBS) +#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \ + (tclStubsPtr->tcl_GetIndexFromObjStruct((interp), (objPtr), (tablePtr), (offset), (msg), \ + (flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr))) +#define Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) \ + (TCLBOOLWARNING(boolPtr)(sizeof(*(boolPtr)) >= sizeof(int) && (TCL_MAJOR_VERSION == 8)) ? tclStubsPtr->tcl_GetBooleanFromObj(interp, objPtr, (int *)(boolPtr)) : \ + Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#define Tcl_GetBoolean(interp, src, boolPtr) \ + (TCLBOOLWARNING(boolPtr)(sizeof(*(boolPtr)) >= sizeof(int) && (TCL_MAJOR_VERSION == 8)) ? tclStubsPtr->tcl_GetBoolean(interp, src, (int *)(boolPtr)) : \ + Tcl_GetBool(interp, src, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#else +#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \ + ((Tcl_GetIndexFromObjStruct)((interp), (objPtr), (tablePtr), (offset), (msg), \ + (flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr))) +#define Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) \ + (TCLBOOLWARNING(boolPtr)(sizeof(*(boolPtr)) >= sizeof(int) && (TCL_MAJOR_VERSION == 8)) ? Tcl_GetBooleanFromObj(interp, objPtr, (int *)(boolPtr)) : \ + Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#define Tcl_GetBoolean(interp, src, boolPtr) \ + (TCLBOOLWARNING(boolPtr)(sizeof(*(boolPtr)) >= sizeof(int) && (TCL_MAJOR_VERSION == 8)) ? Tcl_GetBoolean(interp, src, (int *)(boolPtr)) : \ + Tcl_GetBool(interp, src, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr))) +#endif + +#ifdef TCL_MEM_DEBUG +# undef Tcl_Alloc +# define Tcl_Alloc(x) \ + (Tcl_DbCkalloc((x), __FILE__, __LINE__)) +# undef Tcl_Free +# define Tcl_Free(x) \ + Tcl_DbCkfree((x), __FILE__, __LINE__) +# undef Tcl_Realloc +# define Tcl_Realloc(x,y) \ + (Tcl_DbCkrealloc((x), (y), __FILE__, __LINE__)) +# undef Tcl_AttemptAlloc +# define Tcl_AttemptAlloc(x) \ + (Tcl_AttemptDbCkalloc((x), __FILE__, __LINE__)) +# undef Tcl_AttemptRealloc +# define Tcl_AttemptRealloc(x,y) \ + (Tcl_AttemptDbCkrealloc((x), (y), __FILE__, __LINE__)) +#endif /* !TCL_MEM_DEBUG */ + +#define Tcl_NewLongObj(value) Tcl_NewWideIntObj((long)(value)) +#define Tcl_NewIntObj(value) Tcl_NewWideIntObj((int)(value)) +#define Tcl_DbNewLongObj(value, file, line) Tcl_DbNewWideIntObj((long)(value), file, line) +#define Tcl_SetIntObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (int)(value)) +#define Tcl_SetLongObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (long)(value)) +#define Tcl_BackgroundError(interp) Tcl_BackgroundException((interp), TCL_ERROR) +#define Tcl_StringMatch(str, pattern) Tcl_StringCaseMatch((str), (pattern), 0) + +#if TCL_UTF_MAX < 4 +# undef Tcl_UniCharToUtfDString +# define Tcl_UniCharToUtfDString Tcl_Char16ToUtfDString +# undef Tcl_UtfToUniCharDString +# define Tcl_UtfToUniCharDString Tcl_UtfToChar16DString +# undef Tcl_UtfToUniChar +# define Tcl_UtfToUniChar Tcl_UtfToChar16 +# undef Tcl_UniCharLen +# define Tcl_UniCharLen Tcl_Char16Len +# undef Tcl_UniCharToUtf +# if defined(USE_TCL_STUBS) +# define Tcl_UniCharToUtf(c, p) \ + (tclStubsPtr->tcl_UniCharToUtf((c)|TCL_COMBINE, (p))) +# else +# define Tcl_UniCharToUtf(c, p) \ + ((Tcl_UniCharToUtf)((c)|TCL_COMBINE, (p))) +# endif +#if !defined(BUILD_tcl) +# undef Tcl_NumUtfChars +# define Tcl_NumUtfChars TclNumUtfChars +# undef Tcl_GetCharLength +# define Tcl_GetCharLength TclGetCharLength +# undef Tcl_UtfAtIndex +# define Tcl_UtfAtIndex TclUtfAtIndex +# undef Tcl_GetRange +# define Tcl_GetRange TclGetRange +# undef Tcl_GetUniChar +# define Tcl_GetUniChar TclGetUniChar +#endif +#endif +#if defined(USE_TCL_STUBS) +# define Tcl_WCharToUtfDString (sizeof(wchar_t) != sizeof(short) \ + ? (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))tclStubsPtr->tcl_UniCharToUtfDString \ + : (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_Char16ToUtfDString) +# define Tcl_UtfToWCharDString (sizeof(wchar_t) != sizeof(short) \ + ? (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))tclStubsPtr->tcl_UtfToUniCharDString \ + : (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToChar16DString) +# define Tcl_UtfToWChar (sizeof(wchar_t) != sizeof(short) \ + ? (Tcl_Size (*)(const char *, wchar_t *))tclStubsPtr->tcl_UtfToUniChar \ + : (Tcl_Size (*)(const char *, wchar_t *))Tcl_UtfToChar16) +# define Tcl_WCharLen (sizeof(wchar_t) != sizeof(short) \ + ? (Tcl_Size (*)(wchar_t *))tclStubsPtr->tcl_UniCharLen \ + : (Tcl_Size (*)(wchar_t *))Tcl_Char16Len) +#else +# define Tcl_WCharToUtfDString (sizeof(wchar_t) != sizeof(short) \ + ? (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_UniCharToUtfDString \ + : (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_Char16ToUtfDString) +# define Tcl_UtfToWCharDString (sizeof(wchar_t) != sizeof(short) \ + ? (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToUniCharDString \ + : (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToChar16DString) +# define Tcl_UtfToWChar (sizeof(wchar_t) != sizeof(short) \ + ? (Tcl_Size (*)(const char *, wchar_t *))Tcl_UtfToUniChar \ + : (Tcl_Size (*)(const char *, wchar_t *))Tcl_UtfToChar16) +# define Tcl_WCharLen (sizeof(wchar_t) != sizeof(short) \ + ? (Tcl_Size (*)(wchar_t *))Tcl_UniCharLen \ + : (Tcl_Size (*)(wchar_t *))Tcl_Char16Len) +#endif + +/* + * Deprecated Tcl procedures: + */ + +#define Tcl_EvalObj(interp, objPtr) \ + Tcl_EvalObjEx(interp, objPtr, 0) +#define Tcl_GlobalEvalObj(interp, objPtr) \ + Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL) + +#if TCL_MAJOR_VERSION > 8 +# undef Tcl_Close +# define Tcl_Close(interp, chan) Tcl_CloseEx(interp, chan, 0) +#endif + +#undef TclUtfCharComplete +#undef TclUtfNext +#undef TclUtfPrev +#ifndef TCL_NO_DEPRECATED +# define Tcl_CreateSlave Tcl_CreateChild +# define Tcl_GetSlave Tcl_GetChild +# define Tcl_GetMaster Tcl_GetParent +#endif + +#ifdef USE_TCL_STUBS + /* Protect those 10 functions, make them useless through the stub table */ +# undef TclGetStringFromObj +# undef TclGetBytesFromObj +# undef TclGetUnicodeFromObj +# undef TclListObjGetElements +# undef TclListObjLength +# undef TclDictObjSize +# undef TclSplitList +# undef TclSplitPath +# undef TclFSSplitPath +# undef TclParseArgsObjv +#endif + +#if TCL_MAJOR_VERSION < 9 + /* TIP #627 for 8.7 */ +# undef Tcl_CreateObjCommand2 +# define Tcl_CreateObjCommand2 Tcl_CreateObjCommand +# undef Tcl_CreateObjTrace2 +# define Tcl_CreateObjTrace2 Tcl_CreateObjTrace +# undef Tcl_NRCreateCommand2 +# define Tcl_NRCreateCommand2 Tcl_NRCreateCommand +# undef Tcl_NRCallObjProc2 +# define Tcl_NRCallObjProc2 Tcl_NRCallObjProc + /* TIP #660 for 8.7 */ +# undef Tcl_GetSizeIntFromObj +# define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj + +# undef Tcl_GetBytesFromObj +# define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) \ + tclStubsPtr->tclGetBytesFromObj((interp), (objPtr), (sizePtr)) +# undef Tcl_GetStringFromObj +# define Tcl_GetStringFromObj(objPtr, sizePtr) \ + tclStubsPtr->tclGetStringFromObj((objPtr), (sizePtr)) +# undef Tcl_GetUnicodeFromObj +# define Tcl_GetUnicodeFromObj(objPtr, sizePtr) \ + tclStubsPtr->tclGetUnicodeFromObj((objPtr), (sizePtr)) +# undef Tcl_ListObjGetElements +# define Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr) \ + tclStubsPtr->tclListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)) +# undef Tcl_ListObjLength +# define Tcl_ListObjLength(interp, listPtr, lengthPtr) \ + tclStubsPtr->tclListObjLength((interp), (listPtr), (lengthPtr)) +# undef Tcl_DictObjSize +# define Tcl_DictObjSize(interp, dictPtr, sizePtr) \ + tclStubsPtr->tclDictObjSize((interp), (dictPtr), (sizePtr)) +# undef Tcl_SplitList +# define Tcl_SplitList(interp, listStr, argcPtr, argvPtr) \ + tclStubsPtr->tclSplitList((interp), (listStr), (argcPtr), (argvPtr)) +# undef Tcl_SplitPath +# define Tcl_SplitPath(path, argcPtr, argvPtr) \ + tclStubsPtr->tclSplitPath((path), (argcPtr), (argvPtr)) +# undef Tcl_FSSplitPath +# define Tcl_FSSplitPath(pathPtr, lenPtr) \ + tclStubsPtr->tclFSSplitPath((pathPtr), (lenPtr)) +# undef Tcl_ParseArgsObjv +# define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) \ + tclStubsPtr->tclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) +#elif defined(TCL_8_API) +# undef Tcl_GetByteArrayFromObj +# undef Tcl_GetBytesFromObj +# undef Tcl_GetStringFromObj +# undef Tcl_GetUnicodeFromObj +# undef Tcl_ListObjGetElements +# undef Tcl_ListObjLength +# undef Tcl_DictObjSize +# undef Tcl_SplitList +# undef Tcl_SplitPath +# undef Tcl_FSSplitPath +# undef Tcl_ParseArgsObjv +# if !defined(USE_TCL_STUBS) +# define Tcl_GetByteArrayFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + TclGetBytesFromObj(NULL, (objPtr), (sizePtr)) : \ + (Tcl_GetBytesFromObj)(NULL, (objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + TclGetBytesFromObj((interp), (objPtr), (sizePtr)) : \ + (Tcl_GetBytesFromObj)((interp), (objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_GetStringFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + TclGetStringFromObj((objPtr), (sizePtr)) : \ + (Tcl_GetStringFromObj)((objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_GetUnicodeFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + TclGetUnicodeFromObj((objPtr), (sizePtr)) : \ + (Tcl_GetUnicodeFromObj)((objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr) (sizeof(*(objcPtr)) <= sizeof(int) ? \ + TclListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)) : \ + (Tcl_ListObjGetElements)((interp), (listPtr), (Tcl_Size *)(void *)(objcPtr), (objvPtr))) +# define Tcl_ListObjLength(interp, listPtr, lengthPtr) (sizeof(*(lengthPtr)) <= sizeof(int) ? \ + TclListObjLength((interp), (listPtr), (lengthPtr)) : \ + (Tcl_ListObjLength)((interp), (listPtr), (Tcl_Size *)(void *)(lengthPtr))) +# define Tcl_DictObjSize(interp, dictPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + TclDictObjSize((interp), (dictPtr), (sizePtr)) : \ + (Tcl_DictObjSize)((interp), (dictPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_SplitList(interp, listStr, argcPtr, argvPtr) (sizeof(*(argcPtr)) <= sizeof(int) ? \ + TclSplitList((interp), (listStr), (argcPtr), (argvPtr)) : \ + (Tcl_SplitList)((interp), (listStr), (Tcl_Size *)(void *)(argcPtr), (argvPtr))) +# define Tcl_SplitPath(path, argcPtr, argvPtr) (sizeof(*(argcPtr)) <= sizeof(int) ? \ + TclSplitPath((path), (argcPtr), (argvPtr)) : \ + (Tcl_SplitPath)((path), (Tcl_Size *)(void *)(argcPtr), (argvPtr))) +# define Tcl_FSSplitPath(pathPtr, lenPtr) (sizeof(*(lenPtr)) <= sizeof(int) ? \ + TclFSSplitPath((pathPtr), (lenPtr)) : \ + (Tcl_FSSplitPath)((pathPtr), (Tcl_Size *)(void *)(lenPtr))) +# define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ + TclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) : \ + (Tcl_ParseArgsObjv)((interp), (argTable), (Tcl_Size *)(void *)(objcPtr), (objv), (remObjv))) +# elif !defined(BUILD_tcl) +# define Tcl_GetByteArrayFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + tclStubsPtr->tclGetBytesFromObj(NULL, (objPtr), (sizePtr)) : \ + tclStubsPtr->tcl_GetBytesFromObj(NULL, (objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + tclStubsPtr->tclGetBytesFromObj((interp), (objPtr), (sizePtr)) : \ + tclStubsPtr->tcl_GetBytesFromObj((interp), (objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_GetStringFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + tclStubsPtr->tclGetStringFromObj((objPtr), (sizePtr)) : \ + tclStubsPtr->tcl_GetStringFromObj((objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_GetUnicodeFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + tclStubsPtr->tclGetUnicodeFromObj((objPtr), (sizePtr)) : \ + tclStubsPtr->tcl_GetUnicodeFromObj((objPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr) (sizeof(*(objcPtr)) <= sizeof(int) ? \ + tclStubsPtr->tclListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)) : \ + tclStubsPtr->tcl_ListObjGetElements((interp), (listPtr), (Tcl_Size *)(void *)(objcPtr), (objvPtr))) +# define Tcl_ListObjLength(interp, listPtr, lengthPtr) (sizeof(*(lengthPtr)) <= sizeof(int) ? \ + tclStubsPtr->tclListObjLength((interp), (listPtr), (lengthPtr)) : \ + tclStubsPtr->tcl_ListObjLength((interp), (listPtr), (Tcl_Size *)(void *)(lengthPtr))) +# define Tcl_DictObjSize(interp, dictPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ + tclStubsPtr->tclDictObjSize((interp), (dictPtr), (sizePtr)) : \ + tclStubsPtr->tcl_DictObjSize((interp), (dictPtr), (Tcl_Size *)(void *)(sizePtr))) +# define Tcl_SplitList(interp, listStr, argcPtr, argvPtr) (sizeof(*(argcPtr)) <= sizeof(int) ? \ + tclStubsPtr->tclSplitList((interp), (listStr), (argcPtr), (argvPtr)) : \ + tclStubsPtr->tcl_SplitList((interp), (listStr), (Tcl_Size *)(void *)(argcPtr), (argvPtr))) +# define Tcl_SplitPath(path, argcPtr, argvPtr) (sizeof(*(argcPtr)) <= sizeof(int) ? \ + tclStubsPtr->tclSplitPath((path), (argcPtr), (argvPtr)) : \ + tclStubsPtr->tcl_SplitPath((path), (Tcl_Size *)(void *)(argcPtr), (argvPtr))) +# define Tcl_FSSplitPath(pathPtr, lenPtr) (sizeof(*(lenPtr)) <= sizeof(int) ? \ + tclStubsPtr->tclFSSplitPath((pathPtr), (lenPtr)) : \ + tclStubsPtr->tcl_FSSplitPath((pathPtr), (Tcl_Size *)(void *)(lenPtr))) +# define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ + tclStubsPtr->tclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) : \ + tclStubsPtr->tcl_ParseArgsObjv((interp), (argTable), (Tcl_Size *)(void *)(objcPtr), (objv), (remObjv))) +# endif /* defined(USE_TCL_STUBS) */ +#else /* !defined(TCL_8_API) */ +# undef Tcl_GetByteArrayFromObj +# define Tcl_GetByteArrayFromObj(objPtr, sizePtr) \ + Tcl_GetBytesFromObj(NULL, (objPtr), (sizePtr)) +#endif /* defined(TCL_8_API) */ + +#endif /* _TCLDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tclPlatDecls.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tclPlatDecls.h new file mode 100644 index 00000000..b8243d2f --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tcl9.0/tclPlatDecls.h @@ -0,0 +1,228 @@ +/* + * tclPlatDecls.h -- + * + * Declarations of platform specific Tcl APIs. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * All rights reserved. + */ + +#ifndef _TCLPLATDECLS +#define _TCLPLATDECLS + +#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 + +/* + * 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. + */ + +/* + * 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 + +#ifndef MODULE_SCOPE +# ifdef __cplusplus +# define MODULE_SCOPE extern "C" +# else +# define MODULE_SCOPE extern +# endif +#endif + +#if TCL_MAJOR_VERSION < 9 + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +/* 0 */ +EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len, + Tcl_DString *dsPtr); +/* 1 */ +EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len, + Tcl_DString *dsPtr); +/* Slot 2 is reserved */ +/* 3 */ +EXTERN void Tcl_WinConvertError(unsigned errCode); +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ +/* 0 */ +EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, + const char *bundleName, int hasResourceFile, + Tcl_Size maxPathLen, char *libraryPath); +/* 1 */ +EXTERN int Tcl_MacOSXOpenVersionedBundleResources( + Tcl_Interp *interp, const char *bundleName, + const char *bundleVersion, + int hasResourceFile, Tcl_Size maxPathLen, + char *libraryPath); +/* 2 */ +EXTERN void Tcl_MacOSXNotifierAddRunLoopMode( + const void *runLoopMode); +#endif /* MACOSX */ + +typedef struct TclPlatStubs { + int magic; + void *hooks; + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ + TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */ + char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */ + void (*reserved2)(void); + void (*tcl_WinConvertError) (unsigned errCode); /* 3 */ +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ + int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 0 */ + int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 1 */ + void (*tcl_MacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 2 */ +#endif /* MACOSX */ +} TclPlatStubs; + +extern const TclPlatStubs *tclPlatStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ +#define Tcl_WinUtfToTChar \ + (tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */ +#define Tcl_WinTCharToUtf \ + (tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */ +/* Slot 2 is reserved */ +#define Tcl_WinConvertError \ + (tclPlatStubsPtr->tcl_WinConvertError) /* 3 */ +#endif /* WIN */ +#ifdef MAC_OSX_TCL /* MACOSX */ +#define Tcl_MacOSXOpenBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ +#define Tcl_MacOSXOpenVersionedBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ +#define Tcl_MacOSXNotifierAddRunLoopMode \ + (tclPlatStubsPtr->tcl_MacOSXNotifierAddRunLoopMode) /* 2 */ +#endif /* MACOSX */ + +#endif /* defined(USE_TCL_STUBS) */ + +#else /* TCL_MAJOR_VERSION > 8 */ + +/* !BEGIN!: Do not edit below this line. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Exported function declarations: + */ + +/* Slot 0 is reserved */ +/* 1 */ +EXTERN int Tcl_MacOSXOpenVersionedBundleResources( + Tcl_Interp *interp, const char *bundleName, + const char *bundleVersion, + int hasResourceFile, Tcl_Size maxPathLen, + char *libraryPath); +/* 2 */ +EXTERN void Tcl_MacOSXNotifierAddRunLoopMode( + const void *runLoopMode); +/* 3 */ +EXTERN void Tcl_WinConvertError(unsigned errCode); + +typedef struct TclPlatStubs { + int magic; + void *hooks; + + void (*reserved0)(void); + int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 1 */ + void (*tcl_MacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 2 */ + void (*tcl_WinConvertError) (unsigned errCode); /* 3 */ +} TclPlatStubs; + +extern const TclPlatStubs *tclPlatStubsPtr; + +#ifdef __cplusplus +} +#endif + +#if defined(USE_TCL_STUBS) + +/* + * Inline function declarations: + */ + +/* Slot 0 is reserved */ +#define Tcl_MacOSXOpenVersionedBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ +#define Tcl_MacOSXNotifierAddRunLoopMode \ + (tclPlatStubsPtr->tcl_MacOSXNotifierAddRunLoopMode) /* 2 */ +#define Tcl_WinConvertError \ + (tclPlatStubsPtr->tcl_WinConvertError) /* 3 */ + +#endif /* defined(USE_TCL_STUBS) */ + +/* !END!: Do not edit above this line. */ + +#endif /* TCL_MAJOR_VERSION */ + +#ifdef MAC_OSX_TCL /* MACOSX */ +#undef Tcl_MacOSXOpenBundleResources +#define Tcl_MacOSXOpenBundleResources(a,b,c,d,e) Tcl_MacOSXOpenVersionedBundleResources(a,b,NULL,c,d,e) +#endif + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#ifdef _WIN32 +# undef Tcl_CreateFileHandler +# undef Tcl_DeleteFileHandler +# undef Tcl_GetOpenFile +#endif +#ifndef MAC_OSX_TCL +# undef Tcl_MacOSXOpenVersionedBundleResources +# undef Tcl_MacOSXNotifierAddRunLoopMode +#endif + +#if defined(USE_TCL_STUBS) && (defined(_WIN32) || defined(__CYGWIN__))\ + && (defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8) +#undef Tcl_WinUtfToTChar +#undef Tcl_WinTCharToUtf +#ifdef _WIN32 +#define Tcl_WinUtfToTChar(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ + (TCHAR *)Tcl_UtfToChar16DString((string), (len), (dsPtr))) +#define Tcl_WinTCharToUtf(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ + (char *)Tcl_Char16ToUtfDString((const unsigned short *)(string), ((((len) + 2) >> 1) - 1), (dsPtr))) +#endif +#endif + +#endif /* _TCLPLATDECLS */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tclAppInit.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tclAppInit.c new file mode 100644 index 00000000..fd4bc5af --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tclAppInit.c @@ -0,0 +1,179 @@ +/* + * tclAppInit.c -- + * + * Provides a default version of the main program and Tcl_AppInit + * function 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. + * + * RCS: @(#) $Id: tclAppInit.c 1325 2007-03-29 07:27:33Z jcw $ + */ + +#include "tcl.h" + +#ifdef TCL_TEST + +#include "tclInt.h" + +extern Tcl_PackageInitProc Procbodytest_Init; +extern Tcl_PackageInitProc Procbodytest_SafeInit; +extern Tcl_PackageInitProc TclObjTest_Init; +extern Tcl_PackageInitProc Tcltest_Init; + +#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 function 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 does + * not 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 function performs application-specific initialization. Most + * applications, especially those that incorporate additional packages, + * will have their own version of this function. + * + * 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; + } + if (Procbodytest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, + Procbodytest_SafeInit); +#endif /* TCL_TEST */ + + /* + * Call the init functions 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. (Dynamically-loadable packages + * should have the same entry-point name.) + */ + + /* + * Call Tcl_CreateCommand for application-specific commands, if they + * weren't already created by the init functions 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; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tclpre9compat.h b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tclpre9compat.h new file mode 100644 index 00000000..50421772 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tclpre9compat.h @@ -0,0 +1,73 @@ +#ifndef CRITCL_TCL9_COMPAT_H +#define CRITCL_TCL9_COMPAT_H + +/* Disable the macros making us believe that everything is hunky-dory on compilation, and then + * reward us with runtime crashes for being a sucker to have believed them. + */ +#define TCL_NO_DEPRECATED + +#include "tcl.h" + +/* + * - - -- --- ----- -------- ------------- --------------------- + * Check for support of the `Tcl_Size` typdef and associated definitions. + * It was introduced in Tcl 8.7 and 9, and we need backward compatibility + * definitions for 8.6. + */ + +#ifndef TCL_SIZE_MAX + #include + #define TCL_SIZE_MAX INT_MAX + + #ifndef Tcl_Size + typedef int Tcl_Size; + #endif + + /* TIP #494 constants, for 8.6 too */ + #define TCL_IO_FAILURE ((Tcl_Size)-1) + #define TCL_AUTO_LENGTH ((Tcl_Size)-1) + #define TCL_INDEX_NONE ((Tcl_Size)-1) + + #define TCL_SIZE_MODIFIER "" + #define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj + #define Tcl_NewSizeIntObj Tcl_NewIntObj +#else + #define Tcl_NewSizeIntObj Tcl_NewWideIntObj +#endif + +#define TCL_SIZE_FMT "%" TCL_SIZE_MODIFIER "d" + +/* + * - - -- --- ----- -------- ------------- --------------------- + * Critcl (3.2.1+) emits the command creation API using Tcl_Size by default. + * Map this to the older int-based API when compiling against Tcl 8.x or older. + * + * Further map use of `Tcl_GetBytesFromObj` to the old `Tcl_GetByteArrayFromObj`. + * This loses the interp argument, and the ability to return NULL. + */ + +#if TCL_MAJOR_VERSION <= 8 +#define Tcl_CreateObjCommand2 Tcl_CreateObjCommand +#define Tcl_GetBytesFromObj(interp,obj,sizeptr) Tcl_GetByteArrayFromObj(obj,sizeptr) +#endif + +/* + * - - -- --- ----- -------- ------------- --------------------- + */ + +#ifndef CONST +#define CONST const +#endif + +#ifndef CONST84 +#define CONST84 const +#endif + +#ifndef CONST86 +#define CONST86 const +#endif + +/* + * - - -- --- ----- -------- ------------- --------------------- + */ +#endif /* CRITCL_TCL9_COMPAT_H */ diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tkstubs.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tkstubs.c new file mode 100644 index 00000000..a4f3f27e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tkstubs.c @@ -0,0 +1,24 @@ + +#if USE_TK_STUBS + + const TkStubs *tkStubsPtr; + const struct TkPlatStubs *tkPlatStubsPtr; + const struct TkIntStubs *tkIntStubsPtr; + const struct TkIntPlatStubs *tkIntPlatStubsPtr; + const struct TkIntXlibStubs *tkIntXlibStubsPtr; + + static int + MyInitTkStubs (Tcl_Interp *ip) + { + if (Tcl_PkgRequireEx(ip, "Tk", "8.1", 0, (ClientData*) &tkStubsPtr) == NULL) return 0; + if (tkStubsPtr == NULL || tkStubsPtr->hooks == NULL) { + Tcl_SetResult(ip, "This extension requires Tk stubs-support.", TCL_STATIC); + return 0; + } + tkPlatStubsPtr = tkStubsPtr->hooks->tkPlatStubs; + tkIntStubsPtr = tkStubsPtr->hooks->tkIntStubs; + tkIntPlatStubsPtr = tkStubsPtr->hooks->tkIntPlatStubs; + tkIntXlibStubsPtr = tkStubsPtr->hooks->tkIntXlibStubs; + return 1; + } +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/critcl_c/tkstubs_noconst.c b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tkstubs_noconst.c new file mode 100644 index 00000000..36a0f7b8 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/critcl_c/tkstubs_noconst.c @@ -0,0 +1,27 @@ + +#if USE_TK_STUBS + /* Pre 8.6 two of the variables are not declared const. + * Prevent mismatch with tkDecls.h + */ + + TkStubs *tkStubsPtr; + const struct TkPlatStubs *tkPlatStubsPtr; + const struct TkIntStubs *tkIntStubsPtr; + const struct TkIntPlatStubs *tkIntPlatStubsPtr; + struct TkIntXlibStubs *tkIntXlibStubsPtr; + + static int + MyInitTkStubs (Tcl_Interp *ip) + { + if (Tcl_PkgRequireEx(ip, "Tk", "8.1", 0, (ClientData*) &tkStubsPtr) == NULL) return 0; + if (tkStubsPtr == NULL || tkStubsPtr->hooks == NULL) { + Tcl_SetResult(ip, "This extension requires Tk stubs-support.", TCL_STATIC); + return 0; + } + tkPlatStubsPtr = tkStubsPtr->hooks->tkPlatStubs; + tkIntStubsPtr = tkStubsPtr->hooks->tkIntStubs; + tkIntPlatStubsPtr = tkStubsPtr->hooks->tkIntPlatStubs; + tkIntXlibStubsPtr = tkStubsPtr->hooks->tkIntXlibStubs; + return 1; + } +#endif diff --git a/src/vfs/critcl.vfs/lib/critcl/license.terms b/src/vfs/critcl.vfs/lib/critcl/license.terms new file mode 100644 index 00000000..16e6bdf7 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/license.terms @@ -0,0 +1,40 @@ +This software is copyrighted by Jean-Claude Wippler, Steve Landers, +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. diff --git a/src/vfs/critcl.vfs/lib/critcl/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critcl/pkgIndex.tcl new file mode 100644 index 00000000..e3fa617d --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critcl/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critcl 3.2.1 [list source [file join $dir critcl.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critclf/Config b/src/vfs/critcl.vfs/lib/critclf/Config new file mode 100644 index 00000000..7b7e566a --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/Config @@ -0,0 +1,9 @@ +# Fortran-specific flags +# +fcompile g95 -c +fversion g95 -v +flink g95 -shared +finclude -I +foutput -o $outfile +foptimize -O2 +fextra_cflags -DFTN_UNDERSCORE -D__unix diff --git a/src/vfs/critcl.vfs/lib/critclf/critclf.tcl b/src/vfs/critcl.vfs/lib/critclf/critclf.tcl new file mode 100644 index 00000000..4b739b72 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/critclf.tcl @@ -0,0 +1,524 @@ +# critclf.tcl -- +# Fortran version of Critcl +# +package require Tcl 8.6 9 +package provide critclf 0.3 +package require critcl 3.2 +package require wrapfort + +namespace eval critcl { + + # + # Public procedures + # + namespace export fproc + + variable fsrc ;# File with Fortran source code + + variable ftype ;# Fortran types + set ftype(integer) "integer :: VNAME" + set ftype(integer-array) "integer :: size__VNAME; integer, dimension(SIZE) :: VNAME" + set ftype(real) "real(kind=kind(1.0d0)) :: VNAME" + set ftype(real-array) "integer :: size__VNAME; real, dimension(SIZE) :: VNAME" + set ftype(double) "real(kind=kind(1.0d0)) :: VNAME" + set ftype(double-array) "integer :: size__VNAME; real(kind=kind(1.0d0)), dimension(SIZE) :: VNAME" + + # + # Private namespaces for convenience: + # - Store the configuration parameters + # - Re-read the configuration file + # + namespace eval v { + variable fconfigvars {fcompile fversion finclude flink foutput + foptimize fextra_cflags} + set configvars [concat $configvars $fconfigvars] + } + namespace eval c [list + foreach var $v::fconfigvars { + variable $var + } + ] + readconfig $configfile +} + + +# Femit, Femitln, Cmdemit -- +# Store Fortran and C code in a private variable for later reference +# +# Arguments: +# s Fragment of Fortran code to be stored +# +# Result: +# None +# +proc ::critcl::Femit {s} { + append v::fcode($v::curr) $s +} + +proc ::critcl::Femitln {{s ""}} { + Femit "$s\n" +} + +proc ::critcl::Cmdemit {s} { + append v::cmdcode($v::curr) $s +} + + +# Fdefine -- +# Register the new command for later use +# +# Arguments: +# name Name of the new command +# args Argument list and body +# +# Result: +# None +# +proc ::critcl::Fdefine {name args} { + set v::curr [md5_hex "$name $args"] + set file [file normalize [info script]] + + set ns [uplevel 2 namespace current] + if {$ns == "::"} { set ns "" } else { append ns :: } + + set ::auto_index($ns$name) [list [namespace current]::fbuild $file] + + lappend v::code($file,list) $name $v::curr +} + + + +# FortCall -- +# Generate a fragment of C to call the Fortran routine +# +# Arguments: +# name Name of the Fortran subroutine +# carguments List of arguments (already in C form) +# +# Result: +# C code fragment +# +# Note: +# Will probably need to be revised +# +proc ::critcl::FortCall {name carguments} { + + return " $name\( [join $carguments ,] );" + +} + + +# FortDeclaration -- +# Generate a proper Fortran declaration +# +# Arguments: +# type Type of the variable +# vname Name of the variable +# data Additional information +# +# Result: +# Fortran declaration +# +proc ::critcl::FortDeclaration {type vname data} { + variable ftype + + if { [string match "*-array" $type] } { + set size [string map {"size(" "size__" ")" ""} [lindex $data 1]] + return [string map [list VNAME $vname SIZE $size] $ftype($type)] + } else { + return [string map [list VNAME $vname] $ftype($type)] + } +} + + +# fproc -- +# Generate the Tcl/C wrapper for a command written in Fortran +# +# Arguments: +# name Name of the Fortran subroutine and Tcl command +# arguments Description of the arguments +# body Body of the Fortran subroutine +# +# Result: +# None +# +# Note: +# This relies for the most part on Wrapfort for the actual +# generation of the source code +# +proc ::critcl::fproc {name arguments body} { + + ::Wrapfort::incritcl 1 + + Fdefine $name $arguments $body + + Femit "subroutine $name\( &\n " + + set farglist {} + set fdecls {} + set carglist {} + set carguments {} + foreach {type vname data} $arguments { + set role [lindex $data 0] + + switch -- $role { + "input" - + "output" - + "result" { + lappend fdecls [FortDeclaration $type $vname $data] + if { ! [string match "*-array" $type] } { + lappend farglist $vname + lappend carglist "&$vname" + } else { + lappend farglist "$vname, size__$vname" + lappend carglist "$vname, &size__$vname" + set carguments [concat $carguments "integer size__$vname {assign size($vname)}"] + } + } + } + if { $type == "external" } { + lappend farglist $vname + lappend carglist "$vname" + } + } + + Femitln "[join $farglist ",&\n "])" + Femitln " [join $fdecls "\n "]" + Femitln $body ;# TODO: use statements + Femitln "end subroutine $name" + + ::Wrapfort::fproc $name $name \ + [concat $arguments $carguments code [list {Call the routine}] \ + [list [FortCall $name $carglist]]] + + ::Wrapfort::incritcl 0 +} + + +# fexternal -- +# Generate the C wrapper for a Tcl command to be called as an +# external function in Fortran +# +# Arguments: +# name Name of the Fortran interface +# arguments Description of the arguments and the surrounding code +# +# Result: +# None +# +# Note: +# This relies for the most part on Wrapfort for the actual +# generation of the source code +# +proc ::critcl::fexternal {name arguments} { + + ::Wrapfort::incritcl 1 + ::Wrapfort::fexternal $name $arguments + ::Wrapfort::incritcl 0 + +} + + +# fcompile -- +# Compile the generated Fortran code +# +# Arguments: +# file Name of the Fortran source file +# src Complete source code +# lfd Log file +# obj Name of the object file +# +# Result: +# None +# +proc ::critcl::fcompile {file src fopts lfd obj} { + variable run + set cmdline "$c::fcompile $fopts" + set outfile $obj + append cmdline " [subst $c::foutput] $src" + if {$v::options(language) != ""} { + # Allow the compiler to determine the type of file + # otherwise it will try to compile the libs + append cmdline " -x none" + } + if {!$option::debug_symbols} { + append cmdline " $c::foptimize" + } + puts $lfd $cmdline + set v::failed 0 + interp transfer {} $lfd $run + if {[catch { + interp eval $run "exec $cmdline 2>@ $lfd" + interp transfer $run $lfd {} + if {!$v::options(keepsrc) && $src ne $file} { file delete $src } + puts $lfd "$obj: [file size $obj] bytes" + } err]} { + puts $err + interp transfer $run $lfd {} + puts $lfd "ERROR while compiling code in $file:" + puts $lfd $err + incr v::failed + } +} + + +# fbuild -- +# Build the library +# +# Arguments: +# file Name of the library +# load When completed, load the library (or not) +# prefix Prefix for the name of the library +# silent Suppress error message (or not) +# +# Result: +# None +# +proc ::critcl::fbuild {{file ""} {load 1} {prefix {}} {silent ""}} { + if {$file eq ""} { + set link 1 + set file [file normalize [info script]] + } else { + set link 0 + } + + # each unique set of cmds is compiled into a separate extension + # ?? + set digest [md5_hex "$file $v::code($file,list)"] + + set cache $v::cache + set cache [file normalize $cache] + + set base [file join $cache ${v::prefix}_$digest] + set libfile $base + + # the compiled library will be saved for permanent use if the outdir + # option is set (in which case rebuilds will no longer be automatic) + if {$v::options(outdir) != ""} { + set odir [file join [file dirname $file] $v::options(outdir)] + set oroot [file root [file tail $file]] + set libfile [file normalize [file join $odir $oroot]] + file mkdir $odir + } + # get the settings for this file into local variables + foreach x {hdrs srcs libs init ext} { + set $x [append v::code($file,$x) ""] ;# make sure it exists + } + + # modify the output file name if debugging symbols are requested + if {$option::debug_symbols} { + append libfile _g + } + + # choose distinct suffix so switching between them causes a rebuild + switch -- $v::options(combine) { + "" - + dynamic { append libfile _pic$c::object } + static { append libfile _stub$c::object } + standalone { append libfile $c::object } + } + + # the init proc name takes a capitalized prefix from the package name + set ininame stdin ;# in case it's called interactively + regexp {^\w+} [file tail $file] ininame + set pkgname $ininame + set ininame [string totitle $ininame] + if {$prefix != {}} { + set pkgname "${prefix}_$pkgname" + set ininame "${prefix}_$ininame" + } + + # the shared library we hope to produce + set target $base$c::sharedlibext + if {$v::options(force) || ![file exists $target]} { + file mkdir $cache + + set log [file join $cache [pid].log] + set lfd [open $log w] + puts $lfd "\n[clock format [clock seconds]] - $file" + + ::Wrapfort::incritcl 1 + ::Wrapfort::fsource $pkgname $base.c + ::Wrapfort::incritcl 0 + set ffile [open ${base}_f.f90 w] + set cmdfile [open $::Wrapfort::tclfname w] + set fd [open ${base}.c w] + set names {} + + puts $fd "/* Generated by critcl on [clock format [clock seconds]] + * source: $file + * binary: $libfile + */" + foreach {name digest} $v::code($file,list) { + if {[info exists v::code($digest)]} { + puts $fd $v::code($digest) + } + if {[info exists v::fcode($digest)]} { + puts $ffile $v::fcode($digest) + } + if {[info exists v::cmdcode($digest)]} { + puts $cmdfile $v::cmdcode($digest) + } + } + close $fd + close $cmdfile + close $ffile + + set copts [list] + if {$v::options(language) != ""} { + lappend fopts -x $v::options(language) + } + if {$v::options(I) != ""} { + lappend copts $c::include$v:::options(I) + } + lappend copts $c::include$cache + + set fopts [list] + if {$v::options(language) != ""} { + lappend fopts -x $v::options(language) + } + if {$v::options(I) != ""} { + lappend fopts $c::finclude$v:::options(I) + } + lappend fopts $c::finclude$cache + set copies {} + foreach x $hdrs { + if {[string index $x 0] == "-"} { + lappend copts $x + } else { + set copy [file join $cache [file tail $x]] + file delete $copy + file copy $x $copy + lappend copies $copy + } + } + + fcompile $file ${base}_f.f90 $fopts $lfd $libfile + append copts " $c::fextra_cflags" + + set c::compile "gcc -c -fPIC" + set c::cflags "" + set c::threadflags "" + set c::output "-o \$outfile" + set c::optimize "-O" + set c::link_release "" + set c::ldoutput "" + set copts " $c::fextra_cflags" + file copy -force [file join $::Wrapfort::wrapdir "wrapfort_lib.c"] [file dirname $base] + compile $file $::Wrapfort::pkgfname $copts $lfd ${base}_c$c::object + lappend v::objs ${base}_c$c::object + + if { !$v::options(keepsrc) } { + # file delete $::Wrapfort::tclfname -- AM: this does not work yet! + # the file remains open somewhere? + # file delete $base.c + } + + foreach src $srcs { + set tail [file tail $src] + set srcbase [file rootname [file tail $src]] + if {[file dirname $base] ne [file dirname $src]} { + set srcbase [file tail [file dirname $src]]_$srcbase + } + set obj [file join [file normalize $cache] ${srcbase}$c::object] + compile $src $src $copts $lfd $obj + lappend v::objs $obj + } + if {($load || $link) && !$v::failed} { + set cmdline $c::flink + if {[llength $v::preload]} { + append cmdline " $c::link_preload" + } + set outfile $target + if {[string length [set ldout [subst $c::ldoutput]]] == 0} { + set ldout [subst $c::output] + } + if {$option::debug_symbols} { + append cmdline " $c::link_debug $ldout" + } else { + append cmdline " $c::strip $c::link_release $ldout" + } + if {[string match "win32-*-cl" [Platform]]} { + regsub -all -- {-l(\S+)} $libs {\1.lib} libs + } + append cmdline " $libfile " +#AM if {[string match "win32-*-cl" [Platform]]} { +# set f [open [set rsp [file join $cache link.fil]] w] +# puts $f [join $v::objs \n] +# close $f +# append cmdline @$rsp +# } else {} + append cmdline [join [lsort -unique $v::objs]] +# {} + append cmdline " $libs $v::ldflags" + puts $lfd "\n$cmdline" + variable run + interp transfer {} $lfd $run + if {[catch { + interp eval $run "exec $cmdline 2>@ $lfd" + interp transfer $run $lfd {} + puts $lfd "$target: [file size $target] bytes" + } err]} { + interp transfer $run $lfd {} + puts $lfd "ERROR while linking $target:" + incr v::failed + } + if {!$v::failed && [llength $v::preload]} { + # compile preload if necessary + set outfile [file join [file dirname $base] \ + preload$c::sharedlibext] + if {![file readable $outfile]} { + set src [file join $v::cache preload.c] + set obj [file join $v::cache preload.o] + compile $src $src $copts $lfd $obj + set cmdline "$c::link $obj $c::strip [subst $c::output]" + puts $lfd "\n$cmdline" + interp transfer {} $lfd $run + if {[catch { + interp eval $run "exec $cmdline 2>@ $lfd" + interp transfer $run $lfd {} + puts $lfd "$outfile: [file size $target] bytes" + } err]} { + interp transfer $run $lfd {} + puts $lfd "ERROR while linking $outfile:" + incr v::failed + } + } + } + } + # read build log + close $lfd + set lfd [open $log] + set msgs [read $lfd] + close $lfd + file delete -force $log + # append to critcl log + set log [file join $cache $v::prefix.log] + set lfd [open $log a] + puts $lfd $msgs + close $lfd + foreach x $copies { file delete $x } + } + + if {$v::failed} { + if {$silent == ""} { + puts stderr $msgs + puts stderr "critcl build failed ($file)" + } + } elseif {$load} { + load $target $ininame + } + + foreach {name digest} $v::code($file,list) { + if {$name != "" && [info exists v::code($digest)]} { + unset v::code($digest) + } + } + foreach x {hdrs srcs init} { + array unset v::code $file,$x + } + if {$link} { + return [list $target $ininame] + } + return [list $libfile $ininame] +} diff --git a/src/vfs/critcl.vfs/lib/critclf/idx_wrap.tcl b/src/vfs/critcl.vfs/lib/critclf/idx_wrap.tcl new file mode 100644 index 00000000..b14488c0 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/idx_wrap.tcl @@ -0,0 +1,6 @@ +# Package index file for PKGNAME +# +if { [package vsatisfies [package provide Tcl] 8.2]} {return} +package ifneeded PKGNAME 1.0 [list load [file join $dir PKGNAME.dll]] + +# Note: add support for other platforms! diff --git a/src/vfs/critcl.vfs/lib/critclf/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/critclf/pkgIndex.tcl new file mode 100644 index 00000000..5da4c2f4 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded critclf 0.3 [list source [file join $dir critclf.tcl]] +package ifneeded wrapfort 0.3 [list source [file join $dir wrapfort.tcl]] diff --git a/src/vfs/critcl.vfs/lib/critclf/pkg_wrap.c b/src/vfs/critcl.vfs/lib/critclf/pkg_wrap.c new file mode 100644 index 00000000..faa24bb0 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/pkg_wrap.c @@ -0,0 +1,122 @@ +/* Simple wrapper +*/ +/* Include files +*/ +#include +#include +#include +#include +#include +#include + +#include "tcl.h" + +#define EXPORT_FUNC __declspec(dllexport) + +EXPORT_FUNC int PKGINIT_Init( Tcl_Interp *interp ) ; + +#include "wrapfort_lib.c" + +static Tcl_Interp *saved_interp; /* TODO: allow several interpreters! */ + +#if defined(__unix) +#define __stdcall +#endif +#include "FILENAME" + + +#ifdef CRITCLF +TclStubs *tclStubsPtr; +TclPlatStubs *tclPlatStubsPtr; +struct TclIntStubs *tclIntStubsPtr; +struct TclIntPlatStubs *tclIntPlatStubsPtr; + +static int +MyInitTclStubs (Tcl_Interp *ip) +{ + typedef struct { + char *result; + Tcl_FreeProc *freeProc; + int errorLine; + TclStubs *stubTable; + } HeadOfInterp; + + HeadOfInterp *hoi = (HeadOfInterp*) ip; + + if (hoi->stubTable == NULL || hoi->stubTable->magic != TCL_STUB_MAGIC) { + ip->result = "This extension requires stubs-support."; + ip->freeProc = TCL_STATIC; + return 0; + } + + tclStubsPtr = hoi->stubTable; + + if (Tcl_PkgRequire(ip, "Tcl", "8.1", 0) == NULL) { + tclStubsPtr = NULL; + return 0; + } + + if (tclStubsPtr->hooks != NULL) { + tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; + tclIntStubsPtr = tclStubsPtr->hooks->tclIntStubs; + tclIntPlatStubsPtr = tclStubsPtr->hooks->tclIntPlatStubs; + } + + return 1; +} +#endif + +int PKGINIT_Init( Tcl_Interp *interp ) +{ + int retcode ; + int error ; + +/* Register the Fortran logical values +*/ +/* TODO + ftcl_init_log( &ftcl_true, &ftcl_false ) ; +*/ + +/* Initialise the stubs +*/ +#ifdef USE_TCL_STUBS +#ifndef CRITCLF + if (Tcl_InitStubs(interp, "8.0", 0) == NULL) { + return TCL_ERROR; + } +#else + if (MyInitTclStubs(interp) == 0) { + return TCL_ERROR; + } +#endif +#endif + + +/* Inquire about the package's version +*/ + if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) + { + if (TCL_VERSION[0] == '7') + { + if (Tcl_PkgRequire(interp, "Tcl", "8.0", 0) == NULL) + { + return TCL_ERROR; + } + } + } + + if (Tcl_PkgProvide(interp, "PKGNAME", "1.0") != TCL_OK) + { + return TCL_ERROR; + } + +/* Register the package's commands +*/ + retcode = TCL_OK ; + +#include "TCLFNAME" + + return retcode ; +} + +/* End of file ftempl.c */ diff --git a/src/vfs/critcl.vfs/lib/critclf/wrapfort.code b/src/vfs/critcl.vfs/lib/critclf/wrapfort.code new file mode 100644 index 00000000..eaf6c6fa --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/wrapfort.code @@ -0,0 +1,325 @@ +# Nog te doen: +# error-handling (onerror) +# meerdere interpreters + + +# wrapfort.code -- +# Code fragments (templates) for generating a wrapper +# +array set ctype {void void real float double double integer long logical long string "char *" + integer-array long real-array float double-array double + integer-vector long real-vector float double-vector double + integer-matrix long real-matrix float double-matrix double} + +set header " +/* Wrapper for ROUTINE - Tcl-command CMDNAME */ +#ifdef FTN_UNDERSCORE +# define ROUTINE ROUTINE_ +#endif +#ifdef FTN_ALL_CAPS +# define ROUTINE ALLCAPS +#endif +void __stdcall ROUTINE(); /* Important! */ +static int c__ROUTINE( ClientData client_data, Tcl_Interp *interp, + Tcl_Size objc, struct Tcl_Obj * CONST objv\[\] ) { + int _rc_ = TCL_OK ;" + +set declaration(integer) { long NAME;} +set declaration(real) { float NAME;} +set declaration(double) { double NAME;} +set declaration(string) { char NAME[80]; int length__NAME;} +set declaration(logical) { long NAME;} +set declaration(integer-vector) { long *NAME; int size__NAME;} +set declaration(integer-array) { long *NAME; int size__NAME;} +set declaration(integer-matrix) { long *NAME; int size_inner__NAME, size_outer__NAME;} +set declaration(real-vector) { float *NAME; int size__NAME;} +set declaration(real-array) { float *NAME; int size__NAME;} +set declaration(real-matrix) { float *NAME; int size_inner__NAME, size_outer__NAME;} +set declaration(double-vector) { double *NAME; int size__NAME;} +set declaration(double-array) { double *NAME; int size__NAME;} +set declaration(double-matrix) { double *NAME; int size_inner__NAME, size_outer__NAME;} + +set initialisation(check) { + if ( objc != COUNT ) { + Tcl_SetResult( interp, "Wrong number of arguments", NULL ); + return TCL_ERROR; + }} + +set initialisation(integer) { + if ( Tcl_GetLongFromObj( interp, objv[COUNT], &NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be integer", NULL ); + return TCL_ERROR; + }} + +set initialisation(integer-array) { + if ( WrapCopyIntListToArray( interp, objv[COUNT], &NAME, &size__NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be a list of integers", NULL ); + return TCL_ERROR; + }} + +set initialisation(real) { + { + double value; + if ( Tcl_GetDoubleFromObj( interp, objv[COUNT], &value ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be a double precision real", NULL ); + return TCL_ERROR; + } else { + NAME = (float) value; + } + }} + +set initialisation(real-array) { + if ( WrapCopyDoubleListToRealArray( interp, objv[COUNT], &NAME, &size__NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be a list of double precision reals", NULL ); + return TCL_ERROR; + }} + +set initialisation(double) { + if ( Tcl_GetDoubleFromObj( interp, objv[COUNT], &NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be a double precision real", NULL ); + return TCL_ERROR; + }} + +set initialisation(double-array) { + if ( WrapCopyDoubleListToArray( interp, objv[COUNT], &NAME, &size__NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be a list of double precision reals", NULL ); + return TCL_ERROR; + }} + +set initialisation(external) { + saved_interp = interp ; + if ( NAME_tclprocs == NULL ) { + NAME_tclprocs = Tcl_NewListObj( 0, NULL ); + Tcl_IncrRefCount(NAME_tclprocs); + } + if ( Tcl_ListObjAppendElement( interp, NAME_tclprocs, objv[COUNT]) != TCL_OK ) { + Tcl_SetResult( interp, "Name of Tcl command could not be stored for later use", NULL ); + return TCL_ERROR; + }} + +# +# TODO! +# +set initialisation(string) { + if ( Tcl_GetDoubleFromObj( interp, objv[COUNT], &NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT must be a double precision real", NULL ); + return TCL_ERROR; + }} + +set cleanup(close) " return _rc_; +}" + +set cleanup(integer) "/* Nothing to be done for: NAME */" +set cleanup(integer-array) " free(NAME);" +set cleanup(integer-vector) " free(NAME);" +set cleanup(integer-matrix) " free(NAME);" +set cleanup(real) "/* Nothing to be done for: NAME */" +set cleanup(real-array) " free(NAME);" +set cleanup(real-vector) " free(NAME);" +set cleanup(real-matrix) " free(NAME);" +set cleanup(double) "/* Nothing to be done for: NAME */" +set cleanup(double-array) " free(NAME);" +set cleanup(double-vector) " free(NAME);" +set cleanup(double-matrix) " free(NAME);" + +set cleanup(external) { + {int length ; + if ( Tcl_ListObjLength( interp, NAME_tclprocs, &length ) != TCL_OK || + Tcl_ListObjReplace( interp, NAME_tclprocs, length-1, length-1, 0, NULL ) != TCL_OK ) { + Tcl_SetResult( interp, "Argument COUNT could not be cleaned up", NULL ); + return TCL_ERROR; + } + } +} + +set result(integer) { + Tcl_SetObjResult( interp, Tcl_NewLongObj(NAME) ) ; +} +set result(real) { + Tcl_SetObjResult( interp, Tcl_NewDoubleObj((double)NAME) ) ; +} +set result(double) { + Tcl_SetObjResult( interp, Tcl_NewDoubleObj(NAME) ) ; +} +set result(integer-array) { + { + Tcl_Obj *result; + if ( WrapCopyIntArrayToList( interp, NAME, size__NAME, &result ) != TCL_OK ) { + Tcl_SetResult( interp, "Can not copy array to Tcl result", NULL ); + return TCL_ERROR; + } else { + Tcl_SetObjResult( interp, result ) ; + } + }} +set result(real-array) { + { + Tcl_Obj *result; + if ( WrapCopyRealArrayToDoubleList( interp, NAME, size__NAME, &result ) != TCL_OK ) { + Tcl_SetResult( interp, "Can not copy array to Tcl result", NULL ); + return TCL_ERROR; + } else { + Tcl_SetObjResult( interp, result ) ; + } + }} +set result(double-array) { + { + Tcl_Obj *result; + if ( WrapCopyDoubleArrayToList( interp, NAME, size__NAME, &result ) != TCL_OK ) { + Tcl_SetResult( interp, "Can not copy array to Tcl result", NULL ); + return TCL_ERROR; + } else { + Tcl_SetObjResult( interp, result ) ; + } + }} + +# +# Second part: Fortran calling Tcl +# + +set fheader(start) { +/* Wrapper for the NAME interface */ +#ifdef FTN_UNDERSCORE +# define NAME NAME_ +#endif +#ifdef FTN_ALL_CAPS +# define NAME ALLCAPS +#endif +static Tcl_Obj *NAME_tclprocs ; +TYPE __stdcall NAME (} + +set fheader(end) ") \{" + +set fdeclaration(integer) { long *NAME} +set fdeclaration(real) { float *NAME} +set fdeclaration(double) { double *NAME} +set fdeclaration(integer-array) { long *NAME} +set fdeclaration(real-array) { float *NAME} +set fdeclaration(double-array) { double *NAME} +set fdeclaration(integer-vector) { long *NAME} +set fdeclaration(real-vector) { float *NAME} +set fdeclaration(double-vector) { double *NAME} +set fdeclaration(integer-matrix) { long *NAME} +set fdeclaration(real-matrix) { float *NAME} +set fdeclaration(double-matrix) { double *NAME} + +set fdeclaration(length) { int size__NAME = *SIZE;} + +set fdecl_result(integer) { long NAME;} +set fdecl_result(real) { float NAME;} +set fdecl_result(double) { double NAME;} + +set finitialisation(start) { + Tcl_Obj *objv[NOARGS] ; + Tcl_Size objc = NOARGS ; + int error ; + Tcl_Size length ; + Tcl_Interp *interp = saved_interp ; + + if ( Tcl_ListObjLength( interp, NAME_tclprocs, &length ) != TCL_OK || + Tcl_ListObjIndex( interp, NAME_tclprocs, length-1, &objv[0] ) != TCL_OK ) { + Tcl_SetResult( interp, "Could not retrieve proc name", NULL ); + return DUMMY; + } +} +set finitialisation(integer) { objv[IDX] = Tcl_NewLongObj(*NAME); + Tcl_IncrRefCount(objv[IDX]);} +set finitialisation(real) { objv[IDX] = Tcl_NewDoubleObj((double)*NAME); + Tcl_IncrRefCount(objv[IDX]);} +set finitialisation(double) { objv[IDX] = Tcl_NewDoubleObj(*NAME); + Tcl_IncrRefCount(objv[IDX]);} + +set finitialisation(integer-array) { + if ( WrapCopyIntArrayToList( interp, NAME, size__NAME, &objv[IDX] ) != TCL_OK ) { + Tcl_SetResult( interp, "Can not copy array to argument IDX", NULL ); + /* TODO: clean-up! */ + return TCL_ERROR; + } + Tcl_IncrRefCount(objv[IDX]);} + +set finitialisation(real-array) { + if ( WrapCopyRealArrayToDoubleList( interp, NAME, size__NAME, &objv[IDX] ) != TCL_OK ) { + Tcl_SetResult( interp, "Can not copy array to argument IDX", NULL ); + /* TODO: clean-up! */ + return TCL_ERROR; + } + Tcl_IncrRefCount(objv[IDX]);} + +set finitialisation(double-array) { + if ( WrapCopyDoubleArrayToList( interp, NAME, size__NAME, &objv[IDX] ) != TCL_OK ) { + Tcl_SetResult( interp, "Can not copy array to argument IDX", NULL ); + /* TODO: clean-up! */ + return TCL_ERROR; + } + Tcl_IncrRefCount(objv[IDX]);} + +set finitialisation(integer-vector) $finitialisation(integer-array) +set finitialisation(real-vector) $finitialisation(real-array) +set finitialisation(double-vector) $finitialisation(double-array) + +set frunproc { + {int _i_; + for ( _i_ = 0; _i_ < objc; _i_ ++ ) { + Tcl_IncrRefCount(objv[_i_]); + } + error = 0 ; + if ( Tcl_EvalObjv( interp, objc, objv, 0 ) != TCL_OK ) { + error = 1 ; + } + for ( _i_ = 0; _i_ < objc; _i_ ++ ) { + Tcl_DecrRefCount(objv[_i_]); + }} +} +set fresult(integer) { + if ( Tcl_GetLongFromObj( interp, Tcl_GetObjResult(interp), &NAME ) != TCL_OK ) { + Tcl_AppendResult( interp, "Could not retrieve integer result", NULL ) ; + } +} +set fresult(real) { + {double dbl ; + if ( Tcl_GetDoubleFromObj( interp, Tcl_GetObjResult(interp), &dbl ) != TCL_OK ) { + Tcl_AppendResult( interp, "Could not retrieve real result", NULL ) ; + NAME = 0.0f ; + } else { + NAME = (float) dbl ; + } + } +} +set fresult(double) { + if ( Tcl_GetDoubleFromObj( interp, Tcl_GetObjResult(interp), &NAME ) != TCL_OK ) { + Tcl_AppendResult( interp, "Could not retrieve double result", NULL ) ; + } +} + +set fresult(integer-array) { + if ( WrapCopyIntListIntoExistingArray( interp, Tcl_GetObjResult(interp), NAME, size__NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Result of Tcl proc must be a list of integers", NULL ); + return TCL_ERROR; + }} + +set fresult(real-array) { + if ( WrapCopyDoubleListIntoExistingRealArray( interp, Tcl_GetObjResult(interp), NAME, size__NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Result of Tcl proc must be a list of double precision reals", NULL ); + return TCL_ERROR; + }} + +set fresult(double-array) { + if ( WrapCopyDoubleListIntoExistingArray( interp, Tcl_GetObjResult(interp), NAME, size__NAME ) != TCL_OK ) { + Tcl_SetResult( interp, "Result of Tcl proc must be a list of double precision reals", NULL ); + return TCL_ERROR; + }} + +set ferror { + if ( error != 0 ) { + ERROR + }} + +set fcleanup(integer) { Tcl_DecrRefCount(objv[IDX]);} +set fcleanup(real) { Tcl_DecrRefCount(objv[IDX]);} +set fcleanup(double) { Tcl_DecrRefCount(objv[IDX]);} +set fcleanup(integer-array) { Tcl_DecrRefCount(objv[IDX]);} +set fcleanup(real-array) { Tcl_DecrRefCount(objv[IDX]);} +set fcleanup(double-array) { Tcl_DecrRefCount(objv[IDX]);} + +set freturn(integer) { return NAME;} +set freturn(real) { return NAME;} +set freturn(double) { return NAME;} diff --git a/src/vfs/critcl.vfs/lib/critclf/wrapfort.tcl b/src/vfs/critcl.vfs/lib/critclf/wrapfort.tcl new file mode 100644 index 00000000..d344048e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/wrapfort.tcl @@ -0,0 +1,744 @@ +# wrapfort.tcl -- +# Utility for quickly wrapping Fortran (77) routines +# +# TODO: +# - Fortran functions are not covered yet (void __stdcall ...) +# + +package require Tcl 8.6 9 +package provide wrapfort 0.3 + +# Wrapfort -- +# Namespace which holds all relevant information and procedures +# +namespace eval ::Wrapfort { + variable srcout ;# Handle to the output file + variable incritcl 0 ;# Interaction with Critcl + variable tclfname ;# C file with Tcl_CreateCommand() + variable pkgfname ;# C file to compile + + variable header ;# Template for routine header + variable routines ;# List of routines to be registered + variable declaration ;# Array containing the declaration templates + variable initialisation ;# Array containing the initialisation templates + variable cleanup ;# Array containing the templates for clean up code + variable result ;# Array containing the templates for result code + + variable fheader ;# Template for Tcl proc wrapper, called from Fortran + variable fdeclaration ;# Array containing the declaration templates + variable finitialisation ;# Array containing the initialisation templates + variable fcleanup ;# Array containing the templates for clean up code + variable fresult ;# Array containing the templates for result code + + variable ref_interfaces ;# List of referenced interfaces + variable dfn_interfaces ;# List of defined interfaces + + set ref_interfaces {} + set dfn_interfaces {} + + namespace export fproc fsource fexternal + + variable wrapdir [file dirname [info script]] ;# Directory containing auxiliary files + + source [file join $wrapdir "wrapfort.code"] +} + + +# incritcl -- +# Set the parameter that determines whether used via Critcl +# +# Arguments: +# in If true, called via Critcl, otherwise standalone +# +proc ::Wrapfort::incritcl {in} { + variable incritcl + + set incritcl $in + +} + + +# Output -- +# Write the C code fragments +# +# Arguments: +# code Code to be written to file or stored in a variable +# +proc ::Wrapfort::Output {code} { + variable incritcl + variable srcout + + if { ! $incritcl } { + puts $srcout $code + } else { + ::critcl::Emitln $code + } +} +proc ::Wrapfort::Output2 {code} { + variable incritcl + variable cmdout + + if { ! $incritcl } { + puts $cmdout $code + } else { + return -code error "Cmdemit does not exist!!" + ::critcl::Cmdemit $code + } +} + + +# fsource -- +# Open the source file +# +# Arguments: +# pkgname Name of the package +# filename Name of the file to write +# +proc ::Wrapfort::fsource {pkgname filename} { + variable srcout + variable cmdout + variable wrapdir + variable tclfname + variable pkgfname + variable incritcl + + set srcout [open $filename w] + set cmdout [open [file join [file dirname $filename] "tcl_[file tail $filename]"] w] + + # + # The template files + # + set infile [open [file join $wrapdir "pkg_wrap.c"]] + set pkgfname [file join [file dirname $filename] "pkg_[file tail $filename]"] + set tclfname [file join [file dirname $filename] "tcl_[file tail $filename]"] + + set contents [string map [list PKGNAME $pkgname \ + PKGINIT [string totitle $pkgname] FILENAME $filename TCLFNAME $tclfname] \ + [read $infile]] + + set outfile [open $pkgfname w] + if { $incritcl } { + puts $outfile "#define CRITCLF" + } + puts -nonewline $outfile $contents + close $outfile + close $infile + + set infile [open [file join $wrapdir "idx_wrap.tcl"]] + set outfile [open "pkgIndex.tcl" w] + set contents [string map [list PKGNAME $pkgname] [read $infile]] + puts -nonewline $outfile $contents + close $outfile + close $infile +} + + +# fproc -- +# Procedure to drive the generation of the wrapper code +# +# Arguments: +# cmdname Name of the corresponding Tcl command +# froutine Name of the Fortran routine/function that is to be wrapped +# arglist Description of the argument list and local +# variables, as well as specific code +# +proc ::Wrapfort::fproc {cmdname routine arglist} { + # + # Check any external interfaces + # + ExternalInterfaces $arglist + + # + # The generation occurs in stages + # + WriteTclCreateCommand $cmdname $routine + WriteRoutineHeader $cmdname $routine $arglist + + WriteDeclarations $arglist + WriteInitialisation $arglist + WriteBody $arglist + WriteResultCode $arglist + WriteCleanup $arglist +} + + +# ExternalInterfaces -- +# Check and update the lists of external interfaces +# +# Arguments: +# arglist Argument list for the Fortran routine +# Result: +# None +# +# Side effects: +# Updates the list ref_interfaces. May throw +# an error +# +proc ::Wrapfort::ExternalInterfaces {arglist} { + variable ref_interfaces + variable dfn_interfaces + + foreach {type name specs} $arglist { + if { $type == "external" } { + if { [lsearch $ref_interfaces $name] >= 0 } { + return -code error "Interface $name already referenced!" + } else { + lappend ref_interfaces $name + } + if { [lsearch $dfn_interfaces $name] < 0 } { + return -code error "Interface $name has not been defined yet!" + } + } + } +} + + +# WriteTclCreateCommand -- +# Write the Tcl_CreateObjCommand line to register the command +# +# Arguments: +# cmdname Name of the corresponding Tcl command +# routine Name of the C routine/function that will be created +# Result: +# None +# +# Side effects: +# Writes a piece of the code to the second file +# +proc ::Wrapfort::WriteTclCreateCommand {cmdname routine} { + + Output2 [string map [list CMDNAME $cmdname ROUTINE $routine] \ + " Tcl_CreateObjCommand2( interp, \"CMDNAME\", c__ROUTINE, NULL, NULL );"] +} + + +# WriteRoutineHeader -- +# Write the header for the routine/function +# +# Arguments: +# cmdname Name of the corresponding Tcl command +# routine Name of the C routine/function that will be created +# arglist Description of the argument list and local +# variables, as well as specific code +# Result: +# None +# +# Side effects: +# Writes a piece of the code to file, also stores the command +# and routine names for later use. +# +proc ::Wrapfort::WriteRoutineHeader {cmdname routine arglist} { + variable routines + variable header + variable external_decl + + lappend routines [list $cmdname $routine] + + Output [string map [list ROUTINE $routine ALLCAPS [string toupper $routine] \ + CMDNAME $cmdname] $header] +} + + +# WriteInitialisation -- +# Write the initialisation code for the routine +# +# Arguments: +# arglist Description of the argument list and local +# variables, as well as specific code +# Result: +# None +# +# Side effects: +# Writes a piece of the code to file +# +proc ::Wrapfort::WriteInitialisation {arglist} { + variable initialisation + + # + # First count the arguments + # + set count 1 + foreach {type name specs} $arglist { + switch -- $type { + "integer" - "real" - "double" - "string" - "logical" - + "integer-vector" - "real-vector" - "double-vector" - + "integer-array" - "real-array" - "double-array" - + "integer-matrix" - "real-matrix" - "double-matrix" { + if { [lindex $specs 0] == "input" } { + incr count + } + } + "external" { + incr count + } + } + } + + Output [string map [list COUNT $count] $initialisation(check)] + + # + # Then handle the arguments + # + set count 1 + foreach {type name specs} $arglist { + switch -- $type { + "integer" - "real" - "double" - "string" - "logical" - + "integer-vector" - "real-vector" - "double-vector" - + "integer-array" - "real-array" - "double-array" - + "integer-matrix" - "real-matrix" - "double-matrix" { + if { [lindex $specs 0] == "input"} { + Output [string map [list NAME $name COUNT $count] \ + $initialisation($type)] + } + } + "external" { + Output [string map [list NAME $name COUNT $count] \ + $initialisation($type)] + } + } + if { [lindex $specs 0] != "result" } { + incr count + } + } + + # + # Finally handle the local variables + # + foreach {type name specs} $arglist { + switch -- $type { + "integer" - "double" - "string" - "logical" - + "integer-vector" - "real-vector" - "double-vector" - + "integer-array" - "real-array" - "double-array" - + "integer-matrix" - "real-matrix" - "double-matrix" { + if { [lindex $specs 0] != "input"} { + # + # TODO: Requires more code! + # + Output "[MakeInitCode $type $name $specs]" + } + } + } + } +} + + +# MakeInitCode -- +# Make the code to initialise the given variable +# +# Arguments: +# type Type of the variable +# name Name of the variable +# specs Specification of how to initialise the variable +# Result: +# Fragment of C code to initialise the variable +# +proc ::Wrapfort::MakeInitCode {type name specs} { + + # For the moment: just replace size() by the hidden C variable + + if { [lindex $specs 0] == "assign" } { + regsub -all {size\((.+)\)} [lrange $specs 1 end] {size__\1} ccode + return " $name = $ccode ;" + } elseif { [lindex $specs 0] == "allocate" } { + set ctype [DetermineCType $type] + + regsub -all {size\((.+)\)} [lrange $specs 1 end] {size__\1} ccode + return " $name = ($ctype *) ckalloc(sizeof($ctype)*($ccode)) ; + size__$name = $ccode;" + } elseif { [lindex $specs 0] == "result" && [string match "*-array" $type] } { + set ctype [DetermineCType $type] + + regsub -all {size\((.+)\)} [lrange $specs 1 end] {size__\1} ccode + return " $name = ($ctype *) ckalloc(sizeof($ctype)*($ccode)) ; + size__$name = $ccode;" + } else { + return " /* No initialisation for $name ($specs) */" + } +} + + +# WriteDeclarations -- +# Extract the definitions and declarations from the list and +# write to the source file +# +# Arguments: +# arglist Description of the argument list and local +# variables, as well as specific code +# Result: +# None +# +# Side effects: +# Writes a piece of the code to file +# +proc ::Wrapfort::WriteDeclarations {arglist} { + variable srcout + variable declaration + + foreach {type name specs} $arglist { + switch -- $type { + "integer" - "double" - "real" - "string" - "logical" - + "integer-vector" - "real-vector" - "double-vector" - + "integer-array" - "real-array" - "double-array" - + "integer-matrix" - "real-matrix" - "double-matrix" { + Output [string map [list NAME $name] $declaration($type)] + } + "code" - "external" { + continue ;# Just skip those at this stage + } + default { + return -code error "Unknown keyword/type: $type" + } + } + } +} + + +# WriteBody -- +# Write the literal code that may appear as type "code" +# +# Arguments: +# arglist Description of the argument list and local +# variables, as well as specific code +# Result: +# None +# +# Side effects: +# Writes a piece of the code to file +# +proc ::Wrapfort::WriteBody {arglist} { + variable srcout + + foreach {type name specs} $arglist { + switch -- $type { + "code" { + Output $specs + } + } + } +} + + +# WriteResultCode -- +# Write the code to pass on the results +# +# Arguments: +# arglist Description of the argument list and local +# variables, as well as specific code +# Result: +# None +# +# Side effects: +# Writes a piece of the code to file +# +proc ::Wrapfort::WriteResultCode {arglist} { + variable result + variable srcout + + set count 0 + foreach {type name specs} $arglist { + switch -- [lindex $specs 0] { + "result" { + Output [string map [list NAME $name] $result($type)] + } + } + } +} + + +# WriteCleanup -- +# Write the code to clean up before returning +# +# Arguments: +# arglist Description of the argument list and local +# variables, as well as specific code +# Result: +# None +# +# Side effects: +# Writes a piece of the code to file +# +proc ::Wrapfort::WriteCleanup {arglist} { + variable cleanup + variable srcout + + set count 0 + foreach {type name specs} $arglist { + switch -- $type { + "integer" - "real" - "double" - "string" - "logical" - + "integer-vector" - "real-vector" - "double-vector" - + "integer-array" - "real-array" - "double-array" - + "integer-matrix" - "real-matrix" - "double-matrix" - "external" { + Output [string map [list NAME $name] $cleanup($type)] + } + } + } + + Output $cleanup(close) +} + + +# fexternal -- +# Procedure to generate a wrapper for a Tcl procedure +# +# Arguments: +# interface Name of the Fortran interface +# arglist Description of the arguments on the Fortran and Tcl side +# +proc ::Wrapfort::fexternal {interface arglist} { + + set data(onerror) {} + array set data $arglist + + # + # Check that the calling Fortran routine has already been defined! + # + CheckCallingRoutine $interface + + # + # The generation occurs in stages + # + FortranWriteRoutineHeader $interface $data(fortran) + + FortranWriteInitialisation $interface $data(fortran) $data(toproc) + FortranWriteResultCode $interface $data(fortran) $data(toproc) $data(onerror) + FortranWriteCleanup $interface $data(fortran) $data(toproc) +} + + +# CheckCallingRoutine -- +# Check if the calling Fortran routine has already been defined +# +# Arguments: +# name Name of the interface +# Result: +# None +# +# Side effects: +# Updates the list dfn_interfaces. May throw an error +# +proc ::Wrapfort::CheckCallingRoutine {name} { + variable ref_interfaces + variable dfn_interfaces + + if { [lsearch $dfn_interfaces $name] >= 0 } { + return -code error "Interface $name has already been defined!" + } + + lappend dfn_interfaces $name +} + + +# FortranWriteRoutineHeader -- +# Write the header for the wrapper routine +# +# Arguments: +# interface Name of the Fortran interface +# arglist Description of the arguments on the Fortran side +# +proc ::Wrapfort::FortranWriteRoutineHeader {interface arglist} { + variable srcout + variable fheader + variable fdeclaration + + set ftype [DetermineFunctionType $arglist] + + Output "[string map [list TYPE $ftype NAME $interface \ + ALLCAPS [string toupper $interface]] $fheader(start)]" + + set arguments {} + foreach {type var specs} $arglist { + if { [lindex $specs 0] != "result" } { + lappend arguments "[string map [list NAME $var] $fdeclaration($type)]" + } + } + Output [join $arguments ",\n"] + Output $fheader(end) + + # + # Local declarations we need + # + foreach {type var specs} $arglist { + if { [string match "*-array" $type] } { + set size [lindex $specs 1] + Output "[string map [list SIZE $size NAME $var] $fdeclaration(length)]" + } + } +} + + +# DetermineFunctionType -- +# Determine the type of the C wrapper +# +# Arguments: +# arglist Description of the arguments on the Fortran side +# +proc ::Wrapfort::DetermineFunctionType {arglist} { + variable ctype + + set functiontype "void" + + foreach {type name specs} $arglist { + if { [lindex $specs 0] == "result" } { + set functiontype $type + break + } + } + return $ctype($functiontype) +} + + +# DetermineCType -- +# Determine the C type that corresponds to the given type +# +# Arguments: +# type Type of the variable in the interface definition +# +proc ::Wrapfort::DetermineCType {type} { + variable ctype + + return $ctype($type) +} + + +# ReturnDummyValue -- +# Determine the correct dummy return value (if any) +# +# Arguments: +# arglist Description of the arguments on the Fortran side +# +proc ::Wrapfort::ReturnDummyValue {arglist} { + + set dummy [DetermineFunctionType $arglist] + + if { $dummy == "void" } { + set dummy "" + } else { + set dummy "($dummy) 0" + } + return $dummy +} + + +# FortranWriteInitialisation -- +# Write the initialisation part of the wrapper routine +# +# Arguments: +# interface Name of the Fortran interface +# fortargs Description of the arguments on the Fortran side +# tclargs Description of the arguments on the Tcl side +# +proc ::Wrapfort::FortranWriteInitialisation {interface fortargs tclargs} { + variable srcout + variable finitialisation + variable fdecl_result + + foreach {type name specs} $fortargs { + if { [lindex $specs 0] == "result" } { + Output "[string map [list NAME $name] \ + $fdecl_result($type)]" + } + } + + set noargs [NumberArguments $tclargs] + Output "[string map [list NOARGS $noargs NAME $interface \ + DUMMY [ReturnDummyValue $fortargs]] $finitialisation(start)]" + + set idx 1 + foreach {var role} $tclargs { + if { $role != "result" } { + set pos [lsearch $fortargs $var] + set type [lindex $fortargs [expr {$pos-1}]] + Output "[string map [list NAME $var IDX $idx] $finitialisation($type)]" + incr idx + } + } +} + + +# NumberArguments -- +# Determine the number of arguments to be passed to the Tcl proc +# +# Arguments: +# arglist Description of the arguments on the Tcl side +# +proc ::Wrapfort::NumberArguments {arglist} { + + set number 1 + foreach {name role} $arglist { + if { $role != "result" } { + incr number + } + } + return $number +} + + +# FortranWriteResultCode -- +# Write the part for calling the Tcl proc and handling the result +# +# Arguments: +# interface Name of the Fortran interface +# fortargs Description of the arguments on the Fortran side +# tclargs Description of the arguments on the Tcl side +# errorhandling Error handling code +# +proc ::Wrapfort::FortranWriteResultCode {interface fortargs tclargs errorhandling} { + variable srcout + variable frunproc + variable fresult + variable ferror + + Output $frunproc + + foreach {var role} $tclargs { + if { $role == "result" } { + set pos [lsearch $fortargs $var] + set type [lindex $fortargs [expr {$pos-1}]] + Output "[string map [list NAME $var] $fresult($type)]" + } + } + #foreach {type var specs} $fortargs { + # if { [lindex $specs 0] == "result" } { + # Output "[string map [list NAME $var] $fresult($type)]" + # } + #} + + Output [string map [list ERROR $errorhandling] $ferror] +} + + +# FortranWriteCleanup -- +# Write the cleanup code +# +# Arguments: +# interface Name of the Fortran interface +# fortargs Description of the arguments on the Fortran side +# tclargs Description of the arguments on the Tcl side +# +proc ::Wrapfort::FortranWriteCleanup {interface fortargs tclargs} { + variable srcout + variable fcleanup + variable freturn + + set idx 1 + foreach {var role} $tclargs { + if { $role != "result" } { + set pos [lsearch $fortargs $var] + set type [lindex $fortargs [expr {$pos-1}]] + Output "[string map [list NAME $var IDX $idx] $fcleanup($type)]" + incr idx + } + } + + set ftype [DetermineFunctionType $fortargs] + + if { $ftype != "void" } { + foreach {type var specs} $fortargs { + if { [lindex $specs 0] == "result" } { + Output "[string map [list NAME $var] $freturn($type)]" + } + } + } + + Output "\}" +} diff --git a/src/vfs/critcl.vfs/lib/critclf/wrapfort_libf.f90 b/src/vfs/critcl.vfs/lib/critclf/wrapfort_libf.f90 new file mode 100644 index 00000000..70952683 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/critclf/wrapfort_libf.f90 @@ -0,0 +1,31 @@ +! wrapfort_libf.f90 +! Auxiliary Fortran routines for Wrapfort +! + +! fort_set_logical -- +! Set a logical value (from C to Fortran) +! +! Arguments: +! var Variable to be set +! clog Set to true (if /= 0), to false (if 0) +! +subroutine fort_set_logical( var, clog ) + logical :: var + integer :: clog + + var = clog .ne. 0 +end subroutine fort_set_logical + +! fort_get_logical -- +! Get a logical value (from Fortran to C) +! +! Arguments: +! var Variable to be set +! log Set to 1 (if true), to 0 (if false) +! +subroutine fort_get_logical( var, flog ) + integer :: var + logical :: flog + + var = merge(1,0,flog) +end subroutine fort_get_logical diff --git a/src/vfs/critcl.vfs/lib/md5/md5.tcl b/src/vfs/critcl.vfs/lib/md5/md5.tcl new file mode 100644 index 00000000..9825263d --- /dev/null +++ b/src/vfs/critcl.vfs/lib/md5/md5.tcl @@ -0,0 +1,451 @@ +################################################## +# +# md5.tcl - MD5 in Tcl +# Author: Don Libes , July 1999 +# Version 1.2.0 +# +# MD5 defined by RFC 1321, "The MD5 Message-Digest Algorithm" +# HMAC defined by RFC 2104, "Keyed-Hashing for Message Authentication" +# +# Most of the comments below come right out of RFC 1321; That's why +# they have such peculiar numbers. In addition, I have retained +# original syntax, bugs in documentation (yes, really), etc. from the +# RFC. All remaining bugs are mine. +# +# HMAC implementation by D. J. Hagberg and +# is based on C code in RFC 2104. +# +# For more info, see: http://expect.nist.gov/md5pure +# +# - Don +# +# Modified by Miguel Sofer to use inlines and simple variables +################################################## + +package require Tcl 8.6 9 +namespace eval ::md5 {} + +if {![catch {package require Trf 2.0}]} { + # Trf is available, so implement the functionality provided here + # in terms of calls to Trf for speed. + + proc ::md5::md5 {msg} { + string tolower [::hex -mode encode [::md5 $msg]] + } + + # hmac: hash for message authentication + + # MD5 of Trf and MD5 as defined by this package have slightly + # different results. Trf returns the digest in binary, here we get + # it as hex-string. In the computation of the HMAC the latter + # requires back conversion into binary in some places. With Trf we + # can use omit these. + + proc ::md5::hmac {key text} { + # if key is longer than 64 bytes, reset it to MD5(key). If shorter, + # pad it out with null (\x00) chars. + set keyLen [string length $key] + if {$keyLen > 64} { + #old: set key [binary format H32 [md5 $key]] + set key [::md5 $key] + set keyLen [string length $key] + } + + # ensure the key is padded out to 64 chars with nulls. + set padLen [expr {64 - $keyLen}] + append key [binary format "a$padLen" {}] + + # Split apart the key into a list of 16 little-endian words + binary scan $key i16 blocks + + # XOR key with ipad and opad values + set k_ipad {} + set k_opad {} + foreach i $blocks { + append k_ipad [binary format i [expr {$i ^ 0x36363636}]] + append k_opad [binary format i [expr {$i ^ 0x5c5c5c5c}]] + } + + # Perform inner md5, appending its results to the outer key + append k_ipad $text + #old: append k_opad [binary format H* [md5 $k_ipad]] + append k_opad [::md5 $k_ipad] + + # Perform outer md5 + #old: md5 $k_opad + string tolower [::hex -mode encode [::md5 $k_opad]] + } + +} else { + # Without Trf use the all-tcl implementation by Don Libes. + + # T will be inlined after the definition of md5body + + # test md5 + # + # This proc is not necessary during runtime and may be omitted if you + # are simply inserting this file into a production program. + # + proc ::md5::test {} { + foreach {msg expected} { + "" + "d41d8cd98f00b204e9800998ecf8427e" + "a" + "0cc175b9c0f1b6a831c399e269772661" + "abc" + "900150983cd24fb0d6963f7d28e17f72" + "message digest" + "f96b697d7cb7938d525a2f31aaf161d0" + "abcdefghijklmnopqrstuvwxyz" + "c3fcd3d76192e4007dfb496cca67e13b" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "d174ab98d277d9f5a5611c2c9f419d9f" + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + "57edf4a22be3c955ac49da2e2107b67a" + } { + puts "testing: md5 \"$msg\"" + set computed [md5 $msg] + puts "expected: $expected" + puts "computed: $computed" + if {0 != [string compare $computed $expected]} { + puts "FAILED" + } else { + puts "SUCCEEDED" + } + } + } + + # time md5 + # + # This proc is not necessary during runtime and may be omitted if you + # are simply inserting this file into a production program. + # + proc ::md5::time {} { + foreach len {10 50 100 500 1000 5000 10000} { + set time [::time {md5 [format %$len.0s ""]} 100] + regexp -- "\[0-9]*" $time msec + puts "input length $len: [expr {$msec/1000}] milliseconds per interation" + } + } + + # + # We just define the body of md5pure::md5 here; later we + # regsub to inline a few function calls for speed + # + + set ::md5::md5body { + + # + # 3.1 Step 1. Append Padding Bits + # + + set msgLen [string length $msg] + + set padLen [expr {56 - $msgLen%64}] + if {$msgLen % 64 > 56} { + incr padLen 64 + } + + # pad even if no padding required + if {$padLen == 0} { + incr padLen 64 + } + + # append single 1b followed by 0b's + append msg [binary format "a$padLen" \200] + + # + # 3.2 Step 2. Append Length + # + + # RFC doesn't say whether to use little- or big-endian + # code demonstrates little-endian + # This step limits our input to size 2^32b or 2^24B + append msg [binary format "i1i1" [expr {8*$msgLen}] 0] + + # + # 3.3 Step 3. Initialize MD Buffer + # + + set A [expr 0x67452301] + set B [expr 0xefcdab89] + set C [expr 0x98badcfe] + set D [expr 0x10325476] + + # + # 3.4 Step 4. Process Message in 16-Word Blocks + # + + # process each 16-word block + # RFC doesn't say whether to use little- or big-endian + # code says little-endian + binary scan $msg i* blocks + + # loop over the message taking 16 blocks at a time + + foreach {X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15} $blocks { + + # Save A as AA, B as BB, C as CC, and D as DD. + set AA $A + set BB $B + set CC $C + set DD $D + + # Round 1. + # Let [abcd k s i] denote the operation + # a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). + # [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] + set A [expr {$B + [<<< [expr {$A + [F $B $C $D] + $X0 + $T01}] 7]}] + set D [expr {$A + [<<< [expr {$D + [F $A $B $C] + $X1 + $T02}] 12]}] + set C [expr {$D + [<<< [expr {$C + [F $D $A $B] + $X2 + $T03}] 17]}] + set B [expr {$C + [<<< [expr {$B + [F $C $D $A] + $X3 + $T04}] 22]}] + # [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] + set A [expr {$B + [<<< [expr {$A + [F $B $C $D] + $X4 + $T05}] 7]}] + set D [expr {$A + [<<< [expr {$D + [F $A $B $C] + $X5 + $T06}] 12]}] + set C [expr {$D + [<<< [expr {$C + [F $D $A $B] + $X6 + $T07}] 17]}] + set B [expr {$C + [<<< [expr {$B + [F $C $D $A] + $X7 + $T08}] 22]}] + # [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] + set A [expr {$B + [<<< [expr {$A + [F $B $C $D] + $X8 + $T09}] 7]}] + set D [expr {$A + [<<< [expr {$D + [F $A $B $C] + $X9 + $T10}] 12]}] + set C [expr {$D + [<<< [expr {$C + [F $D $A $B] + $X10 + $T11}] 17]}] + set B [expr {$C + [<<< [expr {$B + [F $C $D $A] + $X11 + $T12}] 22]}] + # [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16] + set A [expr {$B + [<<< [expr {$A + [F $B $C $D] + $X12 + $T13}] 7]}] + set D [expr {$A + [<<< [expr {$D + [F $A $B $C] + $X13 + $T14}] 12]}] + set C [expr {$D + [<<< [expr {$C + [F $D $A $B] + $X14 + $T15}] 17]}] + set B [expr {$C + [<<< [expr {$B + [F $C $D $A] + $X15 + $T16}] 22]}] + + # Round 2. + # Let [abcd k s i] denote the operation + # a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). + # Do the following 16 operations. + # [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] + set A [expr {$B + [<<< [expr {$A + [G $B $C $D] + $X1 + $T17}] 5]}] + set D [expr {$A + [<<< [expr {$D + [G $A $B $C] + $X6 + $T18}] 9]}] + set C [expr {$D + [<<< [expr {$C + [G $D $A $B] + $X11 + $T19}] 14]}] + set B [expr {$C + [<<< [expr {$B + [G $C $D $A] + $X0 + $T20}] 20]}] + # [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] + set A [expr {$B + [<<< [expr {$A + [G $B $C $D] + $X5 + $T21}] 5]}] + set D [expr {$A + [<<< [expr {$D + [G $A $B $C] + $X10 + $T22}] 9]}] + set C [expr {$D + [<<< [expr {$C + [G $D $A $B] + $X15 + $T23}] 14]}] + set B [expr {$C + [<<< [expr {$B + [G $C $D $A] + $X4 + $T24}] 20]}] + # [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] + set A [expr {$B + [<<< [expr {$A + [G $B $C $D] + $X9 + $T25}] 5]}] + set D [expr {$A + [<<< [expr {$D + [G $A $B $C] + $X14 + $T26}] 9]}] + set C [expr {$D + [<<< [expr {$C + [G $D $A $B] + $X3 + $T27}] 14]}] + set B [expr {$C + [<<< [expr {$B + [G $C $D $A] + $X8 + $T28}] 20]}] + # [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32] + set A [expr {$B + [<<< [expr {$A + [G $B $C $D] + $X13 + $T29}] 5]}] + set D [expr {$A + [<<< [expr {$D + [G $A $B $C] + $X2 + $T30}] 9]}] + set C [expr {$D + [<<< [expr {$C + [G $D $A $B] + $X7 + $T31}] 14]}] + set B [expr {$C + [<<< [expr {$B + [G $C $D $A] + $X12 + $T32}] 20]}] + + # Round 3. + # Let [abcd k s t] [sic] denote the operation + # a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). + # Do the following 16 operations. + # [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] + set A [expr {$B + [<<< [expr {$A + [H $B $C $D] + $X5 + $T33}] 4]}] + set D [expr {$A + [<<< [expr {$D + [H $A $B $C] + $X8 + $T34}] 11]}] + set C [expr {$D + [<<< [expr {$C + [H $D $A $B] + $X11 + $T35}] 16]}] + set B [expr {$C + [<<< [expr {$B + [H $C $D $A] + $X14 + $T36}] 23]}] + # [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] + set A [expr {$B + [<<< [expr {$A + [H $B $C $D] + $X1 + $T37}] 4]}] + set D [expr {$A + [<<< [expr {$D + [H $A $B $C] + $X4 + $T38}] 11]}] + set C [expr {$D + [<<< [expr {$C + [H $D $A $B] + $X7 + $T39}] 16]}] + set B [expr {$C + [<<< [expr {$B + [H $C $D $A] + $X10 + $T40}] 23]}] + # [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] + set A [expr {$B + [<<< [expr {$A + [H $B $C $D] + $X13 + $T41}] 4]}] + set D [expr {$A + [<<< [expr {$D + [H $A $B $C] + $X0 + $T42}] 11]}] + set C [expr {$D + [<<< [expr {$C + [H $D $A $B] + $X3 + $T43}] 16]}] + set B [expr {$C + [<<< [expr {$B + [H $C $D $A] + $X6 + $T44}] 23]}] + # [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48] + set A [expr {$B + [<<< [expr {$A + [H $B $C $D] + $X9 + $T45}] 4]}] + set D [expr {$A + [<<< [expr {$D + [H $A $B $C] + $X12 + $T46}] 11]}] + set C [expr {$D + [<<< [expr {$C + [H $D $A $B] + $X15 + $T47}] 16]}] + set B [expr {$C + [<<< [expr {$B + [H $C $D $A] + $X2 + $T48}] 23]}] + + # Round 4. + # Let [abcd k s t] [sic] denote the operation + # a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). + # Do the following 16 operations. + # [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] + set A [expr {$B + [<<< [expr {$A + [I $B $C $D] + $X0 + $T49}] 6]}] + set D [expr {$A + [<<< [expr {$D + [I $A $B $C] + $X7 + $T50}] 10]}] + set C [expr {$D + [<<< [expr {$C + [I $D $A $B] + $X14 + $T51}] 15]}] + set B [expr {$C + [<<< [expr {$B + [I $C $D $A] + $X5 + $T52}] 21]}] + # [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] + set A [expr {$B + [<<< [expr {$A + [I $B $C $D] + $X12 + $T53}] 6]}] + set D [expr {$A + [<<< [expr {$D + [I $A $B $C] + $X3 + $T54}] 10]}] + set C [expr {$D + [<<< [expr {$C + [I $D $A $B] + $X10 + $T55}] 15]}] + set B [expr {$C + [<<< [expr {$B + [I $C $D $A] + $X1 + $T56}] 21]}] + # [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] + set A [expr {$B + [<<< [expr {$A + [I $B $C $D] + $X8 + $T57}] 6]}] + set D [expr {$A + [<<< [expr {$D + [I $A $B $C] + $X15 + $T58}] 10]}] + set C [expr {$D + [<<< [expr {$C + [I $D $A $B] + $X6 + $T59}] 15]}] + set B [expr {$C + [<<< [expr {$B + [I $C $D $A] + $X13 + $T60}] 21]}] + # [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64] + set A [expr {$B + [<<< [expr {$A + [I $B $C $D] + $X4 + $T61}] 6]}] + set D [expr {$A + [<<< [expr {$D + [I $A $B $C] + $X11 + $T62}] 10]}] + set C [expr {$D + [<<< [expr {$C + [I $D $A $B] + $X2 + $T63}] 15]}] + set B [expr {$C + [<<< [expr {$B + [I $C $D $A] + $X9 + $T64}] 21]}] + + # Then perform the following additions. (That is increment each + # of the four registers by the value it had before this block + # was started.) + incr A $AA + incr B $BB + incr C $CC + incr D $DD + } + # 3.5 Step 5. Output + + # ... begin with the low-order byte of A, and end with the high-order byte + # of D. + + return [bytes $A][bytes $B][bytes $C][bytes $D] + } + + # + # Here we inline/regsub the functions F, G, H, I and <<< + # + + namespace eval ::md5 { + #proc md5pure::F {x y z} {expr {(($x & $y) | ((~$x) & $z))}} + regsub -all -- {\[ *F +(\$.) +(\$.) +(\$.) *\]} $md5body {((\1 \& \2) | ((~\1) \& \3))} md5body + + #proc md5pure::G {x y z} {expr {(($x & $z) | ($y & (~$z)))}} + regsub -all -- {\[ *G +(\$.) +(\$.) +(\$.) *\]} $md5body {((\1 \& \3) | (\2 \& (~\3)))} md5body + + #proc md5pure::H {x y z} {expr {$x ^ $y ^ $z}} + regsub -all -- {\[ *H +(\$.) +(\$.) +(\$.) *\]} $md5body {(\1 ^ \2 ^ \3)} md5body + + #proc md5pure::I {x y z} {expr {$y ^ ($x | (~$z))}} + regsub -all -- {\[ *I +(\$.) +(\$.) +(\$.) *\]} $md5body {(\2 ^ (\1 | (~\3)))} md5body + + # bitwise left-rotate + if {0} { + proc md5pure::<<< {x i} { + # This works by bitwise-ORing together right piece and left + # piece so that the (original) right piece becomes the left + # piece and vice versa. + # + # The (original) right piece is a simple left shift. + # The (original) left piece should be a simple right shift + # but Tcl does sign extension on right shifts so we + # shift it 1 bit, mask off the sign, and finally shift + # it the rest of the way. + + # expr {($x << $i) | ((($x >> 1) & 0x7fffffff) >> (31-$i))} + + # + # New version, faster when inlining + # We replace inline (computing at compile time): + # R$i -> (32 - $i) + # S$i -> (0x7fffffff >> (31-$i)) + # + + expr { ($x << $i) | (($x >> R$i) & S$i)} + } + } + # inline <<< + regsub -all -- {\[ *<<< +\[ *expr +({[^\}]*})\] +([0-9]+) *\]} $md5body {(([set x [expr \1]] << \2) | (($x >> R\2) \& S\2))} md5body + + # now replace the R and S + set map {} + foreach i { + 7 12 17 22 + 5 9 14 20 + 4 11 16 23 + 6 10 15 21 + } { + lappend map R$i [expr {32 - $i}] S$i [expr {0x7fffffff >> (31-$i)}] + } + + # inline the values of T + foreach \ + tName { + T01 T02 T03 T04 T05 T06 T07 T08 T09 T10 + T11 T12 T13 T14 T15 T16 T17 T18 T19 T20 + T21 T22 T23 T24 T25 T26 T27 T28 T29 T30 + T31 T32 T33 T34 T35 T36 T37 T38 T39 T40 + T41 T42 T43 T44 T45 T46 T47 T48 T49 T50 + T51 T52 T53 T54 T55 T56 T57 T58 T59 T60 + T61 T62 T63 T64 } \ + tVal { + 0xd76aa478 0xe8c7b756 0x242070db 0xc1bdceee + 0xf57c0faf 0x4787c62a 0xa8304613 0xfd469501 + 0x698098d8 0x8b44f7af 0xffff5bb1 0x895cd7be + 0x6b901122 0xfd987193 0xa679438e 0x49b40821 + + 0xf61e2562 0xc040b340 0x265e5a51 0xe9b6c7aa + 0xd62f105d 0x2441453 0xd8a1e681 0xe7d3fbc8 + 0x21e1cde6 0xc33707d6 0xf4d50d87 0x455a14ed + 0xa9e3e905 0xfcefa3f8 0x676f02d9 0x8d2a4c8a + + 0xfffa3942 0x8771f681 0x6d9d6122 0xfde5380c + 0xa4beea44 0x4bdecfa9 0xf6bb4b60 0xbebfbc70 + 0x289b7ec6 0xeaa127fa 0xd4ef3085 0x4881d05 + 0xd9d4d039 0xe6db99e5 0x1fa27cf8 0xc4ac5665 + + 0xf4292244 0x432aff97 0xab9423a7 0xfc93a039 + 0x655b59c3 0x8f0ccc92 0xffeff47d 0x85845dd1 + 0x6fa87e4f 0xfe2ce6e0 0xa3014314 0x4e0811a1 + 0xf7537e82 0xbd3af235 0x2ad7d2bb 0xeb86d391 + } { + lappend map \$$tName $tVal + } + set md5body [string map $map $md5body] + + + # Finally, define the proc + proc md5 {msg} $md5body + + # unset auxiliary variables + unset md5body tName tVal map + } + + proc ::md5::byte0 {i} {expr {0xff & $i}} + proc ::md5::byte1 {i} {expr {(0xff00 & $i) >> 8}} + proc ::md5::byte2 {i} {expr {(0xff0000 & $i) >> 16}} + proc ::md5::byte3 {i} {expr {((0xff000000 & $i) >> 24) & 0xff}} + + proc ::md5::bytes {i} { + format %0.2x%0.2x%0.2x%0.2x [byte0 $i] [byte1 $i] [byte2 $i] [byte3 $i] + } + + # hmac: hash for message authentication + proc ::md5::hmac {key text} { + # if key is longer than 64 bytes, reset it to MD5(key). If shorter, + # pad it out with null (\x00) chars. + set keyLen [string length $key] + if {$keyLen > 64} { + set key [binary format H32 [md5 $key]] + set keyLen [string length $key] + } + + # ensure the key is padded out to 64 chars with nulls. + set padLen [expr {64 - $keyLen}] + append key [binary format "a$padLen" {}] + + # Split apart the key into a list of 16 little-endian words + binary scan $key i16 blocks + + # XOR key with ipad and opad values + set k_ipad {} + set k_opad {} + foreach i $blocks { + append k_ipad [binary format i [expr {$i ^ 0x36363636}]] + append k_opad [binary format i [expr {$i ^ 0x5c5c5c5c}]] + } + + # Perform inner md5, appending its results to the outer key + append k_ipad $text + append k_opad [binary format H* [md5 $k_ipad]] + + # Perform outer md5 + md5 $k_opad + } +} + +package provide md5 1.5 diff --git a/src/vfs/critcl.vfs/lib/md5/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/md5/pkgIndex.tcl new file mode 100644 index 00000000..cad668fa --- /dev/null +++ b/src/vfs/critcl.vfs/lib/md5/pkgIndex.tcl @@ -0,0 +1,2 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +package ifneeded md5 1.5 [list source [file join $dir md5.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_container/container.tcl b/src/vfs/critcl.vfs/lib/stubs_container/container.tcl new file mode 100644 index 00000000..89293e1e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_container/container.tcl @@ -0,0 +1,385 @@ +# -*- tcl -*- +# STUBS handling -- Container. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A container is a variable holding a stubs table value. + +# stubs table dictionary keys +# +# library -- +# +# The name of the entire library. This value is used to compute +# the USE_*_STUB_PROCS macro and the name of the init file. +# +# interfaces -- +# +# A dictionary indexed by interface name that is used to maintain +# the set of valid interfaces. The value is empty. +# +# scspec -- +# +# Storage class specifier for external function declarations. +# Normally "EXTERN", may be set to something like XYZAPI +# +# epoch, revision -- +# +# The epoch and revision numbers of the interface currently being defined. +# (@@@TODO: should be an array mapping interface names -> numbers) +# +# hooks -- +# +# A dictionary indexed by interface name that contains the set of +# subinterfaces that should be defined for a given interface. +# +# stubs -- +# +# This three dimensional dictionary is indexed first by interface +# name, second by platform name, and third by a numeric +# offset. Each numeric offset contains the C function +# specification that should be used for the given entry in the +# table. The specification consists of a list in the form returned +# by ParseDecl in the stubs reader package, i.e. +# +# decl = list (return-type fun-name arguments) +# arguments = void | list (arg-info ...) +# arg-info = list (type name ?array?) +# array = '[]' +# +# last -- +# +# This two dimensional dictionary is indexed first by interface name, +# and second by platform name. The associated entry contains the +# largest numeric offset used for a given interface/platform +# combo. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 + +namespace eval ::stubs::container {} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::container::new {} { + return { + library "UNKNOWN" + interfaces {} + hooks {} + stubs {} + last {} + scspec "EXTERN" + epoch {} + revision 0 + } +} + +# Methods to incrementally fill the container with data. Strongly +# related to the API commands of the stubs reader package. + +proc ::stubs::container::library {tablevar name} { + upvar 1 $tablevar t + dict set t library $name + return +} + +proc ::stubs::container::interface {tablevar name} { + upvar 1 $tablevar t + if {[dict exists $t interfaces $name]} { + return -code error "Duplicate declaration of interface \"$name\"" + } + dict set t interfaces $name {} + return +} + +proc ::stubs::container::scspec {tablevar value} { + upvar 1 $tablevar t + dict set t scspec $value + return +} + +proc ::stubs::container::epoch {tablevar value} { + upvar 1 $tablevar t + + if {![string is integer -strict $value]} { + return -code error "Expected integer for epoch, but got \"$value\"" + } + + dict set t epoch $value + return +} + +proc ::stubs::container::hooks {tablevar interface names} { + upvar 1 $tablevar t + dict set t hooks $interface $names + return +} + +proc ::stubs::container::declare {tablevar interface index platforms decl} { + variable legalplatforms + upvar 1 $tablevar t + + #puts "DECLARE ($interface $index) \[$platforms\] =\n\t'[join $decl "'\n\t'"]'" + + if {![dict exists $t interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + if {![string is integer -strict $index]} { + return -code error "Bad index \"$index\", expected integer" + } + + # legal platform codes + # - unix, win, macosx, x11, aqua + + # Check for duplicate declarations, then add the declaration and + # bump the lastNum counter if necessary. + + foreach platform $platforms { + if {![dict exists $legalplatforms $platform]} { + set expected [linsert [join [lsort -dict [dict keys $legalplatforms]] {, }] end-1 or] + return -code error "Bad platform \"$platform\", expected one of $expected" + } + + set key $interface,$platform,$index + if {[dict exists $t stubs $key]} { + return -code error \ + "Duplicate entry: declare $interface $index $platforms $decl" + } + } + + if {![llength $decl]} return + + dict incr t revision + + foreach platform $platforms { + set group $interface,$platform + set key $interface,$platform,$index + + dict set t stubs $key $decl + if {![dict exists $t last $group] || + ($index > [dict get $t last $group])} { + dict set t last $group $index + } + } + return +} + +# # ## ### ##### ######## ############# +# Testing methods. + +proc ::stubs::container::library? {table} { + return [dict get $table library] +} + +proc ::stubs::container::hooks? {table interface} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + return [dict exists $table hooks $interface] +} + +proc ::stubs::container::slot? {table interface platform at} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + return [dict exists $table stubs $interface,$platform,$at] +} + +proc ::stubs::container::scspec? {table} { + return [dict get $table scspec] +} + +proc ::stubs::container::revision? {table} { + return [dict get $table revision] +} + +proc ::stubs::container::epoch? {table} { + return [dict get $table epoch] +} + +# # ## ### ##### ######## ############# +# Accessor methods. + +proc ::stubs::container::interfaces {table} { + return [dict keys [dict get $table interfaces]] +} + +proc ::stubs::container::hooksof {table interface} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + if {![dict exists $table hooks $interface]} { + return {} + } + return [dict get $table hooks $interface] +} + +proc ::stubs::container::platforms {table interface} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + set res {} + #checker exclude warnArgWrite + dict with table { + #checker -scope block exclude warnUndefinedVar + # 'last' is dict element. + foreach k [dict keys $last $interface,*] { + lappend res [lindex [split $k ,] end] + } + } + return $res +} + +proc ::stubs::container::lastof {table interface {platform {}}} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + if {[llength [info level 0]] == 4} { + set key $interface,$platform + if {![dict exists $table last $key]} { + return -1 + } + return [dict get $table last $key] + } + + set res {} + #checker exclude warnArgWrite + dict with table { + #checker -scope block exclude warnUndefinedVar + # 'last' is dict element. + foreach k [dict keys $last $interface,*] { + lappend res [dict get $last $k] + } + } + return $res +} + +proc ::stubs::container::slotplatforms {table interface at} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + set res {} + #checker exclude warnArgWrite + dict with table { + #checker -scope block exclude warnUndefinedVar + # 'stubs' is dict element. + foreach k [dict keys $stubs $interface,*,$at] { + lappend res [lindex [split $k ,] 1] + } + } + return $res +} + +proc ::stubs::container::slot {table interface platform at} { + if {![dict exists $table interfaces $interface]} { + return -code error "Unknown interface \"$interface\"" + } + if {![dict exists $table stubs $interface,$platform,$at]} { + return -code error "Unknown slot \"$platform,$at\"" + } + return [dict get $table stubs $interface,$platform,$at] +} + +# # ## ### ##### ######## ############# +## Serialize, also nicely formatted for readability. + +proc ::stubs::container::print {table} { + + lappend lines "stubs [list [library? $table]] \{" + lappend lines " scspec [list [scspec? $table]]" + lappend lines " epoch [list [epoch? $table]]" + lappend lines " revision [list [revision? $table]]" + + foreach if [interfaces $table] { + lappend lines " interface [list $if] \{" + lappend lines " hooks [list [hooksof $table $if]]" + + set n -1 + foreach l [lastof $table $if] { + if {$l > $n} { set n $l } + } + # n = max lastof for the interface. + + for {set at 0} {$at <= $n} {incr at} { + + set pl [slotplatforms $table $if $at] + if {![llength $pl]} continue + + foreach p $pl { + lappend d $p [slot $table $if $p $at] + #puts |[lindex $d end-1]|[lindex $d end]| + } + # d = list of decls for the slot, per platform. + # invert and collapse... + + foreach {d plist} [Invert $d] { + #puts |$d| + #puts <$plist> + + # d = list (rtype fname arguments) + # arguments = list (argdef) + # argdef = list (atype aname arrayflag) + # | list (atype aname) + # | list (atype) + + lassign $d rtype fname fargs + + lappend lines " declare $at [list $plist] \{" + lappend lines " function [list $fname]" + lappend lines " return [list $rtype]" + foreach a $fargs { + lappend lines " argument [list $a]" + } + lappend lines " \}" + } + } + + lappend lines " \}" + } + + lappend lines "\}" + + return [join $lines \n] +} + +proc ::stubs::container::Invert {dict} { + # input dict : key -> list(value) + # result is a dict : value -> list(key) + + array set res {} + foreach {k v} $dict { + lappend res($v) $k + } + #parray res + set final {} + foreach k [lsort -dict [array names res]] { + lappend final $k [lsort -dict $res($k)] + } + return $final +} + +# # ## ### ##### ######## ############# +## API + +namespace eval ::stubs::container { + variable legalplatforms { + generic . + unix . + win . + macosx . + x11 . + aqua . + } + + namespace export \ + new library interface scspec epoch hooks declare \ + library? hooks? slot? scspec? revision? epoch? \ + interfaces hooksof platforms lastof slotplatforms slot +} + +# # ## ### ##### +package provide stubs::container 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_container/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_container/pkgIndex.tcl new file mode 100644 index 00000000..59882706 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_container/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::container 1.1.1 [list source [file join $dir container.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_decl/gen_decl.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_decl/gen_decl.tcl new file mode 100644 index 00000000..613778da --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_decl/gen_decl.tcl @@ -0,0 +1,118 @@ +# -*- tcl -*- +# STUBS handling -- Code generation: Writing declarations. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A gen is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen +package require stubs::container + +namespace eval ::stubs::gen::decl::g { + namespace import ::stubs::gen::* +} + +namespace eval ::stubs::gen::decl::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::decl::gen {table name} { + set text "\n/*\n * Exported function declarations:\n */\n\n" + append text [g::forall $table $name [list [namespace current]::Make $table] 0] + return $text +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::gen::decl::Make {table name decl index} { + #puts "DECL($name $index) = |$decl|" + + lassign $decl rtype fname args + + append text "/* $index */\n" + + set line "[c::scspec? $table] $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 {![llength $args]} { + append text $line $fname ";\n" + return $text + } + + set arg1 [lindex $args 0] + switch -exact -- $arg1 { + void { + append text $line $fname "(void)" + } + TCL_VARARGS { + append line $fname + append text [MakeArgs $line $pad [lrange $args 1 end] ", ..."] + } + default { + append line $fname + append text [MakeArgs $line $pad $args] + } + } + append text ";\n" + return $text +} + +proc ::stubs::gen::decl::MakeArgs {line pad arguments {suffix {}}} { + #checker -scope local exclude warnArgWrite + set text "" + set sep "(" + foreach arg $arguments { + append line $sep + set next {} + + lassign $arg atype aname aind + + append next $atype + if {[string index $next end] ne "*"} { + append next " " + } + append next $aname $aind + + 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 "$suffix)" + + if {[lindex $arguments end] eq "{const char *} format"} { + # TCL_VARARGS case... arguments list already shrunken. + set n [llength $arguments] + append line " TCL_FORMAT_PRINTF(" $n ", " [expr {$n + 1}] ")" + } + + return $text$line +} + +# # ## ### ##### +namespace eval ::stubs::gen::decl { + namespace export gen +} + +# # ## ### ##### +package provide stubs::gen::decl 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_decl/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_decl/pkgIndex.tcl new file mode 100644 index 00000000..4550dede --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_decl/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen::decl 1.1.1 [list source [file join $dir gen_decl.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_header/gen_header.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_header/gen_header.tcl new file mode 100644 index 00000000..22722e70 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_header/gen_header.tcl @@ -0,0 +1,110 @@ +# -*- tcl -*- +# STUBS handling -- Code generation: Writing the stub headers. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A gen is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen +package require stubs::container +package require stubs::gen::slot +package require stubs::gen::macro +package require stubs::gen::decl + +namespace eval ::stubs::gen::header::g { + namespace import ::stubs::gen::* +} +namespace eval ::stubs::gen::header::c { + namespace import ::stubs::container::* +} +namespace eval ::stubs::gen::header::s { + namespace import ::stubs::gen::slot::* +} +namespace eval ::stubs::gen::header::m { + namespace import ::stubs::gen::macro::* +} +namespace eval ::stubs::gen::header::d { + namespace import ::stubs::gen::decl::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::header::multiline {{flag 1}} { + return [m::multiline $flag] +} + +proc ::stubs::gen::header::gen {table name} { + set capName [g::cap $name] + + set epoch [c::epoch? $table] + if {$epoch ne ""} { + set CAPName [string toupper $name] + append text "\n" + append text "#define ${CAPName}_STUBS_EPOCH $epoch\n" + append text "#define ${CAPName}_STUBS_REVISION [c::revision? $table]\n" + } + + # declarations... + append text [d::gen $table $name] + + if {[c::hooks? $table $name]} { + append text "\ntypedef struct ${capName}StubHooks {\n" + foreach hook [c::hooksof $table $name] { + set capHook [g::cap $hook] + append text " const struct ${capHook}Stubs *${hook}Stubs;\n" + } + append text "} ${capName}StubHooks;\n" + } + + # stub table type definition, including field definitions aka slots... + append text "\ntypedef struct ${capName}Stubs {\n" + append text " int magic;\n" + if {$epoch ne ""} { + append text " int epoch;\n" + append text " int revision;\n" + } + append text " const struct ${capName}StubHooks *hooks;\n\n" + append text [s::gen $table $name] + append text "} ${capName}Stubs;\n" + + # stub table global variable + append text "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" + append text "extern const ${capName}Stubs *${name}StubsPtr;\n" + append text "#ifdef __cplusplus\n}\n#endif\n" + + # last, the series of macros for stub users which will route + # function calls through the table. + append text [m::gen $table $name] + + return $text +} + +proc ::stubs::gen::header::rewrite@ {basedir table name} { + rewrite [path $basedir $name] $table $name +} + +proc ::stubs::gen::header::rewrite {path table name} { + g::rewrite $path [gen $table $name] +} + +proc ::stubs::gen::header::path {basedir name} { + return [file join $basedir ${name}Decls.h] +} + +# # ## ### ##### +## Internal helpers. + +# # ## ### ##### +namespace eval ::stubs::gen::header { + namespace export gen multiline rewrite@ rewrite path +} + +# # ## ### ##### ######## ############# +package provide stubs::gen::header 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_header/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_header/pkgIndex.tcl new file mode 100644 index 00000000..715e1e76 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_header/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen::header 1.1.1 [list source [file join $dir gen_header.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_init/gen_init.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_init/gen_init.tcl new file mode 100644 index 00000000..5877c8d3 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_init/gen_init.tcl @@ -0,0 +1,188 @@ +# -*- tcl -*- +# STUBS handling -- Code generation: Writing the initialization code for EXPORTers. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A gen is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen +package require stubs::container + +namespace eval ::stubs::gen::init::g { + namespace import ::stubs::gen::* +} + +namespace eval ::stubs::gen::init::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::init::gen {table} { + # 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 [c::interfaces $table]] { + if {[c::hooks? $table $name]} { + lappend roots $name + } else { + lappend leaves $name + } + } + + set text {} + foreach name $leaves { + append text [Emit $table $name] + } + foreach name $roots { + append text [Emit $table $name] + } + + return $text +} + +proc ::stubs::gen::init::make@ {basedir table} { + make [path $basedir $table] $table +} + +proc ::stubs::gen::init::make {path table} { + variable template + + set c [open $path w] + puts -nonewline $c \ + [string map \ + [list @@ [string map {:: _} [c::library? $table]]] \ + $template] + close $c + + rewrite $path $table + return +} + +proc ::stubs::gen::init::rewrite@ {basedir table} { + rewrite [path $basedir $table] $table + return +} + +proc ::stubs::gen::init::rewrite {path table} { + g::rewrite $path [gen $table] + return +} + +proc ::stubs::gen::init::path {basedir table} { + return [file join $basedir [c::library? $table]StubInit.c] +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::gen::init::Emit {table name} { + # See tcllib/textutil as well. + set capName [g::cap $name] + + if {[c::hooks? $table $name]} { + append text "\nstatic const ${capName}StubHooks ${name}StubHooks = \{\n" + set sep " " + foreach sub [c::hooksof $table $name] { + append text $sep "&${sub}Stubs" + set sep ",\n " + } + append text "\n\};\n" + } + + # Check if this interface is a hook for some other interface. + # TODO: Make this a container API command. + set root 1 + foreach intf [c::interfaces $table] { + if {[c::hooks? $table $intf] && + ([lsearch -exact [c::hooksof $table $intf] $name] >= 0)} { + set root 0 + break + } + } + + # Hooks are local to the file. + append text "\n" + if {!$root} { + append text "static " + } + append text "const ${capName}Stubs ${name}Stubs = \{\n" + append text " TCL_STUB_MAGIC,\n" + + if {[c::epoch? $table] ne ""} { + set CAPName [string toupper $name] + append text " ${CAPName}_STUBS_EPOCH,\n" + append text " ${CAPName}_STUBS_REVISION,\n" + } + + if {[c::hooks? $table $name]} { + append text " &${name}StubHooks,\n" + } else { + append text " 0,\n" + } + + append text [g::forall $table $name [namespace current]::Make 1 \ + " 0, /* @@ */\n"] + + append text "\};\n" + return $text +} + +# Make -- +# +# 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 ::stubs::gen::init::Make {name decl index} { + #puts "INIT($name $index) = |$decl|" + + lassign $decl rtype fname args + + if {![llength $args]} { + append text " &$fname, /* $index */\n" + } else { + append text " $fname, /* $index */\n" + } + return $text +} + +# # ## ### ##### +namespace eval ::stubs::gen::init { + #checker exclude warnShadowVar + variable template [string map {{ } {}} { + /* @@StubsInit.c + * + * The contents of this file are automatically generated + * from the @@.decls file. + * + */ + + #include "@@.h" + + /* !BEGIN!: Do not edit below this line. */ + /* !END!: Do not edit above this line. */ + }] + + namespace export gen make@ make rewrite@ rewrite path +} + +# # ## ### ##### ######## ############# +package provide stubs::gen::init 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_init/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_init/pkgIndex.tcl new file mode 100644 index 00000000..023aae2e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_init/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen::init 1.1.1 [list source [file join $dir gen_init.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_lib/gen_lib.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_lib/gen_lib.tcl new file mode 100644 index 00000000..1b2bb374 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_lib/gen_lib.tcl @@ -0,0 +1,214 @@ +# -*- tcl -*- +# STUBS handling -- Code generation: Writing the initialization code for IMPORTers. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A gen is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen +package require stubs::container + +namespace eval ::stubs::gen::lib::g { + namespace import ::stubs::gen::* +} + +namespace eval ::stubs::gen::lib::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::lib::gen {table} { + # Assuming that dependencies only go one level deep, we need to + # emit all of the leaves first to avoid needing forward + # declarations. + + variable template + + # Assuming that dependencies only go one level deep, we emit all + # of the leaves first to avoid needing forward declarations. + + set leaves {} + set roots {} + + foreach name [lsort [c::interfaces $table]] { + if {[c::hooks? $table $name]} { + lappend roots $name + } else { + lappend leaves $name + } + } + + set headers {} + set variables {} + set hooks {} + + foreach name [concat $leaves $roots] { + set capName [g::cap $name] + + # POLISH - format the variables code block aligned using + # maxlength of interface names. + lappend headers "\#include \"${name}Decls.h\"" + lappend variables "const ${capName}Stubs* ${name}StubsPtr;" + + # Check if this is a hook. If yes it needs additional setup. + set parent [Parent $table $name] + if {$parent eq ""} continue + lappend hooks " ${name}StubsPtr = ${parent}StubsPtr->hooks->${name}Stubs;" + } + + set pname [c::library? $table] ; # FUTURE: May be separate from the library + # namespaces! + set name [string map {:: _} [c::library? $table]] + set capName [g::cap $name] + set upName [string toupper $name] + + set headers [Block $headers] + set variables [Block $variables] + set hooks [Block $hooks] + + return [string map \ + [list \ + @PKG@ $pname \ + @@ $name \ + @UP@ $upName \ + @CAP@ $capName \ + @HEADERS@ $headers \ + @VARS@ $variables \ + @HOOKS@ $hooks \ + ] $template] + return $text +} + +proc ::stubs::gen::lib::Block {list} { + if {![llength $list]} { return "" } + return \n[join $list \n]\n +} + +proc ::stubs::gen::lib::make@ {basedir table} { + make [path $basedir [c::library? $table]] $table +} + +proc ::stubs::gen::lib::make {path table} { + set c [open $path w] + puts -nonewline $c [gen $table] + close $c + return +} + +proc ::stubs::gen::lib::path {basedir name} { + return [file join $basedir ${name}StubLib.c] +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::gen::lib::Parent {table name} { + # Check if this interface is a hook for some other interface. + # TODO: Make this a container API command. + foreach intf [c::interfaces $table] { + if {[c::hooks? $table $intf] && + ([lsearch -exact [c::hooksof $table $intf] $name] >= 0)} { + return $intf + } + } + return "" +} + +# # ## ### ##### +namespace eval ::stubs::gen::lib { + #checker exclude warnShadowVar + variable template [string map {{ + } { +}} { + /* + * @@StubLib.c -- + * + * Stub object that will be statically linked into extensions that wish + * to access @@. + */ + + /* + * We need to ensure that we use the stub macros so that this file contains + * no references to any of the stub functions. This will make it possible + * to build an extension that references @CAP@_InitStubs but doesn't end up + * including the rest of the stub functions. + */ + + #ifndef USE_TCL_STUBS + #define USE_TCL_STUBS + #endif + #undef USE_TCL_STUB_PROCS + + #include + + #ifndef USE_@UP@_STUBS + #define USE_@UP@_STUBS + #endif + #undef USE_@UP@_STUB_PROCS + @HEADERS@ + /* + * Ensure that @CAP@_InitStubs is built as an exported symbol. The other stub + * functions should be built as non-exported symbols. + */ + + #undef TCL_STORAGE_CLASS + #define TCL_STORAGE_CLASS DLLEXPORT + @VARS@ + + /* + *---------------------------------------------------------------------- + * + * @CAP@_InitStubs -- + * + * Checks that the correct version of @CAP@ is loaded and that it + * supports stubs. It then initialises the stub table pointers. + * + * Results: + * The actual version of @CAP@ that satisfies the request, or + * NULL to indicate that an error occurred. + * + * Side effects: + * Sets the stub table pointers. + * + *---------------------------------------------------------------------- + */ + + #ifdef @CAP@_InitStubs + #undef @CAP@_InitStubs + #endif + + char * + @CAP@_InitStubs(Tcl_Interp *interp, CONST char *version, int exact) + { + CONST char *actualVersion; + + actualVersion = Tcl_PkgRequireEx(interp, "@PKG@", version, + exact, (ClientData *) &@@StubsPtr); + if (!actualVersion) { + return NULL; + } + + if (!@@StubsPtr) { + Tcl_SetResult(interp, + "This implementation of @CAP@ does not support stubs", + TCL_STATIC); + return NULL; + } + @HOOKS@ + return (char*) actualVersion; + } + }] + + namespace export gen make@ make rewrite@ rewrite path +} + +# # ## ### ##### ######## ############# +package provide stubs::gen::lib 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_lib/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_lib/pkgIndex.tcl new file mode 100644 index 00000000..4f38729e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_lib/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen::lib 1.1.1 [list source [file join $dir gen_lib.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_macro/gen_macro.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_macro/gen_macro.tcl new file mode 100644 index 00000000..a4ff1d0e --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_macro/gen_macro.tcl @@ -0,0 +1,73 @@ +# -*- tcl -*- +# STUBS handling -- Code generation: Writing the stub macros. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A gen is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen +package require stubs::container + +namespace eval ::stubs::gen::macro::g { + namespace import ::stubs::gen::* +} + +namespace eval ::stubs::gen::macro::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::macro::multiline {{flag 1}} { + variable multiline $flag + return $flag +} + +proc ::stubs::gen::macro::gen {table name} { + set upName [string toupper [string map {:: _} [c::library? $table]]] + set sguard "defined(USE_${upName}_STUBS)" + + append text "\n#if $sguard\n" + append text "\n/*\n * Inline function declarations:\n */\n\n" + append text [g::forall $table $name [namespace current]::Make 0] + append text "\n#endif /* $sguard */\n" + return $text +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::gen::macro::Make {name decl index} { + variable multiline + #puts "MACRO($name $index) = |$decl|" + + lassign $decl rtype fname args + + set capName [g::uncap $fname] + + append text "#define $fname " + if {$multiline} { append text "\\\n\t" } + append text "(" + if {![llength $args]} { append text "*" } + append text "${name}StubsPtr->$capName)" + append text " /* $index */\n" + return $text +} + +# # ## ### ##### +namespace eval ::stubs::gen::macro { + #checker exclude warnShadowVar + variable multiline 1 + + namespace export gen multiline +} + +# # ## ### ##### ######## ############# +package provide stubs::gen::macro 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_macro/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_macro/pkgIndex.tcl new file mode 100644 index 00000000..14a52db7 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_macro/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen::macro 1.1.1 [list source [file join $dir gen_macro.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_slot/gen_slot.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_slot/gen_slot.tcl new file mode 100644 index 00000000..caad7b51 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_slot/gen_slot.tcl @@ -0,0 +1,95 @@ +# -*- tcl -*- +# STUBS handling -- Code generation: Writing SLOT code. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen + +namespace eval ::stubs::gen::slot::g { + namespace import ::stubs::gen::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::slot::gen {table name} { + return [g::forall $table $name [namespace current]::Make 1 \ + " void (*reserved@@)(void);\n"] +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::gen::slot::Make {name decl index} { + #puts "SLOT($name $index) = |$decl|" + + lassign $decl rtype fname args + + set capName [g::uncap $fname] + + set text " " + if {![llength $args]} { + append text $rtype " *" $capName "; /* $index */\n" + return $text + } + + if {[string range $rtype end-7 end] eq "CALLBACK"} { + append text \ + [string trim [string range $rtype 0 end-8]] \ + " (CALLBACK *" $capName ") " + } else { + append text $rtype " (*" $capName ") " + } + + set arg1 [lindex $args 0] + switch -exact -- $arg1 { + void { + append text "(void)" + } + TCL_VARARGS { + append text [MakeArgs [lrange $args 1 end] ", ..."] + } + default { + append text [MakeArgs $args] + } + } + + append text "; /* $index */\n" + return $text +} + +proc ::stubs::gen::slot::MakeArgs {arguments {suffix {}}} { + set text "" + set sep "(" + foreach arg $arguments { + lassign $arg atype aname aind + append text $sep $atype + if {[string index $text end] ne "*"} { + append text " " + } + append text $aname $aind + set sep ", " + } + append text "$suffix)" + + if {[lindex $arguments end] eq "\{const char *\} format"} { + # TCL_VARARGS case... arguments list already shrunken. + set n [llength $arguments] + append text " TCL_FORMAT_PRINTF(" $n ", " [expr {$n + 1}] ")" + } + + return $text +} + +# # ## ### ##### +namespace eval ::stubs::gen::slot { + namespace export gen +} + +# # ## ### ##### +package provide stubs::gen::slot 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_gen_slot/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_gen_slot/pkgIndex.tcl new file mode 100644 index 00000000..f73a4e10 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_gen_slot/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen::slot 1.1.1 [list source [file join $dir gen_slot.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_genframe/genframe.tcl b/src/vfs/critcl.vfs/lib/stubs_genframe/genframe.tcl new file mode 100644 index 00000000..d0fcbf6a --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_genframe/genframe.tcl @@ -0,0 +1,418 @@ +# -*- tcl -*- +# STUBS handling -- Code generation framework. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A gen is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::container + +namespace eval ::stubs::gen::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::gen::warn {cmdprefix} { + variable warnCmd $cmdprefix + return +} + +proc ::stubs::gen::uncap {text} { + return [string tolower [string index $text 0]][string range $text 1 end] +} + +proc ::stubs::gen::cap {text} { + return [string toupper [string index $text 0]][string range $text 1 end] +} + +proc ::stubs::gen::forall {table name emitCmd onAll {skipString {}}} { + if {$skipString eq {}} { + #checker exclude warnArgWrite + set skipString "/* Slot @@ is reserved */\n" + } + + set platforms [c::platforms $table $name] + + if {[lsearch -exact $platforms "generic"] >= 0} { + # Emit integrated stubs block + set lastNum [MAX [c::lastof $table $name]] + + for {set i 0} {$i <= $lastNum} {incr i} { + + set slots [c::slotplatforms $table $name $i] + set emit 0 + if {[lsearch -exact $slots "generic"] >= 0} { + if {[llength $slots] > 1} { + WARN {conflicting generic and platform entries: $name $i} + } + + append text [CALL generic $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($s) 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)))} { + WARN {conflicting platform entries: $name $i} + } + ## unix ## + set temp {} + set plat unix + if {!$slot(aqua) && !$slot(x11)} { + if {$slot($plat)} { + append temp [CALL $plat $i] + } elseif {$onAll} { + append temp [SKIP] + } + } + 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 [CALL $plat $i] + } elseif {$onAll} { + append temp [SKIP] + } + } + if {$temp ne ""} { + append text [AddPlatformGuard $plat $temp] + set emit 1 + } + ## win ## + set temp {} + set plat win + if {$slot($plat)} { + append temp [CALL $plat $i] + } elseif {$onAll} { + append temp [SKIP] + } + 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 [CALL $plat $i] + } elseif {$slot(unix)} { + append temp [CALL unix $i] + } elseif {$onAll} { + append temp [SKIP] + } + } + 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 0 1] ne "/*"} { + # The code 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). + append temp [SKIP] + CHOP temp + append temp " /*\ + Dummy entry for stubs table backwards\ + compatibility */\n" + } + if {$slot($plat)} { + append temp [CALL $plat $i] + } elseif {$onAll} { + append temp [SKIP] + } + } + if {$temp ne ""} { + append text [AddPlatformGuard $plat $temp] + set emit 1 + } + } + if {!$emit} { + append text [SKIP] + } + } + } else { + # Emit separate stubs blocks per platform + array set block {unix 0 x11 0 win 0 macosx 0 aqua 0} + foreach s $platforms { set block($s) 1 } + + ## unix ## + if {$block(unix) && !$block(x11)} { + set temp {} + set plat unix + + # (1) put into helper method + set lastNum [c::lastof $table $name $plat] + for {set i 0} {$i <= $lastNum} {incr i} { + if {[c::slot? $table $name $plat $i]} { + append temp [CALL $plat $i] + } else { + append temp [SKIP] + } + } + append text [AddPlatformGuard $plat $temp] + } + ## win ## + if {$block(win)} { + set temp {} + set plat win + + # (1) put into helper method + set lastNum [c::lastof $table $name $plat] + for {set i 0} {$i <= $lastNum} {incr i} { + if {[c::slot? $table $name $plat $i]} { + append temp [CALL $plat $i] + } else { + append temp [SKIP] + } + } + append text [AddPlatformGuard $plat $temp] + } + ## macosx ## + if {$block(macosx) && !$block(aqua) && !$block(x11)} { + set temp {} + set lastNum [MAX [list \ + [c::lastof $table $name unix] \ + [c::lastof $table $name macosx]]] + + for {set i 0} {$i <= $lastNum} {incr i} { + set emit 0 + foreach plat {unix macosx} { + if {[c::slot? $table $name $plat $i]} { + append temp [CALL $plat $i] + set emit 1 + break + } + } + if {!$emit} { + append temp [SKIP] + } + } + append text [AddPlatformGuard macosx $temp] + } + ## aqua ## + if {$block(aqua)} { + set temp {} + set lastNum [MAX [list \ + [c::lastof $table $name unix] \ + [c::lastof $table $name macosx] \ + [c::lastof $table $name aqua]]] + + for {set i 0} {$i <= $lastNum} {incr i} { + set emit 0 + foreach plat {unix macosx aqua} { + if {[c::slot? $table $name $plat $i]} { + append temp [CALL $plat $i] + set emit 1 + break + } + } + if {!$emit} { + append temp [SKIP] + } + } + append text [AddPlatformGuard aqua $temp] + } + ## x11 ## + if {$block(x11)} { + set temp {} + set lastNum [MAX [list \ + [c::lastof $table $name unix] \ + [c::lastof $table $name macosx] \ + [c::lastof $table $name x11]]] + + for {set i 0} {$i <= $lastNum} {incr i} { + set emit 0 + foreach plat {unix macosx x11} { + if {[c::slot? $table $name $plat $i]} { + if {$plat ne "macosx"} { + append temp [CALL $plat $i] + } else { + append temp [AddPlatformGuard $plat \ + [CALL $plat $i] \ + [SKIP]] + } + set emit 1 + break + } + } + if {!$emit} { + append temp [SKIP] + } + } + append text [AddPlatformGuard x11 $temp] + } + } + + return $text +} + +proc ::stubs::gen::rewrite {path newcode} { + if {![file exists $path]} { + return -code error "Cannot find file: $path" + } + + set in [open ${path} r] + set out [open ${path}.new w] + + # Hardwired use of unix line-endings in the output. + fconfigure $out -translation lf + + # Copy the file header before the code section. + while {![eof $in]} { + set line [gets $in] + if {[string match "*!BEGIN!*" $line]} break + puts $out $line + } + + puts $out "/* !BEGIN!: Do not edit below this line. */" + + # Insert the new code. + puts $out $newcode + + # Skip over the input until the end of the code section. + while {![eof $in]} { + set line [gets $in] + if {[string match "*!END!*" $line]} break + } + + # Copy the trailer after the code section. This can be done fast, + # as searching is not required anymore. + puts $out "/* !END!: Do not edit above this line. */" + puts -nonewline $out [read $in] + + # Close and commit to the changes (atomic rename). + close $in + close $out + file rename -force -- ${path}.new ${path} + return +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::gen::CALL {platform index} { + upvar 1 table table name name emitCmd emitCmd + set decl [c::slot $table $name $platform $index] + return [uplevel \#0 [linsert $emitCmd end $name $decl $index]] +} + +proc ::stubs::gen::WARN {text} { + variable warnCmd + if {$warnCmd eq {}} return + return [uplevel \#0 [linsert $warnCmd end [uplevel 1 [list ::subst $text]]]] +} + +proc ::stubs::gen::SKIP {} { + upvar 1 skipString skipString i i + #puts stderr SKIP/$i/[string map [list {$i} $i] $skipString] + return [string map [list @@ $i] $skipString] +} + +proc ::stubs::gen::CHOP {textvar} { + upvar 1 $textvar text + set text [string range $text 0 end-1] + return +} + +proc ::stubs::gen::AddPlatformGuard {platform iftext {elsetext {}}} { + variable guard_begin + variable guard_else + variable guard_end + + set prefix [expr {![info exists guard_begin($platform)] ? "" : $guard_begin($platform)}] + set middle [expr {![info exists guard_else($platform)] ? "" : $guard_else($platform)}] + set suffix [expr {![info exists guard_end($platform)] ? "" : $guard_end($platform)}] + + return $prefix$iftext[expr {($elsetext eq "") + ? "" + : "$middle$elsetext"}]$suffix +} + +if {[package vsatisfies [package present Tcl] 8.5]} { + #checker exclude warnRedefine + proc ::stubs::gen::MAX {list} { + return [tcl::mathfunc::max {*}$list] + } +} else { + #checker exclude warnRedefine + proc ::stubs::gen::MAX {list} { + set max {} + foreach a $list { + if {($max ne {}) && ($max >= $a)} continue + set max $a + } + return $a + } +} + +# # ## ### ##### + +namespace eval ::stubs::gen { + #checker -scope block exclude warnShadowVar + variable guard_begin + variable guard_else + variable guard_end + + array set guard_begin { + win "#ifdef __WIN32__ /* WIN */\n" + unix "#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */\n" + macosx "#ifdef MAC_OSX_TCL /* MACOSX */\n" + aqua "#ifdef MAC_OSX_TK /* AQUA */\n" + x11 "#if !(defined(__WIN32__) || defined(MAC_OSX_TK)) /* X11 */\n" + } + array set guard_else { + win "#else /* WIN */\n" + unix "#else /* UNIX */\n" + macosx "#else /* MACOSX */\n" + aqua "#else /* AQUA */\n" + x11 "#else /* X11 */\n" + } + array set guard_end { + win "#endif /* WIN */\n" + unix "#endif /* UNIX */\n" + macosx "#endif /* MACOSX */\n" + aqua "#endif /* AQUA */\n" + x11 "#endif /* X11 */\n" + } + + # Default command to report conflict and other warnings. + variable warnCmd {puts stderr} + + namespace export forall rewrite warn cap uncap +} + +# # ## ### ##### +package provide stubs::gen 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_genframe/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_genframe/pkgIndex.tcl new file mode 100644 index 00000000..1a177ee6 --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_genframe/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::gen 1.1.1 [list source [file join $dir genframe.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_reader/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_reader/pkgIndex.tcl new file mode 100644 index 00000000..93cbb83d --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_reader/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::reader 1.1.1 [list source [file join $dir reader.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_reader/reader.tcl b/src/vfs/critcl.vfs/lib/stubs_reader/reader.tcl new file mode 100644 index 00000000..1e46c23a --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_reader/reader.tcl @@ -0,0 +1,245 @@ +# -*- tcl -*- +# STUBS handling -- Reader. +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::container + +# A stubs table is represented by a dictionary value. +# A container is a variable holding a stubs table value. + +namespace eval ::stubs::reader::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::reader::file {tablevar path} { + upvar 1 $tablevar table + + set chan [open $path r] + set text [read $chan] + close $chan + + text table $text + return +} + +proc ::stubs::reader::text {tablevar text} { + variable current + variable table + + upvar 1 $tablevar t + + set sandbox [interp create -safe] + + interp alias $sandbox library {} ::stubs::reader::P_library + interp alias $sandbox interface {} ::stubs::reader::P_interface + interp alias $sandbox scspec {} ::stubs::reader::P_scspec + interp alias $sandbox epoch {} ::stubs::reader::P_epoch + interp alias $sandbox hooks {} ::stubs::reader::P_hooks + interp alias $sandbox declare {} ::stubs::reader::P_declare + interp alias $sandbox export {} ::stubs::reader::P_export + + set current UNKNOWN + set table $t + + set ::errorCode {} + set ::errorInfo {} + + if {![set code [catch { + $sandbox eval $text + } res]]} { + set t $table + } + + interp delete $sandbox + unset table + + return -code $code -errorcode $::errorCode -errorinfo $::errorInfo \ + $res +} + +# READER API methods. These are called when sourcing a .decls +# file, or evaluating a .decls string. They forward to the +# attached container after pre-processing arguments and merging in +# state information (current interface). + +proc ::stubs::reader::P_library {name} { + variable table + c::library table $name + return +} + +proc ::stubs::reader::P_interface {name} { + variable table + variable current + + set current $name + c::interface table $name + return +} + +proc ::stubs::reader::P_scspec {value} { + variable table + c::scspec table $value + return +} + +proc ::stubs::reader::P_epoch {value} { + variable table + c::epoch table $value + return +} + +proc ::stubs::reader::P_hooks {names} { + variable table + variable current + + c::hooks table $current $names + return +} + +proc ::stubs::reader::P_declare {index args} { + variable table + variable current + + switch -exact [llength $args] { + 1 { + # syntax: declare AT DECL + set platforms [list generic] + set decl [lindex $args 0] + } + 2 { + # syntax: declare AT PLATFORMS DECL + lassign $args platforms decl + } + default { + return -code error \ + "wrong \# args: expected 'index ?platforms? decl" + } + } + + c::declare table $current $index $platforms [ParseDecl $decl] + return +} + +proc ::stubs::reader::P_export {decl} { + variable table + variable current + + # Ignore. + return +} + +# Support methods for parsing a C declaration into its constituent +# pieces. + +# ParseDecl -- +# +# Parse a C function declaration into its component parts. +# +# Arguments: +# decl The function declaration. +# +# Results: +# Returns a list of the form {returnType name arguments}. The arguments +# 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 ::stubs::reader::ParseDecl {decl} { + #checker exclude warnArgWrite + regsub -all "\[ \t\n\]+" [string trim $decl] " " decl + #puts "PARSE ($decl)" + + if {![regexp {^(.*)\((.*)\)$} $decl --> prefix arguments]} { + set prefix $decl + set arguments {} + } + + set prefix [string trim $prefix] + if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix --> rtype fname]} { + return -code error "Bad return type: $decl" + } + + set rtype [string trim $rtype] + if {$arguments eq ""} { + return [list $rtype $fname {void}] + } + + foreach arg [split $arguments ,] { + lappend argumentList [string trim $arg] + } + + if {[lindex $argumentList end] eq "..."} { + set arguments TCL_VARARGS + foreach arg [lrange $argumentList 0 end-1] { + set argInfo [ParseArg $arg] + set arity [llength $argInfo] + if {(2 <= $arity) && ($arity <= 3)} { + lappend arguments $argInfo + } else { + return -code error "Bad argument: '$arg' in '$decl'" + } + } + } else { + set arguments {} + foreach arg $argumentList { + set argInfo [ParseArg $arg] + if {$argInfo eq "void"} { + lappend arguments "void" + break + } + set arity [llength $argInfo] + if {(2 <= $arity) && ($arity <= 3)} { + lappend arguments $argInfo + } else { + return -code error "Bad argument: '$arg' in '$decl'" + } + } + } + return [list $rtype $fname $arguments] +} + +# 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 ::stubs::reader::ParseArg {arg} { + if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} { + if {$arg eq "void"} { + return $arg + } else { + return + } + } + set result [list [string trim $type] $name] + if {$array ne ""} { + lappend result $array + } + return $result +} + +# # ## ### ##### ######## ############# +## API + +namespace eval ::stubs::reader { + namespace export file text +} + +# # ## ### ##### +package provide stubs::reader 1.1.1 +return diff --git a/src/vfs/critcl.vfs/lib/stubs_writer/pkgIndex.tcl b/src/vfs/critcl.vfs/lib/stubs_writer/pkgIndex.tcl new file mode 100644 index 00000000..96f9a40a --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_writer/pkgIndex.tcl @@ -0,0 +1,3 @@ +if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} +#checker -scope global exclude warnUndefinedVar +package ifneeded stubs::writer 1.1.1 [list source [file join $dir writer.tcl]] diff --git a/src/vfs/critcl.vfs/lib/stubs_writer/writer.tcl b/src/vfs/critcl.vfs/lib/stubs_writer/writer.tcl new file mode 100644 index 00000000..ba20076f --- /dev/null +++ b/src/vfs/critcl.vfs/lib/stubs_writer/writer.tcl @@ -0,0 +1,120 @@ +# -*- tcl -*- +# STUBS handling -- Write stubs table as .decls file +# +# (c) 2011,2022-2023 Andreas Kupries http://wiki.tcl.tk/andreas%20kupries + +# A stubs table is represented by a dictionary value. +# A container is a variable holding a stubs table value. + +# # ## ### ##### ######## ############# +## Requisites + +package require Tcl 8.6 9 +package require stubs::gen +package require stubs::container + +namespace eval ::stubs::writer::g { + namespace import ::stubs::gen::* +} + +namespace eval ::stubs::writer::c { + namespace import ::stubs::container::* +} + +# # ## ### ##### ######## ############# +## Implementation. + +proc ::stubs::writer::gen {table} { + + set defaults [c::new] + set dscspec [c::scspec? $defaults] + set depoch [c::epoch? $defaults] + + set name [c::library? $table] + set scspec [c::scspec? $table] + set epoch [c::epoch? $table] + set rev [c::revision? $table] + + lappend lines "\# ${name}.decls -- -*- tcl -*-" + lappend lines "\#" + lappend lines "\#\tThis file contains the declarations for all public functions" + lappend lines "\#\tthat are exported by the \"${name}\" library via its stubs table." + lappend lines "\#" + + lappend lines "" + lappend lines "library [list $name]" + + if {($scspec ne $dscspec) || + ($epoch ne $depoch )} { + if {$scspec ne $dscspec} { + lappend lines "scspec [list $scspec]" + } + if {$epoch ne $depoch } { + lappend lines "epoch [list $epoch]" + lappend lines "revision [list $rev]" + } + } + + foreach if [c::interfaces $table] { + lappend lines "" + lappend lines "interface [list $if]" + + if {[c::hooks? $table $if]} { + lappend lines "hooks [list [c::hooksof $table $if]]" + } + lappend lines \ + [g::forall $table $if \ + [list [namespace current]::Make $table] \ + 0] + } + + lappend lines "\# END $name" + + return [join $lines \n] +} + +# # ## ### ##### +## Internal helpers. + +proc ::stubs::writer::Make {table if decl index} { + #puts |--------------------------------------- + #puts |$if|$index|$decl| + + lassign $decl rtype fname arguments + if {[llength $arguments]} { + # what about the third piece of info, array flag?! ... + + set suffix {} + foreach a $arguments { + if {$a eq "void"} { + lappend ax $a + } elseif {$a eq "TCL_VARARGS"} { + set suffix ", ..." + } else { + lassign $a atype aname aflag + # aflag either "", or "[]". + lappend ax "$atype $aname$aflag" + #puts \t|$atype|$aname|$aflag| + } + } + set ax [join $ax {, }]$suffix + } else { + set ax void + } + set cdecl "\n $rtype $fname ($ax)\n" + set platforms [c::slotplatforms $table $if $index] + + lappend lines "" + lappend lines "declare $index [list $platforms] \{$cdecl\}" + + return [join $lines \n]\n +} + +# # ## ### ##### +namespace eval ::stubs::writer { + namespace export gen +} + +# # ## ### ##### +package provide stubs::writer 1.1.1 +return diff --git a/src/vfs/critcl.vfs/license.terms b/src/vfs/critcl.vfs/license.terms new file mode 100644 index 00000000..9dbd87fe --- /dev/null +++ b/src/vfs/critcl.vfs/license.terms @@ -0,0 +1,40 @@ +This software is copyrighted by Jean-Claude Wippler, Steve Landers +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. diff --git a/src/vfs/critcl.vfs/main.tcl b/src/vfs/critcl.vfs/main.tcl new file mode 100644 index 00000000..4c290c87 --- /dev/null +++ b/src/vfs/critcl.vfs/main.tcl @@ -0,0 +1,20 @@ +if {![catch { + # Kit related main: + package require starkit +}]} { + if {[starkit::startup] == "sourced"} return +} else { + # Direct invoke without kit (sourced/debug/dev-edition), assume + # relative location of the required packages: + lappend ::auto_path [file join [file dirname [info script]] lib] +} +package require critcl::app 3 +if {[lindex $::argv 0] eq "tclsh"} { + puts stdout "Attempting to drop into tclsh shell.." + set ::tcl_interactive 1 + puts "stdin: [chan configure stdin]" + set ::tclsh(dorepl) 1 +} else { + #puts [package ifneeded critcl [package require critcl::app 3]] + critcl::app::main $argv +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.0 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.0 new file mode 100644 index 00000000..47529dd0 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.0 @@ -0,0 +1,17 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, objc, objv); + _rv = tcl__command0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.1 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.1 new file mode 100644 index 00000000..ff2d06e9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.1 @@ -0,0 +1,17 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData CD, Tcl_Interp *IP, Tcl_Size OC, Tcl_Obj *CONST OV[]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData CD, Tcl_Interp *IP, Tcl_Size OC, Tcl_Obj *CONST OV[]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, OC, OV); + _rv = tcl__command0_actual (CD, IP, OC, OV); + return critcl_trace_cmd_result (_rv, IP); +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.2 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.2 new file mode 100644 index 00000000..b54e6f31 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.2 @@ -0,0 +1,16 @@ +/* ---------------------------------------------------------------------- */ + +static int +snafu_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} + +static int +snafu(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args ("snafu", objc, objv); + _rv = snafu_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.3 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.3 new file mode 100644 index 00000000..afedaa70 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.3 @@ -0,0 +1,17 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_command_max0 "::the::command+max" +static int +tcl__the_command_max0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} + +static int +tcl__the_command_max0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__the_command_max0, objc, objv); + _rv = tcl__the_command_max0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.4 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.4 new file mode 100644 index 00000000..47529dd0 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.4 @@ -0,0 +1,17 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, objc, objv); + _rv = tcl__command0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.5 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.5 new file mode 100644 index 00000000..47529dd0 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/2.5 @@ -0,0 +1,17 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, objc, objv); + _rv = tcl__command0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.0 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.0 new file mode 100644 index 00000000..aea8ff12 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.0 @@ -0,0 +1,19 @@ +*#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, objc, objv); + _rv = tcl__command0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} +* +Fake_Init* +*Tcl_CreateObjCommand2(interp, ns__command0, tcl__command0, NULL, NULL); +* diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.4 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.4 new file mode 100644 index 00000000..e9729f59 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.4 @@ -0,0 +1,19 @@ +*#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, objc, objv); + _rv = tcl__command0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} +* +Fake_Init* +*Tcl_CreateObjCommand2(interp, ns__command0, tcl__command0, NULL, DELE); +* diff --git a/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.5 b/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.5 new file mode 100644 index 00000000..78e21b07 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand-trace/3.5 @@ -0,0 +1,19 @@ +*#define ns__command0 "::command" +static int +tcl__command0_actual(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ +return TCL_OK; +} + +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ + int _rv; + critcl_trace_cmd_args (ns__command0, objc, objv); + _rv = tcl__command0_actual (clientdata, interp, objc, objv); + return critcl_trace_cmd_result (_rv, interp); +} +* +Fake_Init* +*Tcl_CreateObjCommand2(interp, ns__command0, tcl__command0, ABC, NULL); +* diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/2.0 b/src/vfs/critcl.vfs/test/assets/ccommand/2.0 new file mode 100644 index 00000000..02e19590 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/2.0 @@ -0,0 +1,8 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__command0 "::command" +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/2.1 b/src/vfs/critcl.vfs/test/assets/ccommand/2.1 new file mode 100644 index 00000000..dd2d7ab8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/2.1 @@ -0,0 +1,8 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__command0 "::command" +static int +tcl__command0(ClientData CD, Tcl_Interp *IP, Tcl_Size OC, Tcl_Obj *CONST OV[]) +{ +return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/2.2 b/src/vfs/critcl.vfs/test/assets/ccommand/2.2 new file mode 100644 index 00000000..df424313 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/2.2 @@ -0,0 +1,7 @@ +/* ---------------------------------------------------------------------- */ + +static int +snafu(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/2.3 b/src/vfs/critcl.vfs/test/assets/ccommand/2.3 new file mode 100644 index 00000000..e1644243 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/2.3 @@ -0,0 +1,8 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_command_max0 "::the::command+max" +static int +tcl__the_command_max0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/3.0 b/src/vfs/critcl.vfs/test/assets/ccommand/3.0 new file mode 100644 index 00000000..15ccc9e0 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/3.0 @@ -0,0 +1,10 @@ +*#define ns__command0 "::command" +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ +return TCL_OK; +} +* +Fake_Init* +*Tcl_CreateObjCommand2(interp, ns__command0, tcl__command0, NULL, NULL); +* diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/3.4 b/src/vfs/critcl.vfs/test/assets/ccommand/3.4 new file mode 100644 index 00000000..07b4c717 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/3.4 @@ -0,0 +1,10 @@ +*#define ns__command0 "::command" +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ +return TCL_OK; +} +* +Fake_Init* +*Tcl_CreateObjCommand2(interp, ns__command0, tcl__command0, NULL, DELE); +* diff --git a/src/vfs/critcl.vfs/test/assets/ccommand/3.5 b/src/vfs/critcl.vfs/test/assets/ccommand/3.5 new file mode 100644 index 00000000..2e53e4ec --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/ccommand/3.5 @@ -0,0 +1,10 @@ +*#define ns__command0 "::command" +static int +tcl__command0(ClientData clientdata, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *CONST objv\[\]) +{ +return TCL_OK; +} +* +Fake_Init* +*Tcl_CreateObjCommand2(interp, ns__command0, tcl__command0, ABC, NULL); +* diff --git a/src/vfs/critcl.vfs/test/assets/cconst-trace/2.0 b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.0 new file mode 100644 index 00000000..a2f9e39f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.0 @@ -0,0 +1,22 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" + +static int +tcl__alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__alpha0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Const - - -- --- ----- -------- */ + rv = 1; + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst-trace/2.1 b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.1 new file mode 100644 index 00000000..e35f700a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.1 @@ -0,0 +1,22 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" + +static int +tcl__alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__alpha0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Const - - -- --- ----- -------- */ + rv = FOO; + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst-trace/2.2 b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.2 new file mode 100644 index 00000000..817957b5 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.2 @@ -0,0 +1,22 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" + +static int +tcl__alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__alpha0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Const - - -- --- ----- -------- */ + rv = foo(); + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst-trace/2.3 b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.3 new file mode 100644 index 00000000..7c1d7483 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst-trace/2.3 @@ -0,0 +1,22 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_alpha0 "::the::alpha" + +static int +tcl__the_alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__the_alpha0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Const - - -- --- ----- -------- */ + rv = 0; + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst/2.0 b/src/vfs/critcl.vfs/test/assets/cconst/2.0 new file mode 100644 index 00000000..ec316d85 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst/2.0 @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" + +static int +tcl__alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Const - - -- --- ----- -------- */ + rv = 1; + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst/2.1 b/src/vfs/critcl.vfs/test/assets/cconst/2.1 new file mode 100644 index 00000000..77685dfa --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst/2.1 @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" + +static int +tcl__alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Const - - -- --- ----- -------- */ + rv = FOO; + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst/2.2 b/src/vfs/critcl.vfs/test/assets/cconst/2.2 new file mode 100644 index 00000000..a41bd8f4 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst/2.2 @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" + +static int +tcl__alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Const - - -- --- ----- -------- */ + rv = foo(); + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cconst/2.3 b/src/vfs/critcl.vfs/test/assets/cconst/2.3 new file mode 100644 index 00000000..be39cb03 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cconst/2.3 @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_alpha0 "::the::alpha" + +static int +tcl__the_alpha0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Const - - -- --- ----- -------- */ + rv = 0; + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cdata-trace/2.0 b/src/vfs/critcl.vfs/test/assets/cdata-trace/2.0 new file mode 100644 index 00000000..1291ece7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cdata-trace/2.0 @@ -0,0 +1,21 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" +static int +tcl__alpha0_actual(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +static char script[4] = { + 98,101,116,97, + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, 4); + return TCL_OK; +} + +static int +tcl__alpha0(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__alpha0, objc, objv); + _rv = tcl__alpha0_actual (dummy, ip, objc, objv); + return critcl_trace_cmd_result (_rv, ip); +} diff --git a/src/vfs/critcl.vfs/test/assets/cdata-trace/2.1 b/src/vfs/critcl.vfs/test/assets/cdata-trace/2.1 new file mode 100644 index 00000000..04532cf7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cdata-trace/2.1 @@ -0,0 +1,21 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha_x0 "::alpha-x" +static int +tcl__alpha_x0_actual(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +static char script[4] = { + 98,101,116,97, + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, 4); + return TCL_OK; +} + +static int +tcl__alpha_x0(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__alpha_x0, objc, objv); + _rv = tcl__alpha_x0_actual (dummy, ip, objc, objv); + return critcl_trace_cmd_result (_rv, ip); +} diff --git a/src/vfs/critcl.vfs/test/assets/cdata-trace/2.2 b/src/vfs/critcl.vfs/test/assets/cdata-trace/2.2 new file mode 100644 index 00000000..233d28ce --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cdata-trace/2.2 @@ -0,0 +1,21 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_alpha0 "::the::alpha" +static int +tcl__the_alpha0_actual(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +static char script[4] = { + 98,101,116,97, + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, 4); + return TCL_OK; +} + +static int +tcl__the_alpha0(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ + int _rv; + critcl_trace_cmd_args (ns__the_alpha0, objc, objv); + _rv = tcl__the_alpha0_actual (dummy, ip, objc, objv); + return critcl_trace_cmd_result (_rv, ip); +} diff --git a/src/vfs/critcl.vfs/test/assets/cdata/2.0 b/src/vfs/critcl.vfs/test/assets/cdata/2.0 new file mode 100644 index 00000000..4d270b1a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cdata/2.0 @@ -0,0 +1,12 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha0 "::alpha" +static int +tcl__alpha0(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +static char script[4] = { + 98,101,116,97, + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, 4); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cdata/2.1 b/src/vfs/critcl.vfs/test/assets/cdata/2.1 new file mode 100644 index 00000000..d1df2fa8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cdata/2.1 @@ -0,0 +1,12 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__alpha_x0 "::alpha-x" +static int +tcl__alpha_x0(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +static char script[4] = { + 98,101,116,97, + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, 4); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cdata/2.2 b/src/vfs/critcl.vfs/test/assets/cdata/2.2 new file mode 100644 index 00000000..2833a7b7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cdata/2.2 @@ -0,0 +1,12 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_alpha0 "::the::alpha" +static int +tcl__the_alpha0(ClientData dummy, Tcl_Interp *ip, Tcl_Size objc, Tcl_Obj *CONST objv[]) +{ +static char script[4] = { + 98,101,116,97, + }; + Tcl_SetByteArrayObj(Tcl_GetObjResult(ip), (unsigned char*) script, 4); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.0 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.0 new file mode 100644 index 00000000..8b0424f7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.0 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.1 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.1 new file mode 100644 index 00000000..f1463dbd --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.1 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_aproc0 "::the::aproc" +static void c__the_aproc0() +{ + +} + +static int +tcl__the_aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args (ns__the_aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c__the_aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.10 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.10 new file mode 100644 index 00000000..9b0090b4 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.10 @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int has_x, int x, int y, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _y; + int _z; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if ((oc < 3) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "?x? y z"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 2) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + idx_++; + argc_--; + + + /* (int z) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _y, _z); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.11 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.11 new file mode 100644 index 00000000..dd548abe --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.11 @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x, int y, int has_z, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _y; + int _has_z = 0; + int _z; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if ((oc < 3) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "x y ?z?"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[2], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + idx_ = 3; + argc_ = oc - 3; + + /* (int z, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 0) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + _has_z = 1; + } else { + _z = -1; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _y, _has_z, _z); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.12 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.12 new file mode 100644 index 00000000..99be1fdb --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.12 @@ -0,0 +1,56 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x, int has_y, int y, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _has_y = 0; + int _y; + int _z; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if ((oc < 3) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "x ?y? z"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + idx_ = 2; + argc_ = oc - 2; + + /* (int y, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_y = 1; + } else { + _y = -1; + } + + + /* (int z) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _has_y, _y, _z); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.13 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.13 new file mode 100644 index 00000000..e6879887 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.13 @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_int _args; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = (oc-1); + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[1]; + for (src = 1, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.14 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.14 new file mode 100644 index 00000000..f32000c9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.14 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_object +#define CRITCL_variadic_object + + typedef struct critcl_variadic_object { + int c; + Tcl_Obj* const* v; + } critcl_variadic_object; + +#endif /* CRITCL_variadic_object _________ */ + +static void c__aproc0(critcl_variadic_object args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_object _args; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + /* (object args, ...) - - -- --- ----- -------- */ + { + _args.c = (oc-1); + _args.v = &ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.15 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.15 new file mode 100644 index 00000000..f0ee9f3f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.15 @@ -0,0 +1,79 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int x, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _y; + critcl_variadic_int _args; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc < 3) { + Tcl_WrongNumArgs(interp, 1, ov, "x y ?args...?"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[2], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = (oc-3); + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[3]; + for (src = 3, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.16 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.16 new file mode 100644 index 00000000..4bfea16b --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.16 @@ -0,0 +1,94 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int has_x, int x, int has_y, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _has_y = 0; + int _y; + critcl_variadic_int _args; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_y = 1; + } else { + _y = -1; + } + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = argc_; + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[idx_]; + for (src = idx_, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _has_y, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.17 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.17 new file mode 100644 index 00000000..bb4c1efb --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.17 @@ -0,0 +1,92 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int x, int has_y, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _has_y = 0; + int _y; + critcl_variadic_int _args; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc < 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x ?y? ?args...?"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + idx_ = 2; + argc_ = oc - 2; + + /* (int y, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_y = 1; + } else { + _y = -1; + } + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = argc_; + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[idx_]; + for (src = idx_, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _has_y, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.18 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.18 new file mode 100644 index 00000000..1bdeafcb --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.18 @@ -0,0 +1,95 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int has_x, int x, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _y; + critcl_variadic_int _args; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc < 2) { + Tcl_WrongNumArgs(interp, 1, ov, "?x? y ?args...?"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 2) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + idx_++; + argc_--; + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = argc_; + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[idx_]; + for (src = idx_, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.2 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.2 new file mode 100644 index 00000000..82cb8dc7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.2 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc_beta0 "::aproc+beta" +static void c__aproc_beta0() +{ + +} + +static int +tcl__aproc_beta0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args (ns__aproc_beta0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c__aproc_beta0(); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.3 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.3 new file mode 100644 index 00000000..2994b8c1 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.3 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +static void c_snafu() +{ + +} + +static int +snafu(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args ("snafu", oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c_snafu(); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.4 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.4 new file mode 100644 index 00000000..d1852734 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.4 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(ClientData clientdata) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(cd); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.5 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.5 new file mode 100644 index 00000000..dc97e723 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.5 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 4) { + Tcl_WrongNumArgs(interp, 4, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.6 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.6 new file mode 100644 index 00000000..5ac0ecf9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.6 @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int anargument) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _anargument; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "anargument"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int anargument) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_anargument) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_anargument); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.7 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.7 new file mode 100644 index 00000000..8263bd9f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.7 @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int has_anargument, int anargument) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_anargument = 0; + int _anargument; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if ((oc < 1) || (2 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "?anargument?"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int anargument, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 0) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_anargument) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + _has_anargument = 1; + } else { + _anargument = -1; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_anargument, _anargument); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.8 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.8 new file mode 100644 index 00000000..b952d9ff --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.8 @@ -0,0 +1,64 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int has_x, int x, int y, int has_z, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _y; + int _has_z = 0; + int _z; + int idx_; + int argc_; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if ((oc < 2) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "?x? y ?z?"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + idx_++; + argc_--; + + + /* (int z, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 0) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + _has_z = 1; + } else { + _z = -1; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _y, _has_z, _z); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/2.9 b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.9 new file mode 100644 index 00000000..075c79b8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/2.9 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (int return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.0 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.0 new file mode 100644 index 00000000..8b0424f7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.0 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.1 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.1 new file mode 100644 index 00000000..944150dc --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.1 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return TCL_OK; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (ok return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (rv, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.10 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.10 new file mode 100644 index 00000000..f167497a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.10 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static char* c__aproc0() +{ +return alloc_string("bar"); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + char* rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (dstring return) - - -- --- ----- -------- */ + Tcl_SetResult (interp, rv, TCL_DYNAMIC); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.11 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.11 new file mode 100644 index 00000000..29d8d38b --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.11 @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Obj* c__aproc0() +{ +return Tcl_NewIntObj(0); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Obj* rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (object return) - - -- --- ----- -------- */ + if (rv == NULL) { return critcl_trace_cmd_result (TCL_ERROR, interp); } + Tcl_SetObjResult(interp, rv); + Tcl_DecrRefCount(rv); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.12 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.12 new file mode 100644 index 00000000..9649549b --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.12 @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Channel c__aproc0() +{ +return Tcl_OpenFileChannel (interp, "/tmp", "r", 0); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (new-channel return) - - -- --- ----- -------- */ + if (rv == NULL) { return critcl_trace_cmd_result (TCL_ERROR, interp); } + Tcl_RegisterChannel (interp, rv); + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.13 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.13 new file mode 100644 index 00000000..141f6220 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.13 @@ -0,0 +1,27 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Channel c__aproc0() +{ +return Tcl_GetStdChannel (0); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (known-channel return) - - -- --- ----- -------- */ + if (rv == NULL) { return critcl_trace_cmd_result (TCL_ERROR, interp); } + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.14 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.14 new file mode 100644 index 00000000..70f12497 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.14 @@ -0,0 +1,29 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Channel c__aproc0() +{ +return 0; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (return-channel return) - - -- --- ----- -------- */ + if (rv == NULL) { return critcl_trace_cmd_result (TCL_ERROR, interp); } + Tcl_RegisterChannel (interp, rv); + Tcl_UnregisterChannel(NULL, rv); + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.2 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.2 new file mode 100644 index 00000000..52c67ff1 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.2 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return 0; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (int return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.3 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.3 new file mode 100644 index 00000000..3fecc52a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.3 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.4 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.4 new file mode 100644 index 00000000..a3be87c1 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.4 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (boolean return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.5 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.5 new file mode 100644 index 00000000..a6b0bede --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.5 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static long c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + long rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (long return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewLongObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.6 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.6 new file mode 100644 index 00000000..1b837558 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.6 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_WideInt c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_WideInt rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (wideint return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.7 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.7 new file mode 100644 index 00000000..03cff08a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.7 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static double c__aproc0() +{ +return 0.; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + double rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (double return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.8 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.8 new file mode 100644 index 00000000..9ca60720 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.8 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static float c__aproc0() +{ +return 0.; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + float rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (float return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rv)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/3.9 b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.9 new file mode 100644 index 00000000..c0b660e8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/3.9 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static char* c__aproc0() +{ +return "foo"; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + char* rv; + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (vstring return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewStringObj(rv, -1)); + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.0-int b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.0-int new file mode 100644 index 00000000..a6af880c --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.0-int @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.1-bool b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.1-bool new file mode 100644 index 00000000..72d53b7b --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.1-bool @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (bool x) - - -- --- ----- -------- */ + { + if (Tcl_GetBooleanFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.10-object b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.10-object new file mode 100644 index 00000000..0ea50c92 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.10-object @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Obj* x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Obj* _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (object x) - - -- --- ----- -------- */ + { + _x = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.12-bytes b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.12-bytes new file mode 100644 index 00000000..a70d3761 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.12-bytes @@ -0,0 +1,44 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_bytes +#define CRITCL_bytes + + typedef struct critcl_bytes { + Tcl_Obj* o; + const unsigned char* s; + Tcl_Size len; + } critcl_bytes; + +#endif /* CRITCL_bytes _________ */ + +static void c__aproc0(critcl_bytes x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_bytes _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (bytes x) - - -- --- ----- -------- */ + { + /* Raw binary string _with_ length information */ + _x.s = Tcl_GetBytesFromObj(interp, ov[1], &(_x.len)); + if (_x.s == NULL) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.13-channel b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.13-channel new file mode 100644 index 00000000..aca9eab2 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.13-channel @@ -0,0 +1,32 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Channel x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (channel x) - - -- --- ----- -------- */ + { + int mode; + _x = Tcl_GetChannel(interp, Tcl_GetString (ov[1]), &mode); + if (_x == NULL) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.14-unshared-channel b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.14-unshared-channel new file mode 100644 index 00000000..ada00a56 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.14-unshared-channel @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Channel x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (unshared-channel x) - - -- --- ----- -------- */ + { + int mode; + _x = Tcl_GetChannel(interp, Tcl_GetString (ov[1]), &mode); + if (_x == NULL) return critcl_trace_cmd_result (TCL_ERROR, interp); + if (Tcl_IsChannelShared (_x)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("channel is shared", -1)); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.15-take-channel b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.15-take-channel new file mode 100644 index 00000000..f45fa106 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.15-take-channel @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Channel x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (take-channel x) - - -- --- ----- -------- */ + { + int mode; + _x = Tcl_GetChannel(interp, Tcl_GetString (ov[1]), &mode); + if (_x == NULL) return critcl_trace_cmd_result (TCL_ERROR, interp); + if (Tcl_IsChannelShared (_x)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("channel is shared", -1)); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + { + /* Disable event processing for the channel, both by + * removing any registered handler, and forcing interest + * to none. This also disables the processing of pending + * events which are ready to fire for the given + * channel. If we do not do this, events will hit the + * detached channel and potentially wreck havoc on our + * memory and eventually badly hurt us... + */ + Tcl_DriverWatchProc *watchProc; + Tcl_ClearChannelHandlers(_x); + watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(_x)); + if (watchProc) { + (*watchProc)(Tcl_GetChannelInstanceData(_x), 0); + } + /* Next some fiddling with the reference count to prevent + * the unregistration from killing it. We basically record + * it as globally known before removing it from the + * current interpreter + */ + Tcl_RegisterChannel((Tcl_Interp *) NULL, _x); + Tcl_UnregisterChannel(interp, _x); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.16-vobject b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.16-vobject new file mode 100644 index 00000000..f32000c9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.16-vobject @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_object +#define CRITCL_variadic_object + + typedef struct critcl_variadic_object { + int c; + Tcl_Obj* const* v; + } critcl_variadic_object; + +#endif /* CRITCL_variadic_object _________ */ + +static void c__aproc0(critcl_variadic_object args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_object _args; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + /* (object args, ...) - - -- --- ----- -------- */ + { + _args.c = (oc-1); + _args.v = &ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.17-vint b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.17-vint new file mode 100644 index 00000000..e6879887 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.17-vint @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_int _args; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = (oc-1); + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[1]; + for (src = 1, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.2-long b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.2-long new file mode 100644 index 00000000..5c345a0e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.2-long @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(long x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + long _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (long x) - - -- --- ----- -------- */ + { + if (Tcl_GetLongFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.3-wideint b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.3-wideint new file mode 100644 index 00000000..dc7c6489 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.3-wideint @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_WideInt x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_WideInt _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (wideint x) - - -- --- ----- -------- */ + { + if (Tcl_GetWideIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.4-double b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.4-double new file mode 100644 index 00000000..a29dd23c --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.4-double @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(double x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + double _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (double x) - - -- --- ----- -------- */ + { + if (Tcl_GetDoubleFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.5-float b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.5-float new file mode 100644 index 00000000..e9c6cbd5 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.5-float @@ -0,0 +1,32 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(float x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + float _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (float x) - - -- --- ----- -------- */ + { + double t; + if (Tcl_GetDoubleFromObj(interp, ov[1], &t) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x = (float) t; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.6-int_gt_0 b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.6-int_gt_0 new file mode 100644 index 00000000..16aadd69 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.6-int_gt_0 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int > 0 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x > 0) */ + if (!(_x > 0)) { + Tcl_AppendResult (interp, "expected int > 0, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.7-char_ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.7-char_ new file mode 100644 index 00000000..277b5d0d --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.7-char_ @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(const char* x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + const char* _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (char* x) - - -- --- ----- -------- */ + { + _x = Tcl_GetString(ov[1]); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.8-pstring b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.8-pstring new file mode 100644 index 00000000..6c8d00b2 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.8-pstring @@ -0,0 +1,42 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_pstring +#define CRITCL_pstring + + typedef struct critcl_pstring { + Tcl_Obj* o; + const char* s; + Tcl_Size len; + } critcl_pstring; + +#endif /* CRITCL_pstring _________ */ + +static void c__aproc0(critcl_pstring x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_pstring _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (pstring x) - - -- --- ----- -------- */ + { + _x.s = Tcl_GetStringFromObj(ov[1], &(_x.len)); + _x.o = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/4.9-list b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.9-list new file mode 100644 index 00000000..30132bb8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/4.9-list @@ -0,0 +1,43 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list +#define CRITCL_list + + typedef struct critcl_list { + Tcl_Obj* o; + Tcl_Obj* const* v; + Tcl_Size c; + } critcl_list; + +#endif /* CRITCL_list _________ */ + +static void c__aproc0(critcl_list x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list x) - - -- --- ----- -------- */ + { + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), (Tcl_Obj***) &(_x.v)) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/5.x b/src/vfs/critcl.vfs/test/assets/cproc-trace/5.x new file mode 100644 index 00000000..6fdc038f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/5.x @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x, int y) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _y; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 3) { + Tcl_WrongNumArgs(interp, 1, ov, "x y"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[2], &_y) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _y); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.0-int_gt_4 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.0-int_gt_4 new file mode 100644 index 00000000..806ae43e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.0-int_gt_4 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int > 4 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x > 4) */ + if (!(_x > 4)) { + Tcl_AppendResult (interp, "expected int > 4, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.1-int_gt_4_le_8 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.1-int_gt_4_le_8 new file mode 100644 index 00000000..7c9ba4d7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.1-int_gt_4_le_8 @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int > 4 <= 8 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x > 4) */ + if (!(_x > 4)) { + Tcl_AppendResult (interp, "expected int > 4 <= 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + /* Range check, assert (x <= 8) */ + if (!(_x <= 8)) { + Tcl_AppendResult (interp, "expected int > 4 <= 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.10-int== b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.10-int== new file mode 100644 index 00000000..0e2ad02f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.10-int== @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list_int_any x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; + + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_any x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.11-int=2= b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.11-int=2= new file mode 100644 index 00000000..b4e13af9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.11-int=2= @@ -0,0 +1,74 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list_int_2 x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; + + /* Size check, assert (length (list) == 2) */ + if (_x.c != 2) { + Tcl_AppendResult (interp, "Expected a list of 2", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_2 x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.2-int_lt_8 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.2-int_lt_8 new file mode 100644 index 00000000..1a3e6cc6 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.2-int_lt_8 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int < 8 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x < 8) */ + if (!(_x < 8)) { + Tcl_AppendResult (interp, "expected int < 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.3-int_lt_8_ge_4 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.3-int_lt_8_ge_4 new file mode 100644 index 00000000..fa1259dd --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.3-int_lt_8_ge_4 @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int >= 4 < 8 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x >= 4) */ + if (!(_x >= 4)) { + Tcl_AppendResult (interp, "expected int >= 4 < 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + /* Range check, assert (x < 8) */ + if (!(_x < 8)) { + Tcl_AppendResult (interp, "expected int >= 4 < 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.4-int_gt_2_ge_4 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.4-int_gt_2_ge_4 new file mode 100644 index 00000000..9fddf371 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.4-int_gt_2_ge_4 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int >= 4 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x >= 4) */ + if (!(_x >= 4)) { + Tcl_AppendResult (interp, "expected int >= 4, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.5-int_lt_2_lt_4_lt_6 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.5-int_lt_2_lt_4_lt_6 new file mode 100644 index 00000000..eb1e13ea --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.5-int_lt_2_lt_4_lt_6 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int < 2 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x < 2) */ + if (!(_x < 2)) { + Tcl_AppendResult (interp, "expected int < 2, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.6-int_lt_2_le_4 b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.6-int_lt_2_le_4 new file mode 100644 index 00000000..eb1e13ea --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.6-int_lt_2_le_4 @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (int < 2 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); } + /* Range check, assert (x < 2) */ + if (!(_x < 2)) { + Tcl_AppendResult (interp, "expected int < 2, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.7-=2= b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.7-=2= new file mode 100644 index 00000000..fe527e29 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.7-=2= @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_obj_2 +#define CRITCL_list_obj_2 +#ifndef CRITCL_list +#define CRITCL_list + + typedef struct critcl_list { + Tcl_Obj* o; + Tcl_Obj* const* v; + Tcl_Size c; + } critcl_list; + +#endif /* CRITCL_list _________ */ + +#endif /* CRITCL_list_obj_2 _________ */ + +static void c__aproc0(critcl_list x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list_obj_2 x) - - -- --- ----- -------- */ + { + { + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), (Tcl_Obj***) &(_x.v)) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; } + /* Size check, assert (length (list) == 2) */ + if (_x.c != 2) { + Tcl_AppendResult (interp, "Expected a list of 2", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.8-==int b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.8-==int new file mode 100644 index 00000000..0e2ad02f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.8-==int @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list_int_any x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; + + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_any x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/6.9-=2=int b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.9-=2=int new file mode 100644 index 00000000..b4e13af9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/6.9-=2=int @@ -0,0 +1,74 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list_int_2 x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _x.o = ov[1]; + + /* Size check, assert (length (list) == 2) */ + if (_x.c != 2) { + Tcl_AppendResult (interp, "Expected a list of 2", NULL); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_2 x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc-trace/7.0 b/src/vfs/critcl.vfs/test/assets/cproc-trace/7.0 new file mode 100644 index 00000000..59790cc6 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc-trace/7.0 @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int a) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _a; + + critcl_trace_cmd_args (ns__aproc0, oc, ov); + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "a"); + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + + /* (list_int_any a) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_a.c), &el) != TCL_OK) return critcl_trace_cmd_result (TCL_ERROR, interp); + _a.o = ov[1]; + + _a.v = (int*) ((!_a.c) ? 0 : ckalloc (_a.c * sizeof (int))); + for (k = 0; k < _a.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_a.v[k])) != TCL_OK) { + ckfree ((char*) _a.v); /* Cleanup partial work */ + return critcl_trace_cmd_result (TCL_ERROR, interp); + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_a); + + /* (Release: list_int_any a) - - -- --- ----- -------- */ + if (_a.c) { ckfree ((char*) _a.v); } + + /* (void return) - - -- --- ----- -------- */ + return critcl_trace_cmd_result (TCL_OK, interp); +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.0 b/src/vfs/critcl.vfs/test/assets/cproc/2.0 new file mode 100644 index 00000000..450a60de --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.0 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.1 b/src/vfs/critcl.vfs/test/assets/cproc/2.1 new file mode 100644 index 00000000..5008aecd --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.1 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__the_aproc0 "::the::aproc" +static void c__the_aproc0() +{ + +} + +static int +tcl__the_aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c__the_aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.10 b/src/vfs/critcl.vfs/test/assets/cproc/2.10 new file mode 100644 index 00000000..b0c5e777 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.10 @@ -0,0 +1,57 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int has_x, int x, int y, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _y; + int _z; + int idx_; + int argc_; + + if ((oc < 3) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "?x? y z"); + return TCL_ERROR; + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 2) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return TCL_ERROR; } + + idx_++; + argc_--; + + + /* (int z) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return TCL_ERROR; } + + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _y, _z); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.11 b/src/vfs/critcl.vfs/test/assets/cproc/2.11 new file mode 100644 index 00000000..69dd018c --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.11 @@ -0,0 +1,51 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x, int y, int has_z, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _y; + int _has_z = 0; + int _z; + int idx_; + int argc_; + + if ((oc < 3) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "x y ?z?"); + return TCL_ERROR; + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[2], &_y) != TCL_OK) return TCL_ERROR; } + + + idx_ = 3; + argc_ = oc - 3; + + /* (int z, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 0) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return TCL_ERROR; } + _has_z = 1; + } else { + _z = -1; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _y, _has_z, _z); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.12 b/src/vfs/critcl.vfs/test/assets/cproc/2.12 new file mode 100644 index 00000000..b2cf4ca8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.12 @@ -0,0 +1,54 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x, int has_y, int y, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _has_y = 0; + int _y; + int _z; + int idx_; + int argc_; + + if ((oc < 3) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "x ?y? z"); + return TCL_ERROR; + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + + idx_ = 2; + argc_ = oc - 2; + + /* (int y, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_y = 1; + } else { + _y = -1; + } + + + /* (int z) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return TCL_ERROR; } + + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _has_y, _y, _z); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.13 b/src/vfs/critcl.vfs/test/assets/cproc/2.13 new file mode 100644 index 00000000..11002abf --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.13 @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_int _args; + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = (oc-1); + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[1]; + for (src = 1, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.14 b/src/vfs/critcl.vfs/test/assets/cproc/2.14 new file mode 100644 index 00000000..cd774177 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.14 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_object +#define CRITCL_variadic_object + + typedef struct critcl_variadic_object { + int c; + Tcl_Obj* const* v; + } critcl_variadic_object; + +#endif /* CRITCL_variadic_object _________ */ + +static void c__aproc0(critcl_variadic_object args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_object _args; + /* (object args, ...) - - -- --- ----- -------- */ + { + _args.c = (oc-1); + _args.v = &ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.15 b/src/vfs/critcl.vfs/test/assets/cproc/2.15 new file mode 100644 index 00000000..bca5def4 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.15 @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int x, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _y; + critcl_variadic_int _args; + + if (oc < 3) { + Tcl_WrongNumArgs(interp, 1, ov, "x y ?args...?"); + return TCL_ERROR; + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[2], &_y) != TCL_OK) return TCL_ERROR; } + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = (oc-3); + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[3]; + for (src = 3, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.16 b/src/vfs/critcl.vfs/test/assets/cproc/2.16 new file mode 100644 index 00000000..06cbbf62 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.16 @@ -0,0 +1,92 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int has_x, int x, int has_y, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _has_y = 0; + int _y; + critcl_variadic_int _args; + int idx_; + int argc_; + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_y = 1; + } else { + _y = -1; + } + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = argc_; + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[idx_]; + for (src = idx_, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _has_y, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.17 b/src/vfs/critcl.vfs/test/assets/cproc/2.17 new file mode 100644 index 00000000..2a1bc289 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.17 @@ -0,0 +1,90 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int x, int has_y, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _has_y = 0; + int _y; + critcl_variadic_int _args; + int idx_; + int argc_; + + if (oc < 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x ?y? ?args...?"); + return TCL_ERROR; + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + + idx_ = 2; + argc_ = oc - 2; + + /* (int y, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_y = 1; + } else { + _y = -1; + } + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = argc_; + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[idx_]; + for (src = idx_, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _has_y, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.18 b/src/vfs/critcl.vfs/test/assets/cproc/2.18 new file mode 100644 index 00000000..244352ec --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.18 @@ -0,0 +1,93 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(int has_x, int x, int y, critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _y; + critcl_variadic_int _args; + int idx_; + int argc_; + + if (oc < 2) { + Tcl_WrongNumArgs(interp, 1, ov, "?x? y ?args...?"); + return TCL_ERROR; + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 2) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return TCL_ERROR; } + + idx_++; + argc_--; + + + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = argc_; + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[idx_]; + for (src = idx_, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _y, _args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.2 b/src/vfs/critcl.vfs/test/assets/cproc/2.2 new file mode 100644 index 00000000..197ca330 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.2 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc_beta0 "::aproc+beta" +static void c__aproc_beta0() +{ + +} + +static int +tcl__aproc_beta0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c__aproc_beta0(); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.3 b/src/vfs/critcl.vfs/test/assets/cproc/2.3 new file mode 100644 index 00000000..68defb12 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.3 @@ -0,0 +1,22 @@ +/* ---------------------------------------------------------------------- */ + +static void c_snafu() +{ + +} + +static int +snafu(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c_snafu(); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.4 b/src/vfs/critcl.vfs/test/assets/cproc/2.4 new file mode 100644 index 00000000..d909b478 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.4 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(ClientData clientdata) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(cd); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.5 b/src/vfs/critcl.vfs/test/assets/cproc/2.5 new file mode 100644 index 00000000..02f0f49b --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.5 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 4) { + Tcl_WrongNumArgs(interp, 4, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.6 b/src/vfs/critcl.vfs/test/assets/cproc/2.6 new file mode 100644 index 00000000..13c61ae9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.6 @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int anargument) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _anargument; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "anargument"); + return TCL_ERROR; + } + + /* (int anargument) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_anargument) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_anargument); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.7 b/src/vfs/critcl.vfs/test/assets/cproc/2.7 new file mode 100644 index 00000000..efdb5ab9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.7 @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int has_anargument, int anargument) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_anargument = 0; + int _anargument; + int idx_; + int argc_; + + if ((oc < 1) || (2 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "?anargument?"); + return TCL_ERROR; + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int anargument, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 0) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_anargument) != TCL_OK) return TCL_ERROR; } + _has_anargument = 1; + } else { + _anargument = -1; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_anargument, _anargument); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.8 b/src/vfs/critcl.vfs/test/assets/cproc/2.8 new file mode 100644 index 00000000..b3f644ca --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.8 @@ -0,0 +1,62 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int has_x, int x, int y, int has_z, int z) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _has_x = 0; + int _x; + int _y; + int _has_z = 0; + int _z; + int idx_; + int argc_; + + if ((oc < 2) || (4 < oc)) { + Tcl_WrongNumArgs(interp, 1, ov, "?x? y ?z?"); + return TCL_ERROR; + } + + idx_ = 1; + argc_ = oc - 1; + + /* (int x, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 1) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_x) != TCL_OK) return TCL_ERROR; } + idx_++; + argc_--; + _has_x = 1; + } else { + _x = -1; + } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_y) != TCL_OK) return TCL_ERROR; } + + idx_++; + argc_--; + + + /* (int z, optional, default -1) - - -- --- ----- -------- */ + if (argc_ > 0) { + { + if (Tcl_GetIntFromObj(interp, ov[idx_], &_z) != TCL_OK) return TCL_ERROR; } + _has_z = 1; + } else { + _z = -1; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_has_x, _x, _y, _has_z, _z); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/2.9 b/src/vfs/critcl.vfs/test/assets/cproc/2.9 new file mode 100644 index 00000000..cd0db2ff --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/2.9 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (int return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.0 b/src/vfs/critcl.vfs/test/assets/cproc/3.0 new file mode 100644 index 00000000..450a60de --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.0 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0() +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + c__aproc0(); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.1 b/src/vfs/critcl.vfs/test/assets/cproc/3.1 new file mode 100644 index 00000000..931b5ecf --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.1 @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return TCL_OK; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (ok return) - - -- --- ----- -------- */ + return rv; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.10 b/src/vfs/critcl.vfs/test/assets/cproc/3.10 new file mode 100644 index 00000000..e450477e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.10 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static char* c__aproc0() +{ +return alloc_string("bar"); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + char* rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (dstring return) - - -- --- ----- -------- */ + Tcl_SetResult (interp, rv, TCL_DYNAMIC); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.11 b/src/vfs/critcl.vfs/test/assets/cproc/3.11 new file mode 100644 index 00000000..57f122e4 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.11 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Obj* c__aproc0() +{ +return Tcl_NewIntObj(0); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Obj* rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (object return) - - -- --- ----- -------- */ + if (rv == NULL) { return TCL_ERROR; } + Tcl_SetObjResult(interp, rv); + Tcl_DecrRefCount(rv); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.12 b/src/vfs/critcl.vfs/test/assets/cproc/3.12 new file mode 100644 index 00000000..f34279ce --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.12 @@ -0,0 +1,26 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Channel c__aproc0() +{ +return Tcl_OpenFileChannel (interp, "/tmp", "r", 0); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (new-channel return) - - -- --- ----- -------- */ + if (rv == NULL) { return TCL_ERROR; } + Tcl_RegisterChannel (interp, rv); + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.13 b/src/vfs/critcl.vfs/test/assets/cproc/3.13 new file mode 100644 index 00000000..4ddb6e46 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.13 @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Channel c__aproc0() +{ +return Tcl_GetStdChannel (0); +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (known-channel return) - - -- --- ----- -------- */ + if (rv == NULL) { return TCL_ERROR; } + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.14 b/src/vfs/critcl.vfs/test/assets/cproc/3.14 new file mode 100644 index 00000000..b208d516 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.14 @@ -0,0 +1,27 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_Channel c__aproc0() +{ +return 0; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (return-channel return) - - -- --- ----- -------- */ + if (rv == NULL) { return TCL_ERROR; } + Tcl_RegisterChannel (interp, rv); + Tcl_UnregisterChannel(NULL, rv); + Tcl_SetObjResult (interp, Tcl_NewStringObj (Tcl_GetChannelName (rv), -1)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.2 b/src/vfs/critcl.vfs/test/assets/cproc/3.2 new file mode 100644 index 00000000..b1d51444 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.2 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return 0; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (int return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.3 b/src/vfs/critcl.vfs/test/assets/cproc/3.3 new file mode 100644 index 00000000..aefbefd9 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.3 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (bool return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.4 b/src/vfs/critcl.vfs/test/assets/cproc/3.4 new file mode 100644 index 00000000..683fba95 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.4 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static int c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (boolean return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.5 b/src/vfs/critcl.vfs/test/assets/cproc/3.5 new file mode 100644 index 00000000..7c09887f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.5 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static long c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + long rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (long return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewLongObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.6 b/src/vfs/critcl.vfs/test/assets/cproc/3.6 new file mode 100644 index 00000000..18870d7e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.6 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static Tcl_WideInt c__aproc0() +{ +return 1; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_WideInt rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (wideint return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.7 b/src/vfs/critcl.vfs/test/assets/cproc/3.7 new file mode 100644 index 00000000..8d195a4e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.7 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static double c__aproc0() +{ +return 0.; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + double rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (double return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.8 b/src/vfs/critcl.vfs/test/assets/cproc/3.8 new file mode 100644 index 00000000..53df6d74 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.8 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static float c__aproc0() +{ +return 0.; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + float rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (float return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rv)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/3.9 b/src/vfs/critcl.vfs/test/assets/cproc/3.9 new file mode 100644 index 00000000..a30750f8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/3.9 @@ -0,0 +1,24 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static char* c__aproc0() +{ +return "foo"; +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + char* rv; + if (oc != 1) { + Tcl_WrongNumArgs(interp, 1, ov, NULL); + return TCL_ERROR; + } + + /* Call - - -- --- ----- -------- */ + rv = c__aproc0(); + + /* (vstring return) - - -- --- ----- -------- */ + Tcl_SetObjResult(interp, Tcl_NewStringObj(rv, -1)); + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.0-int b/src/vfs/critcl.vfs/test/assets/cproc/4.0-int new file mode 100644 index 00000000..59c5c18a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.0-int @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.1-bool b/src/vfs/critcl.vfs/test/assets/cproc/4.1-bool new file mode 100644 index 00000000..52b3782a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.1-bool @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (bool x) - - -- --- ----- -------- */ + { + if (Tcl_GetBooleanFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.10-object b/src/vfs/critcl.vfs/test/assets/cproc/4.10-object new file mode 100644 index 00000000..9f48f57a --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.10-object @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Obj* x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Obj* _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (object x) - - -- --- ----- -------- */ + { + _x = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.12-bytes b/src/vfs/critcl.vfs/test/assets/cproc/4.12-bytes new file mode 100644 index 00000000..7345802e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.12-bytes @@ -0,0 +1,42 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_bytes +#define CRITCL_bytes + + typedef struct critcl_bytes { + Tcl_Obj* o; + const unsigned char* s; + Tcl_Size len; + } critcl_bytes; + +#endif /* CRITCL_bytes _________ */ + +static void c__aproc0(critcl_bytes x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_bytes _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (bytes x) - - -- --- ----- -------- */ + { + /* Raw binary string _with_ length information */ + _x.s = Tcl_GetBytesFromObj(interp, ov[1], &(_x.len)); + if (_x.s == NULL) return TCL_ERROR; + _x.o = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.13-channel b/src/vfs/critcl.vfs/test/assets/cproc/4.13-channel new file mode 100644 index 00000000..48291f59 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.13-channel @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Channel x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (channel x) - - -- --- ----- -------- */ + { + int mode; + _x = Tcl_GetChannel(interp, Tcl_GetString (ov[1]), &mode); + if (_x == NULL) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.14-unshared-channel b/src/vfs/critcl.vfs/test/assets/cproc/4.14-unshared-channel new file mode 100644 index 00000000..d3ad2179 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.14-unshared-channel @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Channel x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (unshared-channel x) - - -- --- ----- -------- */ + { + int mode; + _x = Tcl_GetChannel(interp, Tcl_GetString (ov[1]), &mode); + if (_x == NULL) return TCL_ERROR; + if (Tcl_IsChannelShared (_x)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("channel is shared", -1)); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.15-take-channel b/src/vfs/critcl.vfs/test/assets/cproc/4.15-take-channel new file mode 100644 index 00000000..b27de153 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.15-take-channel @@ -0,0 +1,57 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_Channel x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_Channel _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (take-channel x) - - -- --- ----- -------- */ + { + int mode; + _x = Tcl_GetChannel(interp, Tcl_GetString (ov[1]), &mode); + if (_x == NULL) return TCL_ERROR; + if (Tcl_IsChannelShared (_x)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("channel is shared", -1)); + return TCL_ERROR; + } + { + /* Disable event processing for the channel, both by + * removing any registered handler, and forcing interest + * to none. This also disables the processing of pending + * events which are ready to fire for the given + * channel. If we do not do this, events will hit the + * detached channel and potentially wreck havoc on our + * memory and eventually badly hurt us... + */ + Tcl_DriverWatchProc *watchProc; + Tcl_ClearChannelHandlers(_x); + watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(_x)); + if (watchProc) { + (*watchProc)(Tcl_GetChannelInstanceData(_x), 0); + } + /* Next some fiddling with the reference count to prevent + * the unregistration from killing it. We basically record + * it as globally known before removing it from the + * current interpreter + */ + Tcl_RegisterChannel((Tcl_Interp *) NULL, _x); + Tcl_UnregisterChannel(interp, _x); + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.16-vobject b/src/vfs/critcl.vfs/test/assets/cproc/4.16-vobject new file mode 100644 index 00000000..cd774177 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.16-vobject @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_object +#define CRITCL_variadic_object + + typedef struct critcl_variadic_object { + int c; + Tcl_Obj* const* v; + } critcl_variadic_object; + +#endif /* CRITCL_variadic_object _________ */ + +static void c__aproc0(critcl_variadic_object args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_object _args; + /* (object args, ...) - - -- --- ----- -------- */ + { + _args.c = (oc-1); + _args.v = &ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.17-vint b/src/vfs/critcl.vfs/test/assets/cproc/4.17-vint new file mode 100644 index 00000000..11002abf --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.17-vint @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" + +#ifndef CRITCL_variadic_int +#define CRITCL_variadic_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_variadic_int { + Tcl_Obj** o; /* Original object array */ + int c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_variadic_int; + + static int + _critcl_variadic_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_variadic_int _________ */ + +static void c__aproc0(critcl_variadic_int args) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_variadic_int _args; + /* (int args, ...) - - -- --- ----- -------- */ + { + int src, dst, leftovers = (oc-1); + _args.c = leftovers; + _args.v = (int*) ((!leftovers) ? 0 : ckalloc (leftovers * sizeof (int))); + _args.o = (Tcl_Obj**) &ov[1]; + for (src = 1, dst = 0; leftovers > 0; dst++, src++, leftovers--) { + if (_critcl_variadic_int_item (interp, ov[src], &(_args.v[dst])) != TCL_OK) { + ckfree ((char*) _args.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_args); + + /* (Release: int args, ...) - - -- --- ----- -------- */ + if (_args.c) { ckfree ((char*) _args.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.2-long b/src/vfs/critcl.vfs/test/assets/cproc/4.2-long new file mode 100644 index 00000000..f843876e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.2-long @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(long x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + long _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (long x) - - -- --- ----- -------- */ + { + if (Tcl_GetLongFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.3-wideint b/src/vfs/critcl.vfs/test/assets/cproc/4.3-wideint new file mode 100644 index 00000000..8e2ccaef --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.3-wideint @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(Tcl_WideInt x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + Tcl_WideInt _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (wideint x) - - -- --- ----- -------- */ + { + if (Tcl_GetWideIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.4-double b/src/vfs/critcl.vfs/test/assets/cproc/4.4-double new file mode 100644 index 00000000..bba66692 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.4-double @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(double x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + double _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (double x) - - -- --- ----- -------- */ + { + if (Tcl_GetDoubleFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.5-float b/src/vfs/critcl.vfs/test/assets/cproc/4.5-float new file mode 100644 index 00000000..cad74f80 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.5-float @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(float x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + float _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (float x) - - -- --- ----- -------- */ + { + double t; + if (Tcl_GetDoubleFromObj(interp, ov[1], &t) != TCL_OK) return TCL_ERROR; + _x = (float) t; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.6-int_gt_0 b/src/vfs/critcl.vfs/test/assets/cproc/4.6-int_gt_0 new file mode 100644 index 00000000..8d3b970b --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.6-int_gt_0 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int > 0 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x > 0) */ + if (!(_x > 0)) { + Tcl_AppendResult (interp, "expected int > 0, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.7-char_ b/src/vfs/critcl.vfs/test/assets/cproc/4.7-char_ new file mode 100644 index 00000000..e920757f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.7-char_ @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(const char* x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + const char* _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (char* x) - - -- --- ----- -------- */ + { + _x = Tcl_GetString(ov[1]); } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.8-pstring b/src/vfs/critcl.vfs/test/assets/cproc/4.8-pstring new file mode 100644 index 00000000..6b3cd324 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.8-pstring @@ -0,0 +1,40 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_pstring +#define CRITCL_pstring + + typedef struct critcl_pstring { + Tcl_Obj* o; + const char* s; + Tcl_Size len; + } critcl_pstring; + +#endif /* CRITCL_pstring _________ */ + +static void c__aproc0(critcl_pstring x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_pstring _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (pstring x) - - -- --- ----- -------- */ + { + _x.s = Tcl_GetStringFromObj(ov[1], &(_x.len)); + _x.o = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/4.9-list b/src/vfs/critcl.vfs/test/assets/cproc/4.9-list new file mode 100644 index 00000000..64fd346d --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/4.9-list @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list +#define CRITCL_list + + typedef struct critcl_list { + Tcl_Obj* o; + Tcl_Obj* const* v; + Tcl_Size c; + } critcl_list; + +#endif /* CRITCL_list _________ */ + +static void c__aproc0(critcl_list x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (list x) - - -- --- ----- -------- */ + { + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), (Tcl_Obj***) &(_x.v)) != TCL_OK) return TCL_ERROR; + _x.o = ov[1]; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/5.x b/src/vfs/critcl.vfs/test/assets/cproc/5.x new file mode 100644 index 00000000..5801d4d5 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/5.x @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x, int y) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + int _y; + + if (oc != 3) { + Tcl_WrongNumArgs(interp, 1, ov, "x y"); + return TCL_ERROR; + } + + /* (int x) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + + + /* (int y) - - -- --- ----- -------- */ + { + if (Tcl_GetIntFromObj(interp, ov[2], &_y) != TCL_OK) return TCL_ERROR; } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x, _y); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.0-int_gt_4 b/src/vfs/critcl.vfs/test/assets/cproc/6.0-int_gt_4 new file mode 100644 index 00000000..7843641f --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.0-int_gt_4 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int > 4 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x > 4) */ + if (!(_x > 4)) { + Tcl_AppendResult (interp, "expected int > 4, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.1-int_gt_4_le_8 b/src/vfs/critcl.vfs/test/assets/cproc/6.1-int_gt_4_le_8 new file mode 100644 index 00000000..99a8c431 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.1-int_gt_4_le_8 @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int > 4 <= 8 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x > 4) */ + if (!(_x > 4)) { + Tcl_AppendResult (interp, "expected int > 4 <= 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } + /* Range check, assert (x <= 8) */ + if (!(_x <= 8)) { + Tcl_AppendResult (interp, "expected int > 4 <= 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.10-int== b/src/vfs/critcl.vfs/test/assets/cproc/6.10-int== new file mode 100644 index 00000000..c83e1510 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.10-int== @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (list_int_any x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return TCL_ERROR; + _x.o = ov[1]; + + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_any x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.11-int=2= b/src/vfs/critcl.vfs/test/assets/cproc/6.11-int=2= new file mode 100644 index 00000000..93fc9768 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.11-int=2= @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (list_int_2 x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return TCL_ERROR; + _x.o = ov[1]; + + /* Size check, assert (length (list) == 2) */ + if (_x.c != 2) { + Tcl_AppendResult (interp, "Expected a list of 2", NULL); + return TCL_ERROR; + } + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_2 x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.2-int_lt_8 b/src/vfs/critcl.vfs/test/assets/cproc/6.2-int_lt_8 new file mode 100644 index 00000000..918d611d --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.2-int_lt_8 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int < 8 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x < 8) */ + if (!(_x < 8)) { + Tcl_AppendResult (interp, "expected int < 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.3-int_lt_8_ge_4 b/src/vfs/critcl.vfs/test/assets/cproc/6.3-int_lt_8_ge_4 new file mode 100644 index 00000000..d68a9636 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.3-int_lt_8_ge_4 @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int >= 4 < 8 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x >= 4) */ + if (!(_x >= 4)) { + Tcl_AppendResult (interp, "expected int >= 4 < 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } + /* Range check, assert (x < 8) */ + if (!(_x < 8)) { + Tcl_AppendResult (interp, "expected int >= 4 < 8, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.4-int_gt_2_ge_4 b/src/vfs/critcl.vfs/test/assets/cproc/6.4-int_gt_2_ge_4 new file mode 100644 index 00000000..f2b267f5 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.4-int_gt_2_ge_4 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int >= 4 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x >= 4) */ + if (!(_x >= 4)) { + Tcl_AppendResult (interp, "expected int >= 4, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.5-int_lt_2_lt_4_lt_6 b/src/vfs/critcl.vfs/test/assets/cproc/6.5-int_lt_2_lt_4_lt_6 new file mode 100644 index 00000000..0ffb820e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.5-int_lt_2_lt_4_lt_6 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int < 2 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x < 2) */ + if (!(_x < 2)) { + Tcl_AppendResult (interp, "expected int < 2, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.6-int_lt_2_le_4 b/src/vfs/critcl.vfs/test/assets/cproc/6.6-int_lt_2_le_4 new file mode 100644 index 00000000..0ffb820e --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.6-int_lt_2_le_4 @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +static void c__aproc0(int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (int < 2 x) - - -- --- ----- -------- */ + { + { + if (Tcl_GetIntFromObj(interp, ov[1], &_x) != TCL_OK) return TCL_ERROR; } + /* Range check, assert (x < 2) */ + if (!(_x < 2)) { + Tcl_AppendResult (interp, "expected int < 2, but got \"", Tcl_GetString (ov[1]), "\"", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.7-=2= b/src/vfs/critcl.vfs/test/assets/cproc/6.7-=2= new file mode 100644 index 00000000..8e018cdd --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.7-=2= @@ -0,0 +1,51 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_obj_2 +#define CRITCL_list_obj_2 +#ifndef CRITCL_list +#define CRITCL_list + + typedef struct critcl_list { + Tcl_Obj* o; + Tcl_Obj* const* v; + Tcl_Size c; + } critcl_list; + +#endif /* CRITCL_list _________ */ + +#endif /* CRITCL_list_obj_2 _________ */ + +static void c__aproc0(critcl_list x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (list_obj_2 x) - - -- --- ----- -------- */ + { + { + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), (Tcl_Obj***) &(_x.v)) != TCL_OK) return TCL_ERROR; + _x.o = ov[1]; } + /* Size check, assert (length (list) == 2) */ + if (_x.c != 2) { + Tcl_AppendResult (interp, "Expected a list of 2", NULL); + return TCL_ERROR; + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.8-==int b/src/vfs/critcl.vfs/test/assets/cproc/6.8-==int new file mode 100644 index 00000000..c83e1510 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.8-==int @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (list_int_any x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return TCL_ERROR; + _x.o = ov[1]; + + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_any x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/6.9-=2=int b/src/vfs/critcl.vfs/test/assets/cproc/6.9-=2=int new file mode 100644 index 00000000..93fc9768 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/6.9-=2=int @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int x) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _x; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "x"); + return TCL_ERROR; + } + + /* (list_int_2 x) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_x.c), &el) != TCL_OK) return TCL_ERROR; + _x.o = ov[1]; + + /* Size check, assert (length (list) == 2) */ + if (_x.c != 2) { + Tcl_AppendResult (interp, "Expected a list of 2", NULL); + return TCL_ERROR; + } + _x.v = (int*) ((!_x.c) ? 0 : ckalloc (_x.c * sizeof (int))); + for (k = 0; k < _x.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_x.v[k])) != TCL_OK) { + ckfree ((char*) _x.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_x); + + /* (Release: list_int_2 x) - - -- --- ----- -------- */ + if (_x.c) { ckfree ((char*) _x.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/cproc/7.0 b/src/vfs/critcl.vfs/test/assets/cproc/7.0 new file mode 100644 index 00000000..b46f8b35 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/cproc/7.0 @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------- */ + +#define ns__aproc0 "::aproc" +#ifndef CRITCL_list_int +#define CRITCL_list_int + + /* NOTE: Array 'v' is allocated on the heap. The argument + // release code is used to free it after the worker + // function returned. Depending on type and what is done + // by the worker it may have to make copies of the data. + */ + + typedef struct critcl_list_int { + Tcl_Obj* o; /* Original list object, for pass-through cases */ + Tcl_Size c; /* Element count */ + int* v; /* Allocated array of the elements */ + } critcl_list_int; + + static int + _critcl_list_int_item (Tcl_Interp* interp, Tcl_Obj* src, int* dst) { + { + if (Tcl_GetIntFromObj(interp, src, dst) != TCL_OK) return TCL_ERROR; } + return TCL_OK; + } + +#endif /* CRITCL_list_int _________ */ + +static void c__aproc0(critcl_list_int a) +{ + +} + +static int +tcl__aproc0(ClientData cd, Tcl_Interp *interp, Tcl_Size oc, Tcl_Obj *CONST ov[]) +{ + critcl_list_int _a; + + if (oc != 2) { + Tcl_WrongNumArgs(interp, 1, ov, "a"); + return TCL_ERROR; + } + + /* (list_int_any a) - - -- --- ----- -------- */ + { + int k; + Tcl_Obj** el; + if (Tcl_ListObjGetElements (interp, ov[1], /* OK tcl9 */ + &(_a.c), &el) != TCL_OK) return TCL_ERROR; + _a.o = ov[1]; + + _a.v = (int*) ((!_a.c) ? 0 : ckalloc (_a.c * sizeof (int))); + for (k = 0; k < _a.c; k++) { + if (_critcl_list_int_item (interp, el[k], &(_a.v[k])) != TCL_OK) { + ckfree ((char*) _a.v); /* Cleanup partial work */ + return TCL_ERROR; + } + } } + + /* Call - - -- --- ----- -------- */ + c__aproc0(_a); + + /* (Release: list_int_any a) - - -- --- ----- -------- */ + if (_a.c) { ckfree ((char*) _a.v); } + + /* (void return) - - -- --- ----- -------- */ + return TCL_OK; +} diff --git a/src/vfs/critcl.vfs/test/assets/def-2.0 b/src/vfs/critcl.vfs/test/assets/def-2.0 new file mode 100644 index 00000000..03aefe72 --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/def-2.0 @@ -0,0 +1,2 @@ + +#define foo 333 diff --git a/src/vfs/critcl.vfs/test/assets/undef-2.0 b/src/vfs/critcl.vfs/test/assets/undef-2.0 new file mode 100644 index 00000000..7053c3ed --- /dev/null +++ b/src/vfs/critcl.vfs/test/assets/undef-2.0 @@ -0,0 +1,2 @@ + +#undef foo diff --git a/src/vfs/critcl.vfs/test/attic/basic.tcl b/src/vfs/critcl.vfs/test/attic/basic.tcl new file mode 100644 index 00000000..3e6f4ff6 --- /dev/null +++ b/src/vfs/critcl.vfs/test/attic/basic.tcl @@ -0,0 +1,12 @@ +package require critcl 3.2 + +critcl::cproc add {int x int y} int { + return x + y; +} + +critcl::cproc cube {int x} int { + return x * x * x; +} + +puts stderr "add 1 + 2 = [add 1 2]" +puts stderr "cube 2 = [cube 2]" diff --git a/src/vfs/critcl.vfs/test/attic/basic.tst b/src/vfs/critcl.vfs/test/attic/basic.tst new file mode 100644 index 00000000..5da405a5 --- /dev/null +++ b/src/vfs/critcl.vfs/test/attic/basic.tst @@ -0,0 +1,7 @@ +package require tcltest +namespace import tcltest::* + +test basic "Basic compile + go" -body { + puts stderr "exec = [info nameofexecutable]" + puts stderr "prog = $starkit::topdir" +} diff --git a/src/vfs/critcl.vfs/test/attic/c++direct-1.tcl b/src/vfs/critcl.vfs/test/attic/c++direct-1.tcl new file mode 100644 index 00000000..e75b4c9d --- /dev/null +++ b/src/vfs/critcl.vfs/test/attic/c++direct-1.tcl @@ -0,0 +1,70 @@ +package require critcl 3.2 + +critcl::config language c++ +critcl::clibraries -lstdc++ + +namespace eval testing { + critcl::ccode { + class Counter { + public: + Counter(int startValue=0); + Counter operator++(); + void set( int newValue); + void reset(); + int value() const; + private: + int count; + int resetValue; + }; + + Counter::Counter(int startValue) : count(startValue), + resetValue(startValue) {} + Counter Counter::operator++() { + count++; + } + + void Counter::set(int newValue) { + count=newValue; + } + + void Counter::reset() { + count=resetValue; + } + + int Counter::value() const { + return count; + } + } + + critcl::c++command counter Counter { {} {int start_value} } { + void set {int new_value} + void reset {} + void {incr operator++} {} + int value {} + } + +} + +if 1 { + testing::counter p 10 + puts "Initial Counter: [p value]" + p incr + p incr + p incr + puts "Counter after 3 increments: [p value]" + p set 20 + puts "Counter after set to 20: [p value]" + p reset + puts "Counter after reset: [p value]" + + testing::counter d + puts "Initial Counter: [d value]" + d incr + d incr + d incr + puts "Counter after 3 increments: [d value]" + d set 20 + puts "Counter after set to 20: [d value]" + d reset + puts "Counter after reset: [d value]" +} diff --git a/src/vfs/critcl.vfs/test/attic/c++direct-2.tcl b/src/vfs/critcl.vfs/test/attic/c++direct-2.tcl new file mode 100644 index 00000000..6de83745 --- /dev/null +++ b/src/vfs/critcl.vfs/test/attic/c++direct-2.tcl @@ -0,0 +1,29 @@ +package require critcl 3.2 + +critcl::config language c++ +critcl::clibraries -lstdc++ + +critcl::ccode { + class A { + int val; + public: + A() : val (123) {} + int value() const { return val; } + operator int() { return val; } + int operator |(int o) { return val|o; } + int operator &(int o) { return val&o; } + }; +} + +critcl::c++command tst A {} { + int value {} + int {int {operator int}} {} + int {or {operator |}} {int} + int {and {operator &}} {int} +} + +tst A +puts "tst = [A value]" +puts "tst = [A int]" +puts "tst = [A or 0xf]" +puts "tst = [A and 0xf]" diff --git a/src/vfs/critcl.vfs/test/attic/c++indirect.tcl b/src/vfs/critcl.vfs/test/attic/c++indirect.tcl new file mode 100644 index 00000000..4135b90b --- /dev/null +++ b/src/vfs/critcl.vfs/test/attic/c++indirect.tcl @@ -0,0 +1,20 @@ +package require critcl 3.2 + +critcl::config language c++ +critcl::clibraries -lstdc++ + +critcl::ccode { + class A { + int value; + public: + A() : value (123) {} + operator int() const { return value; } + }; +} + +critcl::cproc tryplus {} int { + A var; + return var; +} + +puts "tryplus = [tryplus]" diff --git a/src/vfs/critcl.vfs/test/attic/fbasic.tcl b/src/vfs/critcl.vfs/test/attic/fbasic.tcl new file mode 100644 index 00000000..209d8720 --- /dev/null +++ b/src/vfs/critcl.vfs/test/attic/fbasic.tcl @@ -0,0 +1 @@ +# Basic test for Critclf diff --git a/src/vfs/critcl.vfs/test/bitmap.test b/src/vfs/critcl.vfs/test/bitmap.test new file mode 100644 index 00000000..6c1f2667 --- /dev/null +++ b/src/vfs/critcl.vfs/test/bitmap.test @@ -0,0 +1,69 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# bitmap.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + useLocal lib/critcl/critcl.tcl critcl + useLocal lib/critcl-iassoc/iassoc.tcl critcl::iassoc + + localcache-setup +} +testing { + useLocal lib/critcl-bitmap/bitmap.tcl critcl::bitmap +} + +# ------------------------------------------------------------------------- +## + +test bitmap-mode-tcl-1.0 {critcl-bitmap} -setup { + make-demo TL { + critcl::bitmap::def demo { + global 1 + exact 2 + filler 4 + } + + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* flags} int { + int mask; + demo_encode (ip, flags, &mask); + return mask; + } + critcl::cproc decode {Tcl_Interp* ip int mask} object { + Tcl_Obj* res = demo_decode (ip, mask); + Tcl_IncrRefCount (res); + return res; + } + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo flags} int { + return flags; + } + # Decode hidden in the resultype + critcl::cproc xdecode {Tcl_Interp* ip int mask} demo { + return mask; + } + } +} -body { + res! + res+ [encode {exact filler}] + res+ [lsort -dict [decode 5]] + res+ [xencode global] + res+ [lsort -dict [xdecode 6]] + res? +} -result {6 {{filler global}} 1 {{exact filler}}} + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cache.test b/src/vfs/critcl.vfs/test/cache.test new file mode 100644 index 00000000..86d3f9c0 --- /dev/null +++ b/src/vfs/critcl.vfs/test/cache.test @@ -0,0 +1,67 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# cache.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + + # Helper procedures + useLocalFile test/support/crit_utils.tcl +} +testing { + useLocal lib/critcl/critcl.tcl critcl +} + +overrides + +# ------------------------------------------------------------------------- +## cache syntax + +test critcl-cache-1.0.7 {cache, wrong\#args, too many} -constraints tcl9 -body { + critcl::cache C X +} -returnCodes error -result {wrong # args: should be "critcl::cache ?dir?"} + +test critcl-cache-1.0.6 {cache, wrong\#args, too many} -constraints tcl8.6plus -body { + critcl::cache C X +} -returnCodes error -result {wrong # args: should be "critcl::cache ?dir?"} + +test critcl-cache-1.0.5 {cache, wrong\#args, too many} -constraints tcl8.5 -body { + critcl::cache C X +} -returnCodes error -result {wrong # args: should be "critcl::cache ?dir?"} + +test critcl-cache-1.0.4 {cache, wrong\#args, too many} -constraints tcl8.4 -body { + critcl::cache C X +} -returnCodes error -result {wrong # args: should be "critcl::cache ?dir?"} + +# ------------------------------------------------------------------------- +## + +test critcl-cache-2.0 {cache, default, home directory} -body { + # Note file join below is to not fail because of \ vs / separators + critcl::cache +} -match glob -result [file dirname [file normalize [file join $::env(HOME) .critcl * _dummy_]]] + +test critcl-cache-2.1 {cache, redirecting cache} -setup { + set here [critcl::cache] +} -body { + critcl::cache $env(HOME)/FOO +} -cleanup { + critcl::cache $here + unset here +} -match glob -result [file dirname [file normalize [file join $::env(HOME) FOO _dummy_]]] + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/callback.test b/src/vfs/critcl.vfs/test/callback.test new file mode 100644 index 00000000..48ce1760 --- /dev/null +++ b/src/vfs/critcl.vfs/test/callback.test @@ -0,0 +1,85 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl_callback.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + + useLocal lib/critcl/critcl.tcl critcl +} + +# ------------------------------------------------------------------------- +## The critcl::callback package provides only stubs. +## To test this we create some basic commands linking the functions +## into the Tcl level. + +testing { + # Must be installed + package require critcl::callback + + puts *\t[join [info loaded] \n*\t] + puts -\t[critcl::This] + puts -\t[file dirname [file dirname [info library]]]/include/* + puts -\t[file dirname [file dirname [info nameofexecutable]]]/include/* + + # Access to the stubs include files + critcl::cheaders [file dirname [file dirname [info library]]]/include/* + critcl::cheaders [file dirname [file dirname [info nameofexecutable]]]/include/* + + critcl::api import critcl::callback 1 + + critcl::ccode { + static critcl_callback_p cb = 0; + } + + critcl::cproc cb-make {Tcl_Interp* interp Tcl_Obj* args} void { + cb = critcl_callback_new (interp, args.c, args.v, 2); + critcl_callback_extend (cb, Tcl_NewStringObj("xyz", -1)); + } + + critcl::cproc cb-call {Tcl_Obj* value} void { + critcl_callback_invoke (cb, 1, &value); + } + + critcl::cproc cb-done {} void { + critcl_callback_destroy (cb); + } + + puts -\tLoaded=[critcl::load] + puts *\t[join [info loaded] \n*\t] +} + +# ------------------------------------------------------------------------- +## + +test critcl-callback-1.0.0 {callback} -setup { + proc ::record {args} { lappend ::trace $args } + cb-make record +} -cleanup { + cb-done + unset ::trace +} -body { + cb-call 1 + cb-call a + cb-call 22 + cb-call bbb + set ::trace +} -result {{xyz 1} {xyz a} {xyz 22} {xyz bbb}} + +# ------------------------------------------------------------------------- + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/ccommand-trace.test b/src/vfs/critcl.vfs/test/ccommand-trace.test new file mode 100644 index 00000000..54122cd7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/ccommand-trace.test @@ -0,0 +1,19 @@ +# critcl::ccommand -- Testing with trace code. +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +trace-do ccommand + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/ccommand.test b/src/vfs/critcl.vfs/test/ccommand.test new file mode 100644 index 00000000..da400611 --- /dev/null +++ b/src/vfs/critcl.vfs/test/ccommand.test @@ -0,0 +1,19 @@ +# critcl::ccommand -- Regular tests +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +do ccommand + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cconst-trace.test b/src/vfs/critcl.vfs/test/cconst-trace.test new file mode 100644 index 00000000..5d89fdf7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/cconst-trace.test @@ -0,0 +1,19 @@ +# critcl::cconst -- Testing with trace code. +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +trace-do cconst + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cconst.test b/src/vfs/critcl.vfs/test/cconst.test new file mode 100644 index 00000000..81e18f89 --- /dev/null +++ b/src/vfs/critcl.vfs/test/cconst.test @@ -0,0 +1,19 @@ +# critcl::cconst -- Regular tests +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +do cconst + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cdata-trace.test b/src/vfs/critcl.vfs/test/cdata-trace.test new file mode 100644 index 00000000..385a88e8 --- /dev/null +++ b/src/vfs/critcl.vfs/test/cdata-trace.test @@ -0,0 +1,19 @@ +# critcl::cdata -- Testing with trace code. +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +trace-do cdata + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cdata.test b/src/vfs/critcl.vfs/test/cdata.test new file mode 100644 index 00000000..dd9570ca --- /dev/null +++ b/src/vfs/critcl.vfs/test/cdata.test @@ -0,0 +1,19 @@ +# critcl::cdata -- Regular tests +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +do cdata + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/class.test b/src/vfs/critcl.vfs/test/class.test new file mode 100644 index 00000000..e9864dfe --- /dev/null +++ b/src/vfs/critcl.vfs/test/class.test @@ -0,0 +1,390 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# class.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + useLocal lib/critcl/critcl.tcl critcl + useLocal lib/critcl-util/util.tcl critcl::util + #useLocal lib/critcl-iassoc/iassoc.tcl critcl::iassoc + #useLocal lib/critcl-literals/literals.tcl critcl::literals + + localcache-setup +} +testing { + useLocal lib/critcl-class/class.tcl critcl::class +} + +proc SETUP {} { + make-demo TL { + critcl::class::define ::queuec { + constructor { + if (objc > 0) { + Tcl_AppendResult (interp, "wrong#args for constructor, expected none", NULL); + goto error; + } + } + + method_introspection + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Obj* unget { + List object holding unget'ted elements. + } { + instance->unget = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->unget); + } { + Tcl_DecrRefCount (instance->unget); + } + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Obj* queue { + List object holding the main queue. + } { + instance->queue = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->queue); + } { + Tcl_DecrRefCount (instance->queue); + } + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Obj* append { + List object holding new elements + } { + instance->append = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (instance->append); + } { + Tcl_DecrRefCount (instance->append); + } + + # # ## ### ##### ######## ############# ##################### + insvariable Tcl_Size at { + Index of next element to return from the main queue. + (variable: queue). + } { + instance->at = 0; + } ; # no need for a destructor + + # # ## ### ##### ######## ############# ##################### + method clear proc {} void { + /* + * Delete and recreate the queue memory. A combination of delete/new, + * except the main structure is left unchanged + */ + + Tcl_DecrRefCount (instance->unget); + Tcl_DecrRefCount (instance->queue); + Tcl_DecrRefCount (instance->append); + + instance->at = 0; + instance->unget = Tcl_NewListObj (0,NULL); + instance->queue = Tcl_NewListObj (0,NULL); + instance->append = Tcl_NewListObj (0,NULL); + + Tcl_IncrRefCount (instance->unget); + Tcl_IncrRefCount (instance->queue); + Tcl_IncrRefCount (instance->append); + } + + # # ## ### ##### ######## ############# ##################### + method get as QueueRetrieve 1 + method peek as QueueRetrieve 0 + + # # ## ### ##### ######## ############# ##################### + method put command { + item... = objv[2]... + } { + Tcl_Size i; + + if (objc < 3) { + Tcl_WrongNumArgs (interp, 2, objv, "item ?item ...?"); + return TCL_ERROR; + } + + for (i = 2; i < objc; i++) { + Tcl_ListObjAppendElement (interp, instance->append, objv[i]); + } + + return TCL_OK; + } + + # # ## ### ##### ######## ############# ##################### + method size proc {} wideint { + return QueueSize (instance, NULL, NULL, NULL); + } + + # # ## ### ##### ######## ############# ##################### + method unget proc {Tcl_Obj* item} ok { + if (instance->at == 0) { + /* Need the unget stack */ + Tcl_ListObjAppendElement (interp, instance->unget, item); + } else { + /* + * We have room in the return buffer, so splice directly instead of + * using the unget stack. + */ + + Tcl_Size queuec = 0; + Tcl_ListObjLength (NULL, instance->queue, &queuec); + + instance->at --; + Tcl_ListObjReplace (interp, instance->queue, instance->at, 1, 1, &item); + } + + return TCL_OK; + } + + # # ## ### ##### ######## ############# ##################### + support { + static Tcl_Size + QueueSize (@instancetype@ q, Tcl_Size* u, Tcl_Size* r, Tcl_Size* a) + { + Tcl_Size ungetc = 0; + Tcl_Size queuec = 0; + Tcl_Size appendc = 0; + + Tcl_ListObjLength (NULL, q->unget, &ungetc); + Tcl_ListObjLength (NULL, q->queue, &queuec); + Tcl_ListObjLength (NULL, q->append, &appendc); + + if (u) *u = ungetc; + if (r) *r = queuec; + if (a) *a = appendc; + + return ungetc + queuec + appendc - q->at; + } + + static void + QueueShift (@instancetype@ q) + { + Tcl_Size queuec = 0; + Tcl_Size appendc = 0; + + /* The queue is not done yet, no shift */ + Tcl_ListObjLength (NULL, q->queue, &queuec); + if (q->at < queuec) return; + + /* The queue is done, however there is nothing + * to shift into it, so we don't + */ + Tcl_ListObjLength (NULL, q->append, &appendc); + if (!appendc) return; + + q->at = 0; + Tcl_DecrRefCount (q->queue); + q->queue = q->append; + q->append = Tcl_NewListObj (0,NULL); + Tcl_IncrRefCount (q->append); + } + + static int + QueueRetrieve (@instancetype@ instance, + Tcl_Interp* interp, + Tcl_Size objc, + Tcl_Obj* CONST* objv, + int get) + { + /* Syntax: queue peek|get ?n? + * [0] [1] [2] + */ + + Tcl_Size listc = 0, n = 1; + Tcl_Obj** listv; + Tcl_Obj* r; + Tcl_Size ungetc; + Tcl_Size queuec; + Tcl_Size appendc; + + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs (interp, 2, objv, "?n?"); + return TCL_ERROR; + } + + if (objc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_OK) { + return TCL_ERROR; + } else if (n < 1) { + Tcl_AppendResult (interp, "invalid item count ", + Tcl_GetString (objv[2]), + NULL); + return TCL_ERROR; + } + } + + if (n > QueueSize(instance, &ungetc, &queuec, &appendc)) { + Tcl_AppendResult (interp, + "insufficient items in queue to fill request", + NULL); + return TCL_ERROR; + } + + /* 1. We have item on the unget stack + * a. Enough to satisfy request. + * b. Not enough. + * 2. We have items in the return buffer. + * a. Enough to satisfy request. + * b. Not enough. + * 3. We have items in the append buffer. + * a. Enough to satisfy request. + * b. Not enough. + * + * Case 3. can assume 2b, because an empty return buffer will be filled + * from the append buffer before looking at either. Case 3. cannot happen + * for n==1, the return buffer will contain at least one element. + * + * We distinguish between single and multi-element requests. + * + * XXX AK optimizations - If we can return everything from a single + * buffer, be it queue, or append, just return the buffer object, do not + * create something new. + */ + + if (n == 1) { + if (ungetc) { + /* Pull from unget stack */ + Tcl_ListObjGetElements (interp, instance->unget, &listc, &listv); + r = listv [listc-1]; + Tcl_SetObjResult (interp, r); + if (get) { + /* XXX AK : Should maintain max size info, and proper index, for discard. */ + Tcl_ListObjReplace (interp, instance->unget, listc-1, 1, 0, NULL); + } + } else { + QueueShift (instance); + Tcl_ListObjGetElements (interp, instance->queue, &listc, &listv); + r = listv [instance->at]; + Tcl_SetObjResult (interp, r); + /* + * Note: Doing the SetObj now is important. It increments the + * refcount of 'r', allowing it to survive if the 'QueueShift' below + * kills the internal list (instance->queue) holding it. + */ + if (get) { + instance->at ++; + QueueShift (instance); + } + } + } else { + /* + * Allocate buffer for result, then fill it using the various data + * sources. + */ + + Tcl_Size i = 0, j; + Tcl_Obj** resv = (Tcl_Obj**) ckalloc (n * sizeof (Tcl_Obj*)); + + if (ungetc) { + Tcl_ListObjGetElements (interp, instance->unget, &listc, &listv); + /* + * Note how we are iterating backward in listv. unget is managed + * as a stack, avoiding mem-copy operations and both push and pop. + */ + for (j = listc-1; + j >= 0 && i < n; + j--, i++) { + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + if (get) { + /* XXX AK : Should maintain max size info, and proper index, for discard. */ + Tcl_ListObjReplace (interp, instance->unget, j, i, 0, NULL); + /* XXX CHECK index calcs. */ + } + } + if (i < n) { + QueueShift (instance); + Tcl_ListObjGetElements (interp, instance->queue, &listc, &listv); + for (j = instance->at; + j < listc && i < n; + j++, i++) { + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + + if (get) { + instance->at = j; + QueueShift (instance); + } else if (i < n) { + /* XX */ + Tcl_ListObjGetElements (interp, instance->append, &listc, &listv); + for (j = 0; + j < listc && i < n; + j++, i++) { + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + } + } + + /* + * This can happen if and only if we have to pull data from append, + * and get is set. Without get XX would have run and filled the result + * to completion. + */ + + if (i < n) { + QueueShift (instance); + Tcl_ListObjGetElements (interp, instance->queue, &listc, &listv); + for (j = instance->at; + j < listc && i < n; + j++, i++) { + resv[i] = listv[j]; + Tcl_IncrRefCount (resv[i]); + } + instance->at = j; + QueueShift (instance); + } + + r = Tcl_NewListObj (n, resv); + Tcl_SetObjResult (interp, r); + + for (i=0;i 0} int 1 - - 0 {expected int > 0, but got "0"} + bool - true 1 - x {expected boolean value but got "x"} + long - 0 - - x {expected integer but got "x"} + wideint - 0 - - x {expected integer but got "x"} + double - 0 0.0 - x {expected floating-point number but got "x"} + float - 0 0.0 - x {expected floating-point number but got "x"} + char* - x - - - n/a + pstring char* x - {return x.s} - n/a + pstring object x - {I (x.o); return x.o} - n/a + bytes object \x01 - {I (x.o); return x.o} - n/a + list object {x y} - {I (x.o); return x.o} {{}a} {list element in braces followed by "a" instead of space} + object - x - {I (x); return x} - n/a + pstring object0 x - {return x.o} - n/a + bytes object0 \x01 - {return x.o} - n/a + list object0 {x y} - {return x.o} {{}a} {list element in braces followed by "a" instead of space} + object object0 x - - - n/a + channel known-channel stdin serial0 - x {can not find channel named "x"} +} { + # Note how the object results have to incr the refcount of the + # argument so that the result converter can decr it safely. And + # for object0 we must not, as the result converter doesn't decr. + # + # Bad combinations + if 0 { + # No string terminator in BA char* return allows random bytes into Tcl result. + bytes char* \x01 - - {return x.s} + # rtype `string` considers result dynamic, pstring's field `.s` is really not. + pstring string x - - {return x.s} + } + + if {$goodres eq "-"} { set goodres $good } + if {$rtype eq "-"} { set rtype $type } + if {$body eq "-"} { set body {return x} } + + #puts _____________________$type/$rtype/_good/$good/$goodres ; flush stdout + test cproc-rt-2.$n.0-$type "critcl, cproc, runtime, $type/$rtype, good input" -setup { + #puts ______________________________//setup/$type/$rtype/$body ; flush stdout + make-demo TL [string map [list @a $type @r $rtype @b $body] { + critcl::ccode { + #define I(o) Tcl_IncrRefCount (o) + /* #define RC(o) { fprintf (stdout, "RC %p ~ %d\n", o, o->refCount); fflush (stdout); } */ + } + critcl::cproc pass {{@a} x} @r { @b; } + }] + #puts ______________________________//setup/done/$good/$goodres ; flush stdout + } -body { + #puts ______________________________//run/$good/$goodres ; flush stdout + pass $good + } -result $goodres + #puts ______________________________//ran/$good/$goodres ; flush stdout + + if {$bad eq "-"} continue + + #puts _____________________$type/_bad/$bad ; flush stdout + + # argument validation, trigger error paths + test cproc-rt-2.$n.1-$type "critcl, cproc, runtime, $type, bad input" -setup { + #puts ______________________________//setup/$type ; flush stdout + make-demo TL [string map [list @a $type @r $rtype @b $body] { + critcl::cproc pass {{@a} x} void { } + }] + #puts ______________________________//setup/done ; flush stdout + } -body { + #puts ______________________________//run ; flush stdout + pass $bad + } -returnCodes error -result $errmsg + + incr n +} +unset n + +# ------------------------------------------------------------------------- +# Special return types: void, ok, new-channel + +test cproc-rt-3.0-void "critcl, cproc, runtime, void result" -setup { + make-demo TL { + critcl::cproc pass {} void { } + } +} -body { + pass +} -result {} + +test cproc-rt-3.1.0-ok-pass "critcl, cproc, runtime, ok pass result" -setup { + make-demo TL { + critcl::cproc pass {} ok { return TCL_OK; } + } +} -body { + pass +} -result {} + +test cproc-rt-3.1.1-ok-fail "critcl, cproc, runtime, ok fail result" -setup { + make-demo TL { + critcl::cproc pass {} ok { return TCL_ERROR; } + } +} -body { + pass +} -returnCodes error -result {} + +test cproc-rt-3.2-new-channel "critcl, cproc, runtime, channel result" -setup { + make-demo TL { + critcl::cproc pass {} new-channel { return Tcl_OpenFileChannel (0, "cproc-new-channel", "a", 0); } + } +} -cleanup { + close $c + unset c + file delete cproc-new-channel +} -body { + set c [pass] +} -result {file*} -match glob + +# ------------------------------------------------------------------------- +# Special argument and return types II: unshared-channel, take-channel, return-channel + +test cproc-rt-3.3.0-unshared-channel "critcl, cproc, runtime, unshared channel ok" -setup { + make-demo TL { + critcl::cproc pass {unshared-channel x} known-channel { return x; } + } +} -cleanup { + close $c + unset c + file delete cproc-new-channel +} -body { + set c [pass [open cproc-new-channel w]] +} -result {file*} -match glob + +test cproc-rt-3.3.1-unshared-channel "critcl, cproc, runtime, unshared channel fail" -setup { + make-demo TL { + critcl::cproc pass {unshared-channel x} known-channel { return x; } + } +} -body { + pass stdin +} -returnCodes error -result {channel is shared} + +test cproc-rt-3.4-take-channel "critcl, cproc, runtime, take & return channel" -setup { + make-demo TL { + critcl::cproc pass {take-channel x} return-channel { return x; } + } +} -cleanup { + close $c + unset c + file delete cproc-new-channel +} -body { + set c [pass [open cproc-new-channel w]] +} -result {file*} -match glob + +# ------------------------------------------------------------------------- +# Generated argument types: variadics. + +test cproc-rt-4.0.0-vint "critcl, cproc, runtime, variadic int, ok" -setup { + make-demo TL { + critcl::cproc pass {int args} int { return args.c; } + } +} -body { + pass 1 2 3 4 5 +} -result 5 + +test cproc-rt-4.0.1-vint "critcl, cproc, runtime, variadic int, fail" -setup { + make-demo TL { + critcl::cproc pass {int args} int { return args.c; } + } +} -body { + pass 1 2 a 4 5 +} -returnCodes error -result {expected integer but got "a"} + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cproc-trace.test b/src/vfs/critcl.vfs/test/cproc-trace.test new file mode 100644 index 00000000..f628b6b2 --- /dev/null +++ b/src/vfs/critcl.vfs/test/cproc-trace.test @@ -0,0 +1,19 @@ +# critcl::cproc -- Testing with trace code. +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +trace-do cproc + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/cproc.test b/src/vfs/critcl.vfs/test/cproc.test new file mode 100644 index 00000000..84da4eab --- /dev/null +++ b/src/vfs/critcl.vfs/test/cproc.test @@ -0,0 +1,19 @@ +# critcl::cproc -- Regular tests +# ------------------------------------------------------------------------- +# Setup + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +useLocalFile test/support/crit_utils.tcl + +# ------------------------------------------------------------------------- + +do cproc + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/emap.test b/src/vfs/critcl.vfs/test/emap.test new file mode 100644 index 00000000..0fbe9382 --- /dev/null +++ b/src/vfs/critcl.vfs/test/emap.test @@ -0,0 +1,326 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# emap.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + useLocal lib/critcl/critcl.tcl critcl + useLocal lib/critcl-iassoc/iassoc.tcl critcl::iassoc + + localcache-setup +} +testing { + useLocal lib/critcl-emap/emap.tcl critcl::emap +} + +proc exE {args} { + list [catch { + uplevel 1 $args + } msg] [set msg] +} + +# ------------------------------------------------------------------------- +## + +test emap-mode-tcl-1.0 {critcl-emap, mode: tcl (default)} -setup { + make-demo TL { + critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 + } + critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE + } + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + int scode; + if (demo_encode (ip, state, &scode) != TCL_OK) return -1; + return scode; + } + critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = demo_decode (ip, scode); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; + } + # Decode hidden in the resultype + critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; + } + } +} -body { + res! + res+ [encode mix] + res+ [xencode done] + res+ [decode 0] + res+ [xdecode 1] + res+ [encode foo] + res+ [exE xencode bar] + res+ [exE xdecode -2] + res? +} -result {1 2 init mix -1 {{1 {bad demo "bar": must be done, init, or mix}}} {{1 {Invalid demo state code -2}}}} + +test emap-mode-tcl-1.1 {critcl-emap, mode: tcl (default) +nocase} -setup { + make-demo TL { + critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 + } + critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE + } -nocase + + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + int scode; + if (demo_encode (ip, state, &scode) != TCL_OK) { + return -1; + } + return scode; + } + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; + } + } +} -body { + res! + res+ [encode MIX] + res+ [xencode INIT] + res? +} -result {1 0} + +test emap-mode-tcl-1.2 {critcl-emap, mode: tcl (default), int/direct} -setup { + make-demo TL { + critcl::emap::def demo { + init 0 + mix 1 + done 2 + } + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + int scode; + if (demo_encode (ip, state, &scode) != TCL_OK) return -1; + return scode; + } + critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = demo_decode (ip, scode); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; + } + # Decode hidden in the resultype + critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; + } + } +} -body { + res! + res+ [encode mix] + res+ [xencode done] + res+ [decode 0] + res+ [xdecode 1] + res+ [encode foo] + res+ [exE xencode bar] + res+ [exE xdecode -2] + res? +} -result {1 2 init mix -1 {{1 {bad demo "bar": must be done, init, or mix}}} {{1 {Invalid demo state code -2}}}} + +# ------------------------------------------------------------------------- +## + +test emap-mode-c-1.0 {critcl-emap, mode: c} -setup { + make-demo TL { + critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 + } + critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE + } -mode c + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); + } + critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + } +} -body { + res! + res+ [encode mix] + res+ [encode foo] + res+ [decode 0] + res+ [decode 55] + res? +} -result {1 -1 init {{}}} + +test emap-mode-c-1.2 {critcl-emap, mode: c, int/direct} -setup { + make-demo TL { + critcl::emap::def demo { + init 0 + mix 1 + done 2 + } -mode c + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); + } + critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + } +} -body { + res! + res+ [encode mix] + res+ [encode foo] + res+ [decode 0] + res+ [decode 55] + res? +} -result {1 -1 init {{}}} + +# ------------------------------------------------------------------------- +## + +test emap-mode-tcl+c-1.0 {critcl-emap, mode: tcl+c} -setup { + make-demo TL { + critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 + } + critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE + } -mode {c tcl} + # Add -nocase as last argument for case-insensitive Tcl strings. + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); + } + critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; + } + # Decode hidden in the resultype + critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; + } + } +} -body { + res! + res+ [encode mix] ;# 1 + res+ [xencode done] ;# 2 + res+ [decode 0] ;# init + res+ [xdecode 1] ;# mix + res+ [encode foo] ;# -1 + res+ [decode 55] + res+ [exE xencode bar] + res+ [exE xdecode -2] + res? +} -result {1 2 init mix -1 {{}} {{1 {bad demo "bar": must be done, init, or mix}}} {{1 {Invalid demo state code -2}}}} + +test emap-mode-tcl+c-1.2 {critcl-emap, mode: tcl+c, int/direct} -setup { + make-demo TL { + critcl::emap::def demo { + init 0 + mix 1 + done 2 + } -mode {c tcl} + # Add -nocase as last argument for case-insensitive Tcl strings. + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* state} int { + return demo_encode_cstr (Tcl_GetString(state)); + } + critcl::cproc decode {Tcl_Interp* ip int scode} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_decode_cstr (scode), -1); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo state} int { + return state; + } + # Decode hidden in the resultype + critcl::cproc xdecode {Tcl_Interp* ip int state} demo { + return state; + } + } +} -body { + res! + res+ [encode mix] ;# 1 + res+ [xencode done] ;# 2 + res+ [decode 0] ;# init + res+ [xdecode 1] ;# mix + res+ [encode foo] ;# -1 + res+ [decode 55] + res+ [exE xencode bar] + res+ [exE xdecode -2] + res? +} -result {1 2 init mix -1 {{}} {{1 {bad demo "bar": must be done, init, or mix}}} {{1 {Invalid demo state code -2}}}} + +# ------------------------------------------------------------------------- +## Notes: +# * `+list` is a decoder extension +# * `-nocase` OTOH is an encoder tweak. No need to test here. + +test emap-mode-tcl+list-1.0 {critcl-emap, mode: +list (implies tcl)} -setup { + make-demo TL { + critcl::ccode { + #define STATE_INIT 0 + #define STATE_MIX 1 + #define STATE_DONE 2 + } + critcl::emap::def demo { + init STATE_INIT + mix STATE_MIX + done STATE_DONE + } -mode +list + critcl::cproc decode-list {Tcl_Interp* ip int args} object { + Tcl_Obj* res = demo_decode_list (ip, args.c, args.v); + if (res) { Tcl_IncrRefCount (res); } + return res; + } + } +} -body { + res! + res+ [decode-list 2 0 1 0 0 1 2] + res+ [decode-list] + res+ [exE decode-list 0 3] + res? +} -result {{{done init mix init init mix done}} {{}} {{1 {Invalid demo state code 3}}}} + +# ------------------------------------------------------------------------- +rename exE {} +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/enum.test b/src/vfs/critcl.vfs/test/enum.test new file mode 100644 index 00000000..8c48f06e --- /dev/null +++ b/src/vfs/critcl.vfs/test/enum.test @@ -0,0 +1,99 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# enum.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + + useLocal lib/critcl/critcl.tcl critcl + useLocal lib/critcl-iassoc/iassoc.tcl critcl::iassoc + useLocal lib/critcl-literals/literals.tcl critcl::literals + + localcache-setup +} +testing { + useLocal lib/critcl-enum/enum.tcl critcl::enum +} + +# ------------------------------------------------------------------------- +## + +test enum-mode-tcl+list-1.0 {critcl-enum, mode: +list} -setup { + make-demo TL { + critcl::enum::def demo { + E_global global + E_exact exact + E_filler filler + } +list + + critcl::cproc decode {Tcl_Interp* ip int args} object { + Tcl_Obj* res = demo_ToObjList (ip, args.c, args.v); + Tcl_IncrRefCount (res); + return res; + } + } +} -body { + decode 1 0 2 +} -result {exact global filler} + +test enum-mode-tcl-1.0 {critcl-enum, mode: tcl} -setup { + make-demo TL { + critcl::enum::def demo { + E_global global + E_exact exact + E_filler filler + } + + critcl::cproc encode {Tcl_Interp* ip Tcl_Obj* str} int { + int val; + demo_GetFromObj (ip, str, 0, &val); + return val; + } + + critcl::cproc decode {Tcl_Interp* ip int val} object { + Tcl_Obj* res = demo_ToObj (ip, val); + Tcl_IncrRefCount (res); + return res; + } + + # Encode hidden in the argtype. + critcl::cproc xencode {Tcl_Interp* ip demo str} int { + return str; + } + + # Encode hidden in the argtype. + critcl::cproc xencode-p {Tcl_Interp* ip demo-prefix str} int { + return str; + } + + # Decode hidden in the resultype + critcl::cproc xdecode {Tcl_Interp* ip int val} demo { + return val; + } + } +} -body { + res! + res+ [encode exact] + res+ [xencode filler] + res+ [xencode-p glob] + res+ [xencode glob] + res+ [decode 2] + res+ [xdecode 0] + res? +} -result {1 2 0 0 filler global} + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/iassoc.test b/src/vfs/critcl.vfs/test/iassoc.test new file mode 100644 index 00000000..35e94687 --- /dev/null +++ b/src/vfs/critcl.vfs/test/iassoc.test @@ -0,0 +1,56 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# iassoc.test +## +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + useLocal lib/critcl/critcl.tcl critcl + + localcache-setup +} +testing { + useLocal lib/critcl-iassoc/iassoc.tcl critcl::iassoc +} + +# ------------------------------------------------------------------------- +## + +test iassoc-counter-1.0 {critcl::iassoc - per-interp counter} -setup { + make-demo TL { + critcl::iassoc::def icounter {int base} { + int counter; /* The counter variable */ + } { + data->counter = base; + } { + /* Nothing to release */ + } + critcl::cproc icounter {Tcl_Interp* interp int base} int { + icounter_data d = icounter (interp, base); + d->counter ++; + return d->counter; + } + } +} -body { + res! + res+ [icounter 4] + res+ [icounter 0] + res+ [icounter -1] + res? +} -result {5 6 7} + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/literals.test b/src/vfs/critcl.vfs/test/literals.test new file mode 100644 index 00000000..5337a68c --- /dev/null +++ b/src/vfs/critcl.vfs/test/literals.test @@ -0,0 +1,130 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# enum.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + + useLocal lib/critcl/critcl.tcl critcl + useLocal lib/critcl-iassoc/iassoc.tcl critcl::iassoc + + localcache-setup +} +testing { + useLocal lib/critcl-literals/literals.tcl critcl::literals +} + +# ------------------------------------------------------------------------- +## + +test literals-mode-tcl-1.0 {critcl-literals, mode: tcl (default)} -setup { + make-demo TL { + critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" + } + + critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = demo (ip, code); + Tcl_IncrRefCount (res); + return res; + } + + # Conversion hidden in the result-type + critcl::cproc xstr {Tcl_Interp* ip int code} demo { + return code; + } + } +} -body { + res! + res+ [str 1] + res+ [xstr 2] + res? +} -result {comes the} + +test literals-mode-c-1.0 {critcl-literals, mode: c (alone)} -setup { + make-demo TL { + critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" + } c + + critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_cstr (code), -1); + Tcl_IncrRefCount (res); + return res; + } + } +} -body { + str 3 +} -result sun + +test literals-mode-c+tcl-1.0 {critcl-literals, mode: c + tcl} -setup { + make-demo TL { + critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" + } {c tcl} + + critcl::cproc str {Tcl_Interp* ip int code} object { + Tcl_Obj* res = demo (ip, code); + Tcl_IncrRefCount (res); + return res; + } + + critcl::cproc cstr {Tcl_Interp* ip int code} object { + Tcl_Obj* res = Tcl_NewStringObj (demo_cstr (code), -1); + Tcl_IncrRefCount (res); + return res; + } + } +} -body { + res! + res+ [str 1] + res+ [cstr 2] + res? +} -result {comes the} + +test literals-mode-+list-1.0 {critcl-literals, mode: +list (tcl implied)} -setup { + make-demo TL { + critcl::literals::def demo { + here "here" + comes "comes" + the "the" + sun "sun" + } +list + + critcl::cproc strs {Tcl_Interp* ip int args} object { + Tcl_Obj* res = demo_list (ip, args.c, args.v); + Tcl_IncrRefCount (res); + return res; + } + } +} -body { + res! + res+ [strs 2] + res+ [strs 3 0 1] + res? +} -result {the {{sun here comes}}} + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/md5.test b/src/vfs/critcl.vfs/test/md5.test new file mode 100644 index 00000000..ccd34a76 --- /dev/null +++ b/src/vfs/critcl.vfs/test/md5.test @@ -0,0 +1,62 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# md5.test +## +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + useLocal lib/critcl/critcl.tcl critcl + + localcache-setup +} +testing { + useLocal lib/critcl-md5c/md5c.tcl critcl_md5c +} + +# ------------------------------------------------------------------------- +## + +test critcl-md5c-1.0.0 {md5c, wrong\#args, not enough} -body { + md5c +} -returnCodes error -result {wrong # args: should be "md5c data ?context?"} + +test critcl-md5c-1.0.1 {md5c, wrong\#args, too many} -body { + md5c STR CTX X +} -returnCodes error -result {wrong # args: should be "md5c data ?context?"} + +# ------------------------------------------------------------------------- +## md5c values + +foreach {n expected msg} { + 0 "d41d8cd98f00b204e9800998ecf8427e" "" + 1 "0cc175b9c0f1b6a831c399e269772661" "a" + 2 "900150983cd24fb0d6963f7d28e17f72" "abc" + 3 "f96b697d7cb7938d525a2f31aaf161d0" "message digest" + 4 "c3fcd3d76192e4007dfb496cca67e13b" "abcdefghijklmnopqrstuvwxyz" + 5 "d174ab98d277d9f5a5611c2c9f419d9f" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + 6 "57edf4a22be3c955ac49da2e2107b67a" "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + 7 "020c3dd6931f7e94ecc99a1f4e4c53e2" "a\$apr1\$a" + 8 "e859a53f19b3351aaed08583d74e44bf" "\u0000\u0001\u00FF" + 9 "b63a87afa20522f50750e71f0eaf8e85" "\u0000\u0001\u01FF" +} { + test critcl-md5c-2.0.$n "md5c, msg:($msg)" -body { + binary scan [md5c [encoding convertto utf-8 $msg]] H* computed + set computed + } -result $expected +} + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/stubs_container.test b/src/vfs/critcl.vfs/test/stubs_container.test new file mode 100644 index 00000000..32b0b6c3 --- /dev/null +++ b/src/vfs/critcl.vfs/test/stubs_container.test @@ -0,0 +1,736 @@ +# stubs_container.test -*- tcl -*- + +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +testing { + useLocal lib/stubs_container/container.tcl stubs::container +} + +# ------------------------------------------------------------------------- +# new + +test stubs-container-1.0 {new, wrong\#args} -setup { +} -body { + stubs::container::new X +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::new"} + +test stubs-container-1.1 {new} -setup { + set T [stubs::container::new] +} -body { + lappend R [stubs::container::library? $T] + lappend R [stubs::container::interfaces $T] + lappend R [stubs::container::scspec? $T] + lappend R [stubs::container::epoch? $T] + lappend R [stubs::container::revision? $T] + set R +} -cleanup { + unset T R +} -result {UNKNOWN {} EXTERN {} 0} + +# ------------------------------------------------------------------------- +# library, library? + +test stubs-container-2.0 {library, wrong\#args} -setup { +} -body { + stubs::container::library +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::library tablevar name"} + +test stubs-container-2.1 {library, wrong\#args} -setup { +} -body { + stubs::container::library T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::library tablevar name"} + +test stubs-container-2.2 {library, wrong\#args} -setup { +} -body { + stubs::container::library T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::library tablevar name"} + +test stubs-container-2.3 {library?, wrong\#args} -setup { +} -body { + stubs::container::library? +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::library? table"} + +test stubs-container-2.4 {library?, wrong\#args} -setup { +} -body { + stubs::container::library? T X +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::library? table"} + +test stubs-container-2.5 {library, set/get} -setup { + set T [stubs::container::new] +} -body { + lappend R [stubs::container::library? $T] + stubs::container::library T TEST + lappend R [stubs::container::library? $T] + set R +} -cleanup { + unset T R +} -result {UNKNOWN TEST} + +# ------------------------------------------------------------------------- +# scspec, scspec? + +test stubs-container-3.0 {scspec, wrong\#args} -setup { +} -body { + stubs::container::scspec +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::scspec tablevar value"} + +test stubs-container-3.1 {scspec, wrong\#args} -setup { +} -body { + stubs::container::scspec T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::scspec tablevar value"} + +test stubs-container-3.2 {scspec, wrong\#args} -setup { +} -body { + stubs::container::scspec T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::scspec tablevar value"} + +test stubs-container-3.3 {scspec?, wrong\#args} -setup { +} -body { + stubs::container::scspec? +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::scspec? table"} + +test stubs-container-3.4 {scspec?, wrong\#args} -setup { +} -body { + stubs::container::scspec? T X +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::scspec? table"} + +test stubs-container-3.5 {scspec, set/get} -setup { + set T [stubs::container::new] +} -body { + lappend R [stubs::container::scspec? $T] + stubs::container::scspec T TEST + lappend R [stubs::container::scspec? $T] + set R +} -cleanup { + unset T R +} -result {EXTERN TEST} + +# ------------------------------------------------------------------------- +# epoch, epoch? + +test stubs-container-4.0 {epoch, wrong\#args} -setup { +} -body { + stubs::container::epoch +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::epoch tablevar value"} + +test stubs-container-4.1 {epoch, wrong\#args} -setup { +} -body { + stubs::container::epoch T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::epoch tablevar value"} + +test stubs-container-4.2 {epoch, wrong\#args} -setup { +} -body { + stubs::container::epoch T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::epoch tablevar value"} + +test stubs-container-4.3 {epoch?, wrong\#args} -setup { +} -body { + stubs::container::epoch? +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::epoch? table"} + +test stubs-container-4.4 {epoch?, wrong\#args} -setup { +} -body { + stubs::container::epoch? T X +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::epoch? table"} + +test stubs-container-4.5 {epoch, set/get, bad value, not integer} -setup { + set T [stubs::container::new] +} -body { + stubs::container::epoch T TEST +} -cleanup { + unset T +} -returnCodes error -result {Expected integer for epoch, but got "TEST"} + +test stubs-container-4.6 {epoch, set/get} -setup { + set T [stubs::container::new] +} -body { + lappend R [stubs::container::epoch? $T] + stubs::container::epoch T 42 + lappend R [stubs::container::epoch? $T] + set R +} -cleanup { + unset T R +} -result {{} 42} + +# ------------------------------------------------------------------------- +# interface, interfaces + +test stubs-container-5.0 {interface, wrong\#args} -setup { +} -body { + stubs::container::interface +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::interface tablevar name"} + +test stubs-container-5.1 {interface, wrong\#args} -setup { +} -body { + stubs::container::interface T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::interface tablevar name"} + +test stubs-container-5.2 {interface, wrong\#args} -setup { +} -body { + stubs::container::interface T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::interface tablevar name"} + +test stubs-container-5.3 {interfaces, wrong\#args} -setup { +} -body { + stubs::container::interfaces +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::interfaces table"} + +test stubs-container-5.4 {interfaces, wrong\#args} -setup { +} -body { + stubs::container::interfaces T X +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::interfaces table"} + +test stubs-container-5.5 {interface(s), set/get} -setup { + set T [stubs::container::new] +} -body { + lappend R [stubs::container::interfaces $T] + stubs::container::interface T TEST + lappend R [stubs::container::interfaces $T] + stubs::container::interface T FOO + lappend R [lsort -dict [stubs::container::interfaces $T]] + set R +} -cleanup { + unset T R +} -result {{} TEST {FOO TEST}} + +test stubs-container-5.6 {interface, duplicate declaration} -setup { + set T [stubs::container::new] + stubs::container::interface T A +} -body { + stubs::container::interface T A +} -cleanup { + unset T +} -returnCodes error -result {Duplicate declaration of interface "A"} + +# ------------------------------------------------------------------------- +# hooks, hooks?, hooksof + +test stubs-container-6.0 {hooks, wrong\#args} -setup { +} -body { + stubs::container::hooks +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks tablevar interface names"} + +test stubs-container-6.1 {hooks, wrong\#args} -setup { +} -body { + stubs::container::hooks T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks tablevar interface names"} + +test stubs-container-6.2 {hooks, wrong\#args} -setup { +} -body { + stubs::container::hooks T x +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks tablevar interface names"} + +test stubs-container-6.3 {hooks, wrong\#args} -setup { +} -body { + stubs::container::hooks T x y z +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks tablevar interface names"} + +test stubs-container-6.4 {hooksof, wrong\#args} -setup { +} -body { + stubs::container::hooksof +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooksof table interface"} + +test stubs-container-6.5 {hooksof, wrong\#args} -setup { +} -body { + stubs::container::hooksof T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooksof table interface"} + +test stubs-container-6.6 {hooksof, wrong\#args} -setup { +} -body { + stubs::container::hooksof T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooksof table interface"} + +test stubs-container-6.7 {hooks?, wrong\#args} -setup { +} -body { + stubs::container::hooks? +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks? table interface"} + +test stubs-container-6.8 {hooks?, wrong\#args} -setup { +} -body { + stubs::container::hooks? T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks? table interface"} + +test stubs-container-6.9 {hooks?, wrong\#args} -setup { +} -body { + stubs::container::hooks? T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::hooks? table interface"} + +test stubs-container-6.10 {hooks, hooksof, hooks?, set/get} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::interface T B + stubs::container::hooks T A {B C} +} -body { + lappend R [stubs::container::hooks? $T A] + lappend R [stubs::container::hooks? $T B] + lappend R [stubs::container::hooksof $T A] + lappend R [stubs::container::hooksof $T B] + set R +} -cleanup { + unset T R +} -result {1 0 {B C} {}} + +test stubs-container-6.11 {hooksof, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::hooksof $T A +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +test stubs-container-6.12 {hooks?, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::hooks? $T A +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +# ------------------------------------------------------------------------- +# platforms + +test stubs-container-7.0 {platforms, wrong\#args} -setup { +} -body { + stubs::container::platforms +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::platforms table interface"} + +test stubs-container-7.1 {platforms, wrong\#args} -setup { +} -body { + stubs::container::platforms T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::platforms table interface"} + +test stubs-container-7.2 {platforms, wrong\#args} -setup { +} -body { + stubs::container::platforms T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::platforms table interface"} + +test stubs-container-7.3 {platforms} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::interface T B + stubs::container::declare T B 5 generic _foo_ +} -body { + lappend R [stubs::container::platforms $T A] + lappend R [stubs::container::platforms $T B] + set R +} -cleanup { + unset T R +} -result {{} generic} + +test stubs-container-7.4 {platforms, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::platforms $T A +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +# ------------------------------------------------------------------------- +# lastof + +test stubs-container-8.0 {lastof, wrong\#args} -setup { +} -body { + stubs::container::lastof +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::lastof table interface ?platform?"} + +test stubs-container-8.1 {lastof, wrong\#args} -setup { +} -body { + stubs::container::lastof T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::lastof table interface ?platform?"} + +test stubs-container-8.2 {lastof, wrong\#args} -setup { +} -body { + stubs::container::lastof T x y z a +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::lastof table interface ?platform?"} + +test stubs-container-8.3 {lastof, all} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::interface T B + stubs::container::declare T B 5 generic _foo_ +} -body { + lappend R [stubs::container::lastof $T A] ; # note empty list! + lappend R [stubs::container::lastof $T B] ; # note single element list! + set R +} -cleanup { + unset T R +} -result {{} 5} + +test stubs-container-8.3.1 {lastof, all} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::interface T B + stubs::container::declare T B 5 generic _bogus_ + stubs::container::declare T B 7 aqua _bogus_ +} -body { + lappend R [stubs::container::lastof $T A] ; # note empty list! + lappend R [lsort -dict [stubs::container::lastof $T B]] ; # note list! + set R +} -cleanup { + unset T R +} -result {{} {5 7}} + +test stubs-container-8.4 {lastof, by platform} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::interface T B + stubs::container::declare T B 5 generic _foo_ +} -body { + lappend R [stubs::container::lastof $T A generic] + lappend R [stubs::container::lastof $T B generic] + set R +} -cleanup { + unset T R +} -result {-1 5} + +test stubs-container-8.5 {lastof, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::lastof $T A +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +# ------------------------------------------------------------------------- +# slot? + +test stubs-container-9.0 {slot?, wrong\#args} -setup { +} -body { + stubs::container::slot? +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot? table interface platform at"} + +test stubs-container-9.1 {slot?, wrong\#args} -setup { +} -body { + stubs::container::slot? T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot? table interface platform at"} + +test stubs-container-9.2 {slot?, wrong\#args} -setup { +} -body { + stubs::container::slot? T x +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot? table interface platform at"} + +test stubs-container-9.3 {slot?, wrong\#args} -setup { +} -body { + stubs::container::slot? T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot? table interface platform at"} + +test stubs-container-9.4 {slot?, wrong\#args} -setup { +} -body { + stubs::container::slot? T x y z a +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot? table interface platform at"} + +test stubs-container-9.5 {slot?, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::slot? $T A y z +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +test stubs-container-9.6 {slot?, unknown platform, slot} -setup { + set T [stubs::container::new] + stubs::container::interface T A +} -body { + stubs::container::slot? $T A y z +} -cleanup { + unset T +} -result 0 + +test stubs-container-9.7 {slot?} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::declare T A 5 generic _foo_ +} -body { + stubs::container::slot? $T A generic 5 +} -cleanup { + unset T +} -result 1 + +# ------------------------------------------------------------------------- +# slot + +test stubs-container-10.0 {slot, wrong\#args} -setup { +} -body { + stubs::container::slot +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot table interface platform at"} + +test stubs-container-10.1 {slot, wrong\#args} -setup { +} -body { + stubs::container::slot T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot table interface platform at"} + +test stubs-container-10.2 {slot, wrong\#args} -setup { +} -body { + stubs::container::slot T x +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot table interface platform at"} + +test stubs-container-10.3 {slot, wrong\#args} -setup { +} -body { + stubs::container::slot T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot table interface platform at"} + +test stubs-container-10.4 {slot, wrong\#args} -setup { +} -body { + stubs::container::slot T x y z a +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slot table interface platform at"} + +test stubs-container-10.5 {slot, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::slot $T A y z +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +test stubs-container-10.6 {slot, unknown platform, slot} -setup { + set T [stubs::container::new] + stubs::container::interface T A +} -body { + stubs::container::slot $T A y z +} -cleanup { + unset T +} -returnCodes error -result {Unknown slot "y,z"} + +test stubs-container-10.7 {slot} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::declare T A 5 generic _foo_ +} -body { + stubs::container::slot $T A generic 5 +} -cleanup { + unset T +} -result _foo_ + +# ------------------------------------------------------------------------- +# slotplatforms + +test stubs-container-11.0 {slotplatforms, wrong\#args} -setup { +} -body { + stubs::container::slotplatforms +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slotplatforms table interface at"} + +test stubs-container-11.1 {slotplatforms, wrong\#args} -setup { +} -body { + stubs::container::slotplatforms T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slotplatforms table interface at"} + +test stubs-container-11.2 {slotplatforms, wrong\#args} -setup { +} -body { + stubs::container::slotplatforms T x +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slotplatforms table interface at"} + +test stubs-container-11.3 {slotplatforms, wrong\#args} -setup { +} -body { + stubs::container::slotplatforms T x y a +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::slotplatforms table interface at"} + +test stubs-container-11.4 {slotplatforms, unknown interface} -setup { + set T [stubs::container::new] +} -body { + stubs::container::slotplatforms $T A y +} -cleanup { + unset T +} -returnCodes error -result {Unknown interface "A"} + +test stubs-container-11.5 {slotplatforms, unknown slot} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::declare T A 5 generic _foo_ +} -body { + stubs::container::slotplatforms $T A 4 +} -cleanup { + unset T +} -result {} + +test stubs-container-11.6 {slotplatforms} -setup { + set T [stubs::container::new] + stubs::container::interface T A + stubs::container::declare T A 5 generic _foo_ +} -body { + stubs::container::slotplatforms $T A 5 +} -cleanup { + unset T +} -result generic + +# ------------------------------------------------------------------------- +## Representation overview, basics. + +test stubs-container-12.0 {print, wrong\#args} -setup { +} -body { + stubs::container::print +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::print table"} + +test stubs-container-12.1 {print, wrong\#args} -setup { +} -body { + stubs::container::print T x +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::container::print table"} + +test stubs-container-12.2 {print, empty} -setup { + set T [stubs::container::new] +} -body { + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs UNKNOWN { + scspec EXTERN + epoch {} + revision 0 +}} + +test stubs-container-12.3 {print, global settings} -setup { + set T [stubs::container::new] + stubs::container::library T TEST + stubs::container::scspec T ZEXTERN + stubs::container::epoch T 1 +} -body { + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs TEST { + scspec ZEXTERN + epoch 1 + revision 0 +}} + +test stubs-container-12.4 {print, interface} -setup { + set T [stubs::container::new] + stubs::container::library T TEST + stubs::container::scspec T ZEXTERN + stubs::container::epoch T 1 + stubs::container::interface T A +} -body { + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs TEST { + scspec ZEXTERN + epoch 1 + revision 0 + interface A { + hooks {} + } +}} + +test stubs-container-12.5 {print, interface with hooks} -setup { + set T [stubs::container::new] + stubs::container::library T TEST + stubs::container::scspec T ZEXTERN + stubs::container::epoch T 1 + stubs::container::interface T A + stubs::container::interface T B + stubs::container::interface T C + stubs::container::hooks T A {B C} +} -body { + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs TEST { + scspec ZEXTERN + epoch 1 + revision 0 + interface A { + hooks {B C} + } + interface B { + hooks {} + } + interface C { + hooks {} + } +}} + +test stubs-container-12.6 {print, declarations} -setup { + set T [stubs::container::new] + stubs::container::library T TEST + stubs::container::scspec T ZEXTERN + stubs::container::epoch T 1 + stubs::container::interface T A + stubs::container::declare T A 5 generic _bar_ + stubs::container::declare T A 5 {x11 aqua} _foo_ +} -body { + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs TEST { + scspec ZEXTERN + epoch 1 + revision 2 + interface A { + hooks {} + declare 5 generic { + function {} + return _bar_ + } + declare 5 {aqua x11} { + function {} + return _foo_ + } + } +}} + +# ------------------------------------------------------------------------- + +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/stubs_reader.test b/src/vfs/critcl.vfs/test/stubs_reader.test new file mode 100644 index 00000000..94d681dd --- /dev/null +++ b/src/vfs/critcl.vfs/test/stubs_reader.test @@ -0,0 +1,222 @@ +# stubs_reader.test -*- tcl -*- + +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container +} +testing { + useLocal lib/stubs_reader/reader.tcl stubs::reader +} + +# ------------------------------------------------------------------------- +# file + +test stubs-reader-1.0 {file, wrong\#args} -setup { +} -body { + stubs::reader::file +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::reader::file tablevar path"} + +test stubs-reader-1.1 {file, wrong\#args} -setup { +} -body { + stubs::reader::file T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::reader::file tablevar path"} + +test stubs-reader-1.2 {file, wrong\#args} -setup { +} -body { + stubs::reader::file T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::reader::file tablevar path"} + +# ------------------------------------------------------------------------- +# text + +test stubs-reader-2.0 {text, wrong\#args} -setup { +} -body { + stubs::reader::text +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::reader::text tablevar text"} + +test stubs-reader-2.1 {text, wrong\#args} -setup { +} -body { + stubs::reader::text T +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::reader::text tablevar text"} + +test stubs-reader-2.2 {text, wrong\#args} -setup { +} -body { + stubs::reader::text T x y +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::reader::text tablevar text"} + +# ------------------------------------------------------------------------- +## Representation overview for lots of declarations. + +test stubs-reader-3.0 {text, empty} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T {} + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs UNKNOWN { + scspec EXTERN + epoch {} + revision 0 +}} + +test stubs-reader-3.1 {text, basic types} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library buf + interface buf + hooks {bufInt memchan} + declare 0 generic { + int Buf_IsInitialized (Tcl_Interp *interp) + } + } + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs buf { + scspec EXTERN + epoch {} + revision 1 + interface buf { + hooks {bufInt memchan} + declare 0 generic { + function Buf_IsInitialized + return int + argument {{Tcl_Interp *} interp} + } + } +}} + +test stubs-reader-3.2 {text, void} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library buf + interface buf + hooks {bufInt memchan} + declare 0 generic { + int Buf_IsInitialized (void) + } + } + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs buf { + scspec EXTERN + epoch {} + revision 1 + interface buf { + hooks {bufInt memchan} + declare 0 generic { + function Buf_IsInitialized + return int + argument void + } + } +}} + +test stubs-reader-3.3 {text, void via missing arguments} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library buf + interface buf + hooks {bufInt memchan} + declare 0 generic { + int Buf_IsInitialized () + } + } + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs buf { + scspec EXTERN + epoch {} + revision 1 + interface buf { + hooks {bufInt memchan} + declare 0 generic { + function Buf_IsInitialized + return int + argument void + } + } +}} + +test stubs-reader-3.4 {text, var-args function} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library tcl + interface tcl + declare 2 { + void Tcl_Panic(const char *format, ...) + } + } + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs tcl { + scspec EXTERN + epoch {} + revision 1 + interface tcl { + hooks {} + declare 2 generic { + function Tcl_Panic + return void + argument TCL_VARARGS + argument {{const char *} format} + } + } +}} + +test stubs-reader-3.5 {text, array-flag} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library tcl + interface tcl + declare 17 { + Tcl_Obj *Tcl_ConcatObj(Tcl_Size objc, Tcl_Obj *const objv[]) + } + } + stubs::container::print $T +} -cleanup { + unset T +} -result {stubs tcl { + scspec EXTERN + epoch {} + revision 1 + interface tcl { + hooks {} + declare 17 generic { + function Tcl_ConcatObj + return {Tcl_Obj *} + argument {Tcl_Size objc} + argument {{Tcl_Obj *const} objv {[]}} + } + } +}} + +# ------------------------------------------------------------------------- + +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/stubs_writer.test b/src/vfs/critcl.vfs/test/stubs_writer.test new file mode 100644 index 00000000..da7fa183 --- /dev/null +++ b/src/vfs/critcl.vfs/test/stubs_writer.test @@ -0,0 +1,211 @@ +# stubs_writer.test -*- tcl -*- + +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen +} +testing { + useLocal lib/stubs_writer/writer.tcl stubs::writer +} + +# ------------------------------------------------------------------------- +# gen + +test stubs-writer-1.0 {gen, wrong\#args} -setup { +} -body { + stubs::writer::gen +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::writer::gen table"} + +test stubs-writer-1.1 {gen, wrong\#args} -setup { +} -body { + stubs::writer::gen T x +} -cleanup { +} -returnCodes error -result {wrong # args: should be "stubs::writer::gen table"} + +# ------------------------------------------------------------------------- +## Representation overview for lots of declarations. + +test stubs-writer-2.0 {text, empty} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T {} + stubs::writer::gen $T +} -cleanup { + unset T +} -result {# UNKNOWN.decls -- -*- tcl -*- +# +# This file contains the declarations for all public functions +# that are exported by the "UNKNOWN" library via its stubs table. +# + +library UNKNOWN +# END UNKNOWN} + +test stubs-writer-2.1 {text, basic types} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library buf + interface buf + hooks {bufInt memchan} + declare 0 generic { + int Buf_IsInitialized (Tcl_Interp *interp) + } + } + stubs::writer::gen $T +} -cleanup { + unset T +} -result {# buf.decls -- -*- tcl -*- +# +# This file contains the declarations for all public functions +# that are exported by the "buf" library via its stubs table. +# + +library buf + +interface buf +hooks {bufInt memchan} + +declare 0 generic { + int Buf_IsInitialized (Tcl_Interp * interp) +} + +# END buf} + +test stubs-writer-2.2 {text, void} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library buf + interface buf + hooks {bufInt memchan} + declare 0 generic { + int Buf_IsInitialized (void) + } + } + stubs::writer::gen $T +} -cleanup { + unset T +} -result {# buf.decls -- -*- tcl -*- +# +# This file contains the declarations for all public functions +# that are exported by the "buf" library via its stubs table. +# + +library buf + +interface buf +hooks {bufInt memchan} + +declare 0 generic { + int Buf_IsInitialized (void) +} + +# END buf} + +test stubs-writer-2.3 {text, void via missing arguments} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library buf + interface buf + hooks {bufInt memchan} + declare 0 generic { + int Buf_IsInitialized () + } + } + stubs::writer::gen $T +} -cleanup { + unset T +} -result {# buf.decls -- -*- tcl -*- +# +# This file contains the declarations for all public functions +# that are exported by the "buf" library via its stubs table. +# + +library buf + +interface buf +hooks {bufInt memchan} + +declare 0 generic { + int Buf_IsInitialized (void) +} + +# END buf} + +test stubs-writer-2.4 {text, var-args function} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library tcl + interface tcl + declare 0 { + void Tcl_Panic(const char *format, ...) + } + } + stubs::writer::gen $T +} -cleanup { + unset T +} -result {# tcl.decls -- -*- tcl -*- +# +# This file contains the declarations for all public functions +# that are exported by the "tcl" library via its stubs table. +# + +library tcl + +interface tcl + +declare 0 generic { + void Tcl_Panic (const char * format, ...) +} + +# END tcl} + +test stubs-writer-2.5 {text, array-flag} -setup { + set T [stubs::container::new] +} -body { + stubs::reader::text T { + library tcl + interface tcl + declare 0 { + Tcl_Obj *Tcl_ConcatObj(Tcl_Size objc, Tcl_Obj *const objv[]) + } + } + stubs::writer::gen $T +} -cleanup { + unset T +} -result {# tcl.decls -- -*- tcl -*- +# +# This file contains the declarations for all public functions +# that are exported by the "tcl" library via its stubs table. +# + +library tcl + +interface tcl + +declare 0 generic { + Tcl_Obj * Tcl_ConcatObj (Tcl_Size objc, Tcl_Obj *const objv[]) +} + +# END tcl} + +# ------------------------------------------------------------------------- + +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/suites/ccommand.test b/src/vfs/critcl.vfs/test/suites/ccommand.test new file mode 100644 index 00000000..6666aedb --- /dev/null +++ b/src/vfs/critcl.vfs/test/suites/ccommand.test @@ -0,0 +1,124 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl::ccommand +# -- Core tests. +# Used via ccommand.test and ccommand-trace.test +# -- Parameters +# (1) suffix ('' | '-trace') +# This parameter affects test naming and directory holding the +# expected results. +# ------------------------------------------------------------------------- +# Parameter validation + +global suffix +if {![info exists suffix]} { + error "Missing parameter 'suffix'. Please define as either empty string, or '-trace'" +} elseif {($suffix ne "") && ($suffix ne "-trace")} { + error "Bad value '$suffix' for parameter 'suffix'. Please define as either empty string, or '-trace'" +} + +# ------------------------------------------------------------------------- +# Setup + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen +} + +testing { + useLocal lib/critcl/critcl.tcl critcl +} + +overrides +on-traced-on + +# ------------------------------------------------------------------------- +## ccommand syntax + +test critcl-ccommand${suffix}-1.0.7 {ccommand, wrong\#args} -constraints tcl9 -body { + critcl::ccommand +} -returnCodes error -result {wrong # args: should be "critcl::ccommand name anames ?arg ...?"} + +test critcl-ccommand${suffix}-1.0.6 {ccommand, wrong\#args} -constraints tcl8.6plus -body { + critcl::ccommand +} -returnCodes error -result {wrong # args: should be "critcl::ccommand name anames ?arg ...?"} + +test critcl-ccommand${suffix}-1.0.5 {ccommand, wrong\#args} -constraints tcl8.5 -body { + critcl::ccommand +} -returnCodes error -result {wrong # args: should be "critcl::ccommand name anames ..."} + +test critcl-ccommand${suffix}-1.0.4 {ccommand, wrong\#args} -constraints tcl8.4 -body { + critcl::ccommand +} -returnCodes error -result {wrong # args: should be "critcl::ccommand name anames args"} + +# ------------------------------------------------------------------------- +## Go through the various knobs we can use to configure the definition and output + +test critcl-ccommand${suffix}-2.0 {ccommand, defaults} -body { + get critcl::ccommand command {} { + return TCL_OK; + } +} -result [viewFile [localPath test/assets/ccommand${suffix}/2.0]] + +test critcl-ccommand${suffix}-2.1 {ccommand, custom arguments} -body { + get critcl::ccommand command {CD IP OC OV} { + return TCL_OK; + } +} -result [viewFile [localPath test/assets/ccommand${suffix}/2.1]] + +test critcl-ccommand${suffix}-2.2 {ccommand, -cname (custom C name)} -body { + get critcl::ccommand snafu {} { + return TCL_OK; + } -cname 1 +} -result [viewFile [localPath test/assets/ccommand${suffix}/2.2]] + +test critcl-ccommand${suffix}-2.3 {ccommand, namespaced name, and Tcl vs C} -body { + get critcl::ccommand the::command+max {} { + return TCL_OK; + } +} -result [viewFile [localPath test/assets/ccommand${suffix}/2.3]] + +test critcl-ccommand${suffix}-2.4 {ccommand, -delproc} -body { + get critcl::ccommand command {} { + return TCL_OK; + } -delproc DELE +} -result [viewFile [localPath test/assets/ccommand${suffix}/2.0]] + +test critcl-ccommand${suffix}-2.5 {ccommand, -clientdata} -body { + get critcl::ccommand command {} { + return TCL_OK; + } -clientdata ABC +} -result [viewFile [localPath test/assets/ccommand${suffix}/2.0]] + +# ------------------------------------------------------------------------- +## Full builds. + +test critcl-ccommand${suffix}-3.0 {ccommand, defaults} -setup setup -body { + critcl::ccommand command {} { return TCL_OK; } + critcl::cbuild [the-file] + inspect v*.c +} -cleanup cleanup -match glob \ + -result [viewFile [localPath test/assets/ccommand${suffix}/3.0]] + +test critcl-ccommand${suffix}-3.4 {ccommand, -delproc} -setup setup -body { + critcl::ccommand command {} { return TCL_OK; } -delproc DELE + critcl::cbuild [the-file] + inspect v*.c +} -cleanup cleanup -match glob \ + -result [viewFile [localPath test/assets/ccommand${suffix}/3.4]] + +test critcl-ccommand${suffix}-3.5 {ccommand, -clientdata} -setup setup -body { + critcl::ccommand command {} { return TCL_OK; } -clientdata ABC + critcl::cbuild [the-file] + inspect v*.c +} -cleanup cleanup -match glob \ + -result [viewFile [localPath test/assets/ccommand${suffix}/3.5]] + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/suites/cconst.test b/src/vfs/critcl.vfs/test/suites/cconst.test new file mode 100644 index 00000000..c50249b3 --- /dev/null +++ b/src/vfs/critcl.vfs/test/suites/cconst.test @@ -0,0 +1,91 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl::cconst +# -- Core tests. +# Used via cconst.test and cconst-trace.test +# -- Parameters +# (1) suffix ('' | '-trace') +# This parameter affects test naming and directory holding the +# expected results. +# ------------------------------------------------------------------------- +# Parameter validation + +global suffix +if {![info exists suffix]} { + error "Missing parameter 'suffix'. Please define as either empty string, or '-trace'" +} elseif {($suffix ne "") && ($suffix ne "-trace")} { + error "Bad value '$suffix' for parameter 'suffix'. Please define as either empty string, or '-trace'" +} + +# ------------------------------------------------------------------------- +# Setup + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen +} +testing { + useLocal lib/critcl/critcl.tcl critcl +} + +# Note: The next command does not influence the standard argument- +# and result-types. +#critcl::config lines 0 +overrides +on-traced-on + +# ------------------------------------------------------------------------- +## cconst syntax + +test critcl-cconst${suffix}-1.0 {cconst, wrong args, not enough} -setup { +} -body { + critcl::cconst +} -returnCodes error -result {wrong # args: should be "critcl::cconst name rtype rvalue"} + +test critcl-cconst${suffix}-1.1 {cconst, wrong args, not enough} -setup { +} -body { + critcl::cconst N +} -returnCodes error -result {wrong # args: should be "critcl::cconst name rtype rvalue"} + +test critcl-cconst${suffix}-1.2 {cconst, wrong args, not enough} -setup { +} -body { + critcl::cconst N T +} -returnCodes error -result {wrong # args: should be "critcl::cconst name rtype rvalue"} + +test critcl-cconst${suffix}-1.3 {cconst, wrong args, too many} -setup { +} -body { + critcl::cconst N T R X +} -returnCodes error -result {wrong # args: should be "critcl::cconst name rtype rvalue"} + +test critcl-cconst${suffix}-1.4 {cconst, bad result type (void)} -setup { +} -body { + critcl::cconst N void T +} -returnCodes error -result {Constants cannot be of type "void"} + +# ------------------------------------------------------------------------- +## Go through the various knobs we can use to configure the definition and output + +test critcl-cconst${suffix}-2.0 {cconst, bool, fixed value} -body { + get critcl::cconst alpha bool 1 +} -result [viewFile [localPath test/assets/cconst${suffix}/2.0]] + +test critcl-cconst${suffix}-2.1 {cconst, bool, define} -body { + get critcl::cconst alpha bool FOO +} -result [viewFile [localPath test/assets/cconst${suffix}/2.1]] + +test critcl-cconst${suffix}-2.2 {cconst, bool, function} -body { + get critcl::cconst alpha bool foo() +} -result [viewFile [localPath test/assets/cconst${suffix}/2.2]] + +test critcl-cconst${suffix}-2.3 {cconst, namespaced name} -body { + get critcl::cconst the::alpha bool 0 +} -result [viewFile [localPath test/assets/cconst${suffix}/2.3]] + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/suites/cdata.test b/src/vfs/critcl.vfs/test/suites/cdata.test new file mode 100644 index 00000000..bd21ac9f --- /dev/null +++ b/src/vfs/critcl.vfs/test/suites/cdata.test @@ -0,0 +1,74 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl::cdata +# -- Core tests. +# Used via cdata.test and cdata-trace.test +# -- Parameters +# (1) suffix ('' | '-trace') +# This parameter affects test naming and directory holding the +# expected results. +# ------------------------------------------------------------------------- +# Parameter validation + +global suffix +if {![info exists suffix]} { + error "Missing parameter 'suffix'. Please define as either empty string, or '-trace'" +} elseif {($suffix ne "") && ($suffix ne "-trace")} { + error "Bad value '$suffix' for parameter 'suffix'. Please define as either empty string, or '-trace'" +} + +# ------------------------------------------------------------------------- +# Setup + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen +} +testing { + useLocal lib/critcl/critcl.tcl critcl +} + +overrides +on-traced-on + +# ------------------------------------------------------------------------- +## cdata syntax + +test critcl-cdata${suffix}-1.0 {cdata, wrong args, not enough} -setup { +} -body { + critcl::cdata +} -returnCodes error -result {wrong # args: should be "critcl::cdata name data"} + +test critcl-cdata${suffix}-1.1 {cdata, wrong args, not enough} -setup { +} -body { + critcl::cdata N +} -returnCodes error -result {wrong # args: should be "critcl::cdata name data"} + +test critcl-cdata${suffix}-1.2 {cdata, wrong args, too many} -setup { +} -body { + critcl::cdata N D X +} -returnCodes error -result {wrong # args: should be "critcl::cdata name data"} + +# ------------------------------------------------------------------------- +## Go through the various knobs we can use to configure the definition and output + +test critcl-cdata${suffix}-2.0 {cdata, defaults} -body { + get critcl::cdata alpha beta +} -result [viewFile [localPath test/assets/cdata${suffix}/2.0]] + +test critcl-cdata${suffix}-2.1 {cdata, Tcl vs C identifiers} -body { + get critcl::cdata alpha-x beta +} -result [viewFile [localPath test/assets/cdata${suffix}/2.1]] + +test critcl-cdata${suffix}-2.2 {cdata, namespaced name} -body { + get critcl::cdata the::alpha beta +} -result [viewFile [localPath test/assets/cdata${suffix}/2.2]] + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/suites/cproc.test b/src/vfs/critcl.vfs/test/suites/cproc.test new file mode 100644 index 00000000..671fbf4e --- /dev/null +++ b/src/vfs/critcl.vfs/test/suites/cproc.test @@ -0,0 +1,372 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl::cproc +# -- Core tests. +# Used via cproc.test and cproc-trace.test +# -- Parameters +# (1) suffix ('' | '-trace') +# This parameter affects test naming and directory holding the +# expected results. +# ------------------------------------------------------------------------- +# Parameter validation + +global suffix +if {![info exists suffix]} { + error "Missing parameter 'suffix'. Please define as either empty string, or '-trace'" +} elseif {($suffix ne "") && ($suffix ne "-trace")} { + error "Bad value '$suffix' for parameter 'suffix'. Please define as either empty string, or '-trace'" +} + +# ------------------------------------------------------------------------- +# Setup + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen +} +testing { + useLocal lib/critcl/critcl.tcl critcl +} + +# Note: The next command does not influence the standard argument- +# and result-types. +overrides +#critcl::config lines 0 +on-traced-on + +# ------------------------------------------------------------------------- +## cproc syntax + +test critcl-cproc${suffix}-1.0.7 {cproc, wrong\#args} -constraints tcl9 -body { + critcl::cproc +} -returnCodes error -result {wrong # args: should be "critcl::cproc name adefs rtype ?body? ?arg ...?"} + +test critcl-cproc${suffix}-1.0.6 {cproc, wrong\#args} -constraints tcl8.6plus -body { + critcl::cproc +} -returnCodes error -result {wrong # args: should be "critcl::cproc name adefs rtype ?body? ?arg ...?"} + +test critcl-cproc${suffix}-1.0.5 {cproc, wrong\#args} -constraints tcl8.5 -body { + critcl::cproc +} -returnCodes error -result {wrong # args: should be "critcl::cproc name adefs rtype ?body? ..."} + +test critcl-cproc${suffix}-1.0.4 {cproc, wrong\#args} -constraints tcl8.4 -body { + critcl::cproc +} -returnCodes error -result {wrong # args: should be "critcl::cproc name adefs rtype ?body? args"} + +# ------------------------------------------------------------------------- +## Go through the various knobs we can use to configure the definition and output + +test critcl-cproc${suffix}-2.0 {cproc, simple name} -body { + get critcl::cproc aproc {} void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.0]] + +test critcl-cproc${suffix}-2.1 {cproc, namespaced name} -body { + get critcl::cproc the::aproc {} void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.1]] + +test critcl-cproc${suffix}-2.2 {cproc, Tcl vs C identifiers} -body { + get critcl::cproc aproc+beta {} void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.2]] + +test critcl-cproc${suffix}-2.3 {cproc, custom C name} -body { + get critcl::cproc snafu {} void {} -cname 1 +} -result [viewFile [localPath test/assets/cproc${suffix}/2.3]] + +test critcl-cproc${suffix}-2.4 {cproc, client data} -body { + get critcl::cproc aproc {} void {} -pass-cdata 1 +} -result [viewFile [localPath test/assets/cproc${suffix}/2.4]] + +test critcl-cproc${suffix}-2.5 {cproc, client data} -body { + get critcl::cproc aproc {} void {} -arg-offset 3 +} -result [viewFile [localPath test/assets/cproc${suffix}/2.5]] + +test critcl-cproc${suffix}-2.6 {cproc, int argument} -body { + get critcl::cproc aproc { + int anargument + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.6]] + +test critcl-cproc${suffix}-2.7 {cproc, optional int argument} -body { + get critcl::cproc aproc { + int {anargument -1} + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.7]] + +test critcl-cproc${suffix}-2.8 {cproc, optional args, freely mixed} -body { + get critcl::cproc aproc { + int {x -1} + int y + int {z -1} + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.8]] + +test critcl-cproc${suffix}-2.9 {cproc, int result} -body { + get critcl::cproc aproc {} int {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.9]] + +test critcl-cproc${suffix}-2.10 {cproc, optional args} -body { + get critcl::cproc aproc { + int {x -1} + int y + int z + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.10]] + +test critcl-cproc${suffix}-2.11 {cproc, optional args} -body { + get critcl::cproc aproc { + int x + int y + int {z -1} + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.11]] + +test critcl-cproc${suffix}-2.12 {cproc, optional args} -body { + get critcl::cproc aproc { + int x + int {y -1} + int z + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.12]] + +test critcl-cproc${suffix}-2.13 {cproc, variadic int argument} -body { + get critcl::cproc aproc { + int args + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.13]] + +test critcl-cproc${suffix}-2.14 {cproc, variadic Tcl_Obj* argument} -body { + get critcl::cproc aproc { + object args + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.14]] + +test critcl-cproc${suffix}-2.15 {cproc, variadic int argument, required in front} -body { + get critcl::cproc aproc { + int x + int y + int args + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.15]] + +test critcl-cproc${suffix}-2.16 {cproc, variadic int argument, optional in front} -body { + get critcl::cproc aproc { + int {x -1} + int {y -1} + int args + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.16]] + +test critcl-cproc${suffix}-2.17 {cproc, variadic int argument, mix required/optional in front} -body { + get critcl::cproc aproc { + int x + int {y -1} + int args + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.17]] + +test critcl-cproc${suffix}-2.18 {cproc, variadic int argument, mix optional/required in front} -body { + get critcl::cproc aproc { + int {x -1} + int y + int args + } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/2.18]] + +# ------------------------------------------------------------------------- +# Vary the result type of the function. Covers all builtin result types. + +test critcl-cproc${suffix}-3.0 {cproc, void result} -body { + get critcl::cproc aproc {} void { } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.0]] + +test critcl-cproc${suffix}-3.1 {cproc, Tcl-code result} -body { + get critcl::cproc aproc {} ok { return TCL_OK; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.1]] + +test critcl-cproc${suffix}-3.2 {cproc, int result} -body { + get critcl::cproc aproc {} int { return 0; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.2]] + +test critcl-cproc${suffix}-3.3 {cproc, bool result} -body { + get critcl::cproc aproc {} bool { return 1; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.3]] + +test critcl-cproc${suffix}-3.4 {cproc, boolean result} -body { + get critcl::cproc aproc {} boolean { return 1; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.4]] + +test critcl-cproc${suffix}-3.5 {cproc, long result} -body { + get critcl::cproc aproc {} long { return 1; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.5]] + +test critcl-cproc${suffix}-3.6 {cproc, wideint result} -body { + get critcl::cproc aproc {} wideint { return 1; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.6]] + +test critcl-cproc${suffix}-3.7 {cproc, double result} -body { + get critcl::cproc aproc {} double { return 0.; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.7]] + +test critcl-cproc${suffix}-3.8 {cproc, float result} -body { + get critcl::cproc aproc {} float { return 0.; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.8]] + +test critcl-cproc${suffix}-3.9 {cproc, vstring result} -body { + get critcl::cproc aproc {} vstring { return "foo"; } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.9]] + +test critcl-cproc${suffix}-3.10 {cproc, dstring result} -body { + get critcl::cproc aproc {} dstring { return alloc_string("bar"); } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.10]] + +test critcl-cproc${suffix}-3.11 {cproc, object result} -body { + get critcl::cproc aproc {} object { return Tcl_NewIntObj(0); } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.11]] + +test critcl-cproc${suffix}-3.12 {cproc, channel result, new} -body { + get critcl::cproc aproc {} new-channel { + return Tcl_OpenFileChannel (interp, "/tmp", "r", 0); + } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.12]] + +test critcl-cproc${suffix}-3.13 {cproc, channel result, known} -body { + get critcl::cproc aproc {} known-channel { + return Tcl_GetStdChannel (0); + } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.13]] + +test critcl-cproc${suffix}-3.14 {cproc, channel result, return a taken channel} -body { + get critcl::cproc aproc {} return-channel { + return 0; + } +} -result [viewFile [localPath test/assets/cproc${suffix}/3.14]] + + +# ------------------------------------------------------------------------- +# Vary argument types of the function. Cover all (sensible) builtin result types. +# Not covered: int*, float*, double* (all deprecated) + +set n 0 +foreach type { + int + bool + long + wideint + double + float + {int > 0} + char* + pstring + list + object + --bytearray-- + bytes + channel + unshared-channel + take-channel +} { + # allow marking of types as gone. + # allows us to keep the numbers of all tests when types go away. + # no need to renumber all the files for types after the removed type. + # and new types can reuse the slot in the future + + if {![string match "--*--" $type]} { + set td [string map {{ } _ > gt * _} $type] + test critcl-cproc${suffix}-4.${n}-$td "cproc, $type argument" -body { + get critcl::cproc aproc [list $type x] void { } + } -result [viewFile [localPath test/assets/cproc${suffix}/4.${n}-$td]] + unset td + } + incr n +} + +test critcl-cproc${suffix}-4.${n}-vobject "cproc, variadic Tcl_Obj* argument" -body { + get critcl::cproc aproc {object args} void { } +} -result [viewFile [localPath test/assets/cproc${suffix}/4.${n}-vobject]] +incr n + +test critcl-cproc${suffix}-4.${n}-vint "cproc, variadic int argument" -body { + get critcl::cproc aproc {int args} void { } +} -result [viewFile [localPath test/assets/cproc${suffix}/4.${n}-vint]] + +unset n + +# ------------------------------------------------------------------------- +# Test the various derived types: +# - Extended limited scalars +# - List types (length-limited, with base type, both) + +## TODO: Bad types to demonstrate error checking and messages + +set n 0 +foreach type { + {int > 4} + {int > 4 <= 8} + {int < 8} + {int < 8 >= 4} + {int > 2 >= 4} + {int < 2 < 4 < 6} + {int < 2 <= 4} + {[2]} + {[]int} + {[2]int} + {int[]} + {int[2]} +} { + set td [string map { + \[ = \] = + { } _ + >= ge > gt + <= le < lt + } $type] + set rpath [localPath test/assets/cproc${suffix}/6.${n}-$td] + set result ">> missing: $rpath" + if {[file exists $rpath]} { set result [viewFile $rpath] } + + test critcl-cproc${suffix}-6.${n}-$td "cproc, $type argument" -body { + get critcl::cproc aproc [list $type x] void { } + } -result $result + + incr n ; unset td rpath result +} +unset n + +# ------------------------------------------------------------------------- +# Special list syntax, with indicator tailing the argument name, instead of attached to the type. + +set rpath [localPath test/assets/cproc${suffix}/7.0] +set result ">> missing: $rpath" +if {[file exists $rpath]} { set result [viewFile $rpath] } + +test critcl-cproc${suffix}-7.0 "cproc, `int x[]` argument" -body { + get critcl::cproc aproc {int a[]} void { } +} -result $result + +unset rpath result + +# ------------------------------------------------------------------------- +## Mistakenly entered C syntax - Normalize to working syntax + +test critcl-cproc${suffix}-5.0 {cproc, mistaken C argument syntax, lone comma} -body { + get critcl::cproc aproc { int x , int y } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/5.x]] + +test critcl-cproc${suffix}-5.1 {cproc, mistaken C argument syntax, trailing comma} -body { + get critcl::cproc aproc { int x, int y } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/5.x]] + +test critcl-cproc${suffix}-5.2 {cproc, mistaken C argument syntax, leading comma} -body { + get critcl::cproc aproc { int x ,int y } void {} +} -result [viewFile [localPath test/assets/cproc${suffix}/5.x]] + +# ------------------------------------------------------------------------- +## XXX TODO one to multiple arguments +## XXX TODO ... + +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/support/crit_utils.tcl b/src/vfs/critcl.vfs/test/support/crit_utils.tcl new file mode 100644 index 00000000..f97ac97e --- /dev/null +++ b/src/vfs/critcl.vfs/test/support/crit_utils.tcl @@ -0,0 +1,98 @@ +## -*- tcl -*- +# ------------------------------------------------------------------------- + +proc do {suite} { + global suffix + set suffix "" + uplevel 1 [list source [file join [file dirname [info script]] suites ${suite}.test]] +} + +proc trace-do {suite} { + global suffix + set suffix "-trace" + uplevel 1 [list source [file join [file dirname [info script]] suites ${suite}.test]] + + # Stop tracing code injection for the files coming after this one, + # and reset the marker. + critcl::config trace 0 + #unset ::critcl::v::__trace__ +} + +proc on-traced-on {} { + global suffix + if {$suffix eq {}} return + # Activate trace injection. Run a dummy cproc, in a collection + # environment, to get the once-only generated code out of the way. + uplevel 1 {useLocal lib/critcl-cutil/cutil.tcl critcl::cutil} + critcl::config trace 1 + uplevel 1 {critcl::collect { critcl::cproc __ {} void {}}} + return +} + +proc get {args} { + set t [string trim [critcl::collect $args]] + #regsub -all -- {#line \d+ } $t {#line XX } t + return $t +} + +proc setup {} { + critcl::fastuuid ;# no md5, counter, reset + set critcl::v::this FAKE ;# fake a file-name + critcl::cache [localPath test/CACHE] ;# choose cache + return +} + +proc the-file {} { + return $critcl::v::this +} + +proc cleanup {} { + unset critcl::v::this + unset critcl::v::code + unset critcl::v::delproc + unset critcl::v::clientdata + file delete -force -- [localPath test/CACHE] + return +} + +proc inspect {pattern} { + viewFile [lindex [glob -directory [critcl::cache] $pattern] 0] +} + +proc overrides {} { + critcl::fastuuid ;# no md5, use counter + critcl::config lines 0 ;# no #line, mostly + critcl::config keepsrc 1 ;# keep sources in cache + + # Disable actual compilation + proc ::critcl::Compile {tclfile origin cfile obj} { + } + + proc ::critcl::Link {file} { + } + + proc ::critcl::ExecWithLogging {cmdline okmsg errmsg} { + } + + proc ::critcl::Exec {cmdline} { + } + + proc ::critcl::Load {file} { + } +} + + +tcltest::customMatch glob-check G +proc G {p s} { + set map [list \n \\n \t \\t { } \\s] + set buf {} + foreach c [split $p {}] { + append buf $c + if {![string match ${buf}* $s]} { + puts FAIL|[string map $map ${buf}*]| + } + } + return 1 +} + +# ------------------------------------------------------------------------- diff --git a/src/vfs/critcl.vfs/test/support/testutilities.tcl b/src/vfs/critcl.vfs/test/support/testutilities.tcl new file mode 100644 index 00000000..a18f9218 --- /dev/null +++ b/src/vfs/critcl.vfs/test/support/testutilities.tcl @@ -0,0 +1,708 @@ +# -*- tcl -*- +# Testsuite utilities / boilerplate + +# Copyright (c) 2006-2024, Andreas Kupries +# + +set auto_path [linsert $auto_path 0 \ + [file join [file dirname [file dirname [file dirname [info script]]]] lib]] + +namespace eval ::testutils { + variable version 1.2 + variable self [file dirname [file join [pwd] [info script]]] + variable selfdir [file dirname $self] + variable tag "" + variable theEnv ; # Saved environment. + variable cache {} ; # Path to local critcl cache. +} + +# ### ### ### ######### ######### ######### +## Commands for common functions and boilerplate actions required by +## many testsuites of Tcllib modules and packages in a central place +## for easier maintenance. + +# ### ### ### ######### ######### ######### +## Declare the minimal version of Tcl required to run the package +## tested by this testsuite, and its dependencies. + +proc testsNeedTcl {args} { + # This command ensures that a minimum version of Tcl is used to + # run the tests in the calling testsuite. If the minimum is not + # met by the active interpreter we forcibly bail out of the + # testsuite calling the command. The command has to be called + # immediately after loading the utilities. + + if {[package vsatisfies [package provide Tcl] {*}$args]} return + + puts " Aborting the tests found in \"[file tail [info script]]\"" + puts " Requiring at least Tcl $version, have [package present Tcl]." + + # This causes a 'return' in the calling scope. + return -code return +} + +# ### ### ### ######### ######### ######### +## Declare the minimum version of Tcltest required to run the +## testsuite. + +proc testsNeedTcltest {version} { + # This command ensure that a minimum version of the Tcltest + # support package is used to run the tests in the calling + # testsuite. If the minimum is not met by the loaded package we + # forcibly bail out of the testsuite calling the command. The + # command has to be called after loading the utilities. The only + # command allowed to come before it is 'textNeedTcl' above. + + # Note that this command will try to load a suitable version of + # Tcltest if the package has not been loaded yet. + + if {[lsearch [namespace children] ::tcltest] == -1} { + if {![catch { + package require tcltest $version + }]} { + namespace import -force ::tcltest::* + InitializeTclTest + return + } + } elseif {[package vcompare [package present tcltest] $version] >= 0} { + InitializeTclTest + return + } + + puts " Aborting the tests found in [file tail [info script]]." + puts " Requiring at least tcltest $version, have [package present tcltest]" + + # This causes a 'return' in the calling scope. + return -code return +} + +proc testsNeed {name version} { + # This command ensures that a minimum version of package is + # used to run the tests in the calling testsuite. If the minimum + # is not met by the active interpreter we forcibly bail out of the + # testsuite calling the command. The command has to be called + # immediately after loading the utilities. + + if {[package vsatisfies [package provide $name] $version]} return + + puts " Aborting the tests found in \"[file tail [info script]]\"" + puts " Requiring at least $name $version, have [package present $name]." + + # This causes a 'return' in the calling scope. + return -code return +} + +# ### ### ### ######### ######### ######### + +## Save/restore the environment, for testsuites which have to +## manipulate it to (1) either achieve the effects they test +## for/against, or (2) to shield themselves against manipulation by +## the environment. We have examples for both in 'fileutil' (1), and +## 'doctools' (2). +## +## Saving is done automatically at the beginning of a test file, +## through this module. Restoration is done semi-automatically. We +## __cannot__ hook into the tcltest cleanup hook It is already used by +## all.tcl to transfer the information from the slave doing the actual +## tests to the master. Here the hook is only an alias, and +## unmodifiable. We create a new cleanup command which runs both our +## environment cleanup, and the regular one. All .test files are +## modified to use the new cleanup. + +proc ::testutils::SaveEnvironment {} { + global env + variable theEnv [array get env] + return +} + +proc ::testutils::RestoreEnvironment {} { + global env + variable theEnv + variable cache + foreach k [array names env] { + unset env($k) + } + array set env $theEnv + # + if {$cache eq {}} return + #puts "Cache remove $cache" + file delete -force $cache + return +} + +proc testsuiteCleanup {} { + ::testutils::RestoreEnvironment + ::tcltest::cleanupTests + return +} + +proc array_unset {a {pattern *}} { + upvar 1 $a array + foreach k [array names array $pattern] { + unset array($k) + } + return +} + +# ### ### ### ######### ######### ######### +## Newer versions of the Tcltest support package for testsuite provide +## various features which make the creation and maintenance of +## testsuites much easier. I consider it important to have these +## features even if an older version of Tcltest is loaded. To this end +## we now provide emulations and implementations, conditional on the +## version of Tcltest found to be active. + +# ### ### ### ######### ######### ######### +## Easy definition and initialization of test constraints. + +proc InitializeTclTest {} { + global tcltestinit + if {[info exists tcltestinit] && $tcltestinit} return + set tcltestinit 1 + + if {![package vsatisfies [package provide tcltest] 2.0]} { + # Tcltest 2.0+ provides a documented public API to define and + # initialize a test constraint. For earlier versions of the + # package the user has to directly set a non-public undocumented + # variable in the package's namespace. We create a command doing + # this and emulating the public API. + + proc ::tcltest::testConstraint {c args} { + variable testConstraints + if {[llength $args] < 1} { + if {[info exists testConstraints($c)]} { + return $testConstraints($c) + } else { + return {} + } + } else { + set testConstraints($c) [lindex $args 0] + } + return + } + + namespace eval ::tcltest { + namespace export testConstraint + } + uplevel \#0 {namespace import -force ::tcltest::*} + } + + # ### ### ### ######### ######### ######### + ## Define a set of standard constraints + + ::tcltest::testConstraint tcl8.3only \ + [expr {![package vsatisfies [package provide Tcl] 8.4]}] + + ::tcltest::testConstraint tcl8.3plus \ + [expr {[package vsatisfies [package provide Tcl] 8.3]}] + + ::tcltest::testConstraint tcl8.4plus \ + [expr {[package vsatisfies [package provide Tcl] 8.4]}] + + ::tcltest::testConstraint tcl8.5plus \ + [expr {[package vsatisfies [package provide Tcl] 8.5]}] + + ::tcltest::testConstraint tcl8.6plus \ + [expr {[package vsatisfies [package provide Tcl] 8.6]}] + + ::tcltest::testConstraint tcl9 \ + [expr {[package vsatisfies [package provide Tcl] 9]}] + + ::tcltest::testConstraint tcl8.4minus \ + [expr {![package vsatisfies [package provide Tcl] 8.5]}] + + ::tcltest::testConstraint tcl8.5 \ + [expr { + [ tcltest::testConstraint tcl8.5plus] && + ![tcltest::testConstraint tcl8.6plus] + }] + + ::tcltest::testConstraint tcl8.4 \ + [expr { + [ tcltest::testConstraint tcl8.4plus] && + ![tcltest::testConstraint tcl8.5plus] + }] + + # ### ### ### ######### ######### ######### + ## Cross-version code for the generation of the error messages created + ## by Tcl procedures when called with the wrong number of arguments, + ## either too many, or not enough. + + if {[package vsatisfies [package provide Tcl] 8.6]} { + # 8.6+ + proc ::tcltest::wrongNumArgs {functionName argList missingIndex} { + if {[string match args [lindex $argList end]]} { + set argList [lreplace $argList end end ?arg ...?] + } + if {$argList != {}} {set argList " $argList"} + set msg "wrong # args: should be \"$functionName$argList\"" + return $msg + } + + proc ::tcltest::tooManyArgs {functionName argList} { + # create a different message for functions with no args + if {[llength $argList]} { + if {[string match args [lindex $argList end]]} { + set argList [lreplace $argList end end ?arg ...?] + } + set msg "wrong # args: should be \"$functionName $argList\"" + } else { + set msg "wrong # args: should be \"$functionName\"" + } + return $msg + } + } elseif {[package vsatisfies [package provide Tcl] 8.5]} { + # 8.5 + proc ::tcltest::wrongNumArgs {functionName argList missingIndex} { + if {[string match args [lindex $argList end]]} { + set argList [lreplace $argList end end ...] + } + if {$argList != {}} {set argList " $argList"} + set msg "wrong # args: should be \"$functionName$argList\"" + return $msg + } + + proc ::tcltest::tooManyArgs {functionName argList} { + # create a different message for functions with no args + if {[llength $argList]} { + if {[string match args [lindex $argList end]]} { + set argList [lreplace $argList end end ...] + } + set msg "wrong # args: should be \"$functionName $argList\"" + } else { + set msg "wrong # args: should be \"$functionName\"" + } + return $msg + } + } elseif {[package vsatisfies [package provide Tcl] 8.4]} { + # 8.4+ + proc ::tcltest::wrongNumArgs {functionName argList missingIndex} { + if {$argList != {}} {set argList " $argList"} + set msg "wrong # args: should be \"$functionName$argList\"" + return $msg + } + + proc ::tcltest::tooManyArgs {functionName argList} { + # create a different message for functions with no args + if {[llength $argList]} { + set msg "wrong # args: should be \"$functionName $argList\"" + } else { + set msg "wrong # args: should be \"$functionName\"" + } + return $msg + } + } else { + # 8.2+ + proc ::tcltest::wrongNumArgs {functionName argList missingIndex} { + set msg "no value given for parameter " + append msg "\"[lindex $argList $missingIndex]\" to " + append msg "\"$functionName\"" + return $msg + } + + proc ::tcltest::tooManyArgs {functionName argList} { + set msg "called \"$functionName\" with too many arguments" + return $msg + } + } + + # ### ### ### ######### ######### ######### + ## tclTest::makeFile result API changed for 2.0 + + if {![package vsatisfies [package provide tcltest] 2.0]} { + + # The 'makeFile' in Tcltest 1.0 returns a list of all the + # paths generated so far, whereas the 'makeFile' in 2.0+ + # returns only the path of the newly generated file. We + # standardize on the more useful behaviour of 2.0+. If 1.x is + # present we have to create an emulation layer to get the + # wanted result. + + # 1.0 is not fully correctly described. If the file was + # created before no list is returned at all. We force things + # by adding a line to the old procedure which makes the result + # unconditional (the name of the file/dir created). + + # The same change applies to 'makeDirectory' + + if {![llength [info commands ::tcltest::makeFile_1]]} { + # Marker first. + proc ::tcltest::makeFile_1 {args} {} + + # Extend procedures with command to return the required + # full name. + proc ::tcltest::makeFile {contents name} \ + [info body ::tcltest::makeFile]\n[list set fullName] + + proc ::tcltest::makeDirectory {name} \ + [info body ::tcltest::makeDirectory]\n[list set fullName] + + # Re-export + namespace eval ::tcltest { + namespace export makeFile makeDirectory + } + uplevel \#0 {namespace import -force ::tcltest::*} + } + } + + # ### ### ### ######### ######### ######### + ## Extended functionality, creation of binary temp. files. + ## Also creation of paths for temp. files + + proc ::tcltest::makeBinaryFile {data f} { + set path [makeFile {} $f] + set ch [open $path w] + fconfigure $ch -translation binary + puts -nonewline $ch $data + close $ch + return $path + } + + proc ::tcltest::tempPath {path} { + variable temporaryDirectory + return [file join $temporaryDirectory $path] + } + + namespace eval ::tcltest { + namespace export wrongNumArgs tooManyArgs + namespace export makeBinaryFile tempPath + } + uplevel \#0 {namespace import -force ::tcltest::*} + return +} + +# ### ### ### ######### ######### ######### +## Commands to load files from various locations within the local +## package, and the loading of local packages. None of them goes +## through the auto-loader, nor the regular package management, to +## avoid contamination of the testsuite by packages and code outside +## of the package under test. + +proc localcache-setup {} { + variable ::testutils::cache [selfPath tmp.[pid].[clock seconds]] + #puts "Cache assign $cache" + file mkdir $cache + critcl::cache $cache + critcl::fastuuid + return +} + +proc localPath {fname} { + return [file join $::tcltest::testsDirectory $fname] +} + +proc selfPath {fname} { + return [file join $::testutils::selfdir $fname] +} + +proc useLocalFile {fname} { + return [uplevel 1 [list source [localPath $fname]]] +} + +proc useSelfFile {fname} { + return [uplevel 1 [list source [selfPath $fname]]] +} + +proc use {fname pname args} { + set nsname ::$pname + if {[llength $args]} {set nsname [lindex $args 0]} + + package forget $pname + catch {namespace delete $nsname} + + if {[catch { + uplevel 1 [list useSelfFile $fname] + } msg]} { + puts " Aborting the tests found in \"[file tail [info script]]\"" + puts " Error in [file tail $fname]: $msg" + return -code error "" + } + + puts "$::testutils::tag [list $pname] [package present $pname]" + return +} + +proc useKeep {fname pname args} { + set nsname ::$pname + if {[llength $args]} {set nsname [lindex $args 0]} + + package forget $pname + + # Keep = Keep the existing namespace of the package. + # = Do not delete it. This is required if the + # namespace contains commands created by a + # binary package, like 'tcllibc'. They cannot + # be re-created. + ## + ## catch {namespace delete $nsname} + + if {[catch { + uplevel 1 [list useSelfFile $fname] + } msg]} { + puts " Aborting the tests found in \"[file tail [info script]]\"" + puts " Error in [file tail $fname]: $msg" + return -code error "" + } + + puts "$::testutils::tag [list $pname] [package present $pname]" + return +} + +proc useLocal {fname pname args} { + set nsname ::$pname + if {[llength $args]} {set nsname [lindex $args 0]} + + package forget $pname + catch {namespace delete $nsname} + + if {[catch { + uplevel 1 [list useLocalFile $fname] + } msg]} { + puts " Aborting the tests found in \"[file tail [info script]]\"" + puts " Error in [file tail $fname]: $msg" + return -code error "" + } + + puts "$::testutils::tag [list $pname] [package present $pname]" + return +} + +proc useLocalKeep {fname pname args} { + set nsname ::$pname + if {[llength $args]} {set nsname [lindex $args 0]} + + package forget $pname + + # Keep = Keep the existing namespace of the package. + # = Do not delete it. This is required if the + # namespace contains commands created by a + # binary package, like 'tcllibc'. They cannot + # be re-created. + ## + ## catch {namespace delete $nsname} + + if {[catch { + uplevel 1 [list useLocalFile $fname] + } msg]} { + puts " Aborting the tests found in \"[file tail [info script]]\"" + puts " Error in [file tail $fname]: $msg" + return -code error "" + } + + puts "$::testutils::tag [list $pname] [package present $pname]" + return +} + +proc useAccel {acc fname pname args} { + set use [expr {$acc ? "useKeep" : "use"}] + uplevel 1 [linsert $args 0 $use $fname $pname] +} + +proc support {script} { + InitializeTclTest + set ::testutils::tag "-" + if {[catch { + uplevel 1 $script + } msg]} { + set prefix "SETUP Error (Support): " + puts $prefix[join [split $::errorInfo \n] "\n$prefix"] + + return -code return + } + return +} + +proc testing {script} { + InitializeTclTest + set ::testutils::tag "*" + if {[catch { + uplevel 1 $script + } msg]} { + set prefix "SETUP Error (Testing): " + puts $prefix[join [split $::errorInfo \n] "\n$prefix"] + + return -code return + } + return +} + +# ### ### ### ######### ######### ######### +## General utilities + +# - dictsort - +# +# Sort a dictionary by its keys. I.e. reorder the contents of the +# dictionary so that in its list representation the keys are found in +# ascending alphabetical order. In other words, this command creates +# a canonical list representation of the input dictionary, suitable +# for direct comparison. +# +# Arguments: +# dict: The dictionary to sort. +# +# Result: +# The canonical representation of the dictionary. + +proc dictsort {dict} { + array set a $dict + set out [list] + foreach key [lsort [array names a]] { + lappend out $key $a($key) + } + return $out +} + +# ### ### ### ######### ######### ######### +## Putting strings together, if they cannot be expressed easily as one +## string due to quoting problems. + +proc cat {args} { + return [join $args ""] +} + +# ### ### ### ######### ######### ######### +## Mini-logging facility, can also be viewed as an accumulator for +## complex results. +# +# res! : clear accumulator. +# res+ : add arguments to accumulator. +# res? : query contents of accumulator. +# res?lines : query accumulator and format as +# multiple lines, one per list element. + +proc res! {} { + variable result {} + return +} + +proc res+ {args} { + variable result + lappend result $args + return +} + +proc res? {} { + variable result + return $result +} + +proc res?lines {} { + return [join [res?] \n] +} + +# ### ### ### ######### ######### ######### +## Helper commands to deal with packages +## which have multiple implementations, i.e. +## their pure Tcl base line and one or more +## accelerators. We are assuming a specific +## API for accessing the data about available +## accelerators, switching between them, etc. + +# == Assumed API == +# +# KnownImplementations -- +# Returns list of all known implementations. +# +# Implementations -- +# Returns list of activated implementations. +# A subset of 'KnownImplementations' +# +# Names -- +# Returns dict mapping all known implementations +# to human-readable strings for output during a +# test run +# +# LoadAccelerator accel -- +# Tries to make the implementation named +# 'accel' available for use. Result is boolean. +# True indicates a successful activation. +# +# SwitchTo accel -- +# Activate the implementation named 'accel'. +# The empty string disables all implementations. + +proc TestAccelInit {namespace} { + # Disable all implementations ... Base state. + ${namespace}::SwitchTo {} + + # List the implementations. + array set map [${namespace}::Names] + foreach e [${namespace}::KnownImplementations] { + if {[${namespace}::LoadAccelerator $e]} { + puts "> $map($e)" + } + } + return +} + +proc TestAccelDo {namespace var script} { + upvar 1 $var impl + foreach impl [${namespace}::Implementations] { + ${namespace}::SwitchTo $impl + uplevel 1 $script + } + return +} + +proc TestAccelExit {namespace} { + # Reset the system to a fully inactive state. + ${namespace}::SwitchTo {} + return +} + +# ### ### ### ######### ######### ######### +## + +proc TestFiles {pattern} { + if {[package vsatisfies [package provide Tcl] 8.3]} { + # 8.3+ -directory ok + set flist [glob -nocomplain -directory $::tcltest::testsDirectory $pattern] + } else { + # 8.2 or less, no -directory + set flist [glob -nocomplain [file join $::tcltest::testsDirectory $pattern]] + } + foreach f [lsort -dict $flist] { + uplevel 1 [list source $f] + } + return +} + +proc TestFilesGlob {pattern} { + if {[package vsatisfies [package provide Tcl] 8.3]} { + # 8.3+ -directory ok + set flist [glob -nocomplain -directory $::tcltest::testsDirectory $pattern] + } else { + # 8.2 or less, no -directory + set flist [glob -nocomplain [file join $::tcltest::testsDirectory $pattern]] + } + return [lsort -dict $flist] +} + +# ### ### ### ######### ######### ######### +## + +proc make-demo {name script} { + variable ::testutils::cache + set saved [info script] + set scache $cache + set cache {} + info script $name + critcl::meta name $name + critcl::config lines 0 + critcl::config keepsrc 1 + uplevel 1 $script + critcl::load + info script $saved + set cache $scache + return +} + +# ### ### ### ######### ######### ######### +## + +::testutils::SaveEnvironment + +# ### ### ### ######### ######### ######### +package provide testutils $testutils::version +puts "- testutils [package present testutils]" +return diff --git a/src/vfs/critcl.vfs/test/util_def.test b/src/vfs/critcl.vfs/test/util_def.test new file mode 100644 index 00000000..574ca4d7 --- /dev/null +++ b/src/vfs/critcl.vfs/test/util_def.test @@ -0,0 +1,100 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl_util_def.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + + useLocal lib/critcl/critcl.tcl critcl + + # Helper procedures + useLocalFile test/support/crit_utils.tcl +} +testing { + useLocal lib/critcl-util/util.tcl critcl::util +} + +overrides + +# ------------------------------------------------------------------------- +## util::def syntax + +test critcl-util-def-1.0.7 {util-def, wrong\#args, not enough} -constraints tcl9 -body { + critcl::util::def +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.0.6 {util-def, wrong\#args, not enough} -constraints tcl8.6plus -body { + critcl::util::def +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.0.5 {util-def, wrong\#args, not enough} -constraints tcl8.5 -body { + critcl::util::def +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.0.4 {util-def, wrong\#args, not enough} -constraints tcl8.4 -body { + critcl::util::def +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.1.7 {util-def, wrong\#args, not enough} -constraints tcl9 -body { + critcl::util::def C +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.1.6 {util-def, wrong\#args, not enough} -constraints tcl8.6plus -body { + critcl::util::def C +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.1.5 {util-def, wrong\#args, not enough} -constraints tcl8.5 -body { + critcl::util::def C +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.1.4 {util-def, wrong\#args, not enough} -constraints tcl8.4 -body { + critcl::util::def C +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.2.7 {util-def, wrong\#args, too many} -constraints tcl9 -body { + critcl::util::def C D V X +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.2.6 {util-def, wrong\#args, too many} -constraints tcl8.6plus -body { + critcl::util::def C D V X +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.2.5 {util-def, wrong\#args, too many} -constraints tcl8.5 -body { + critcl::util::def C D V X +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +test critcl-util-def-1.2.4 {util-def, wrong\#args, too many} -constraints tcl8.4 -body { + critcl::util::def C D V X +} -returnCodes error -result {wrong # args: should be "critcl::util::def configfile define ?value?"} + +# ------------------------------------------------------------------------- +## + +test critcl-util-def-2.0 {util-def} -setup { + set here [critcl::cache] + file mkdir $env(HOME)/.critcl-tests-[pid] + critcl::cache $env(HOME)/.critcl-tests-[pid] +} -body { + critcl::util::def C foo 333 + inspect C +} -cleanup { + critcl::cache $here + unset here + file delete -force $env(HOME)/.critcl-tests-[pid] +} -result [viewFile [localPath test/assets/def-2.0]] + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/critcl.vfs/test/util_undef.test b/src/vfs/critcl.vfs/test/util_undef.test new file mode 100644 index 00000000..63d075cf --- /dev/null +++ b/src/vfs/critcl.vfs/test/util_undef.test @@ -0,0 +1,64 @@ +# -*- tcl -*- +# ------------------------------------------------------------------------- +# critcl_util_undef.test +# ------------------------------------------------------------------------- + +source [file join [file dirname [info script]] support testutilities.tcl] + +testsNeedTcl 8.6 9 +testsNeedTcltest 2 + +support { + useLocal lib/stubs_container/container.tcl stubs::container + useLocal lib/stubs_reader/reader.tcl stubs::reader + useLocal lib/stubs_genframe/genframe.tcl stubs::gen + + useLocal lib/critcl/critcl.tcl critcl + + # Helper procedures + useLocalFile test/support/crit_utils.tcl +} +testing { + useLocal lib/critcl-util/util.tcl critcl::util +} + +overrides + +# ------------------------------------------------------------------------- +## util::undef syntax + +test critcl-util-undef-1.0 {util-undef, wrong\#args, not enough} -body { + critcl::util::undef +} -returnCodes error -result {wrong # args: should be "critcl::util::undef configfile define"} + +test critcl-util-undef-1.1 {util-undef, wrong\#args, not enough} -body { + critcl::util::undef C +} -returnCodes error -result {wrong # args: should be "critcl::util::undef configfile define"} + +test critcl-util-undef-1.2 {util-undef, wrong\#args, too many} -body { + critcl::util::undef C D X +} -returnCodes error -result {wrong # args: should be "critcl::util::undef configfile define"} + +# ------------------------------------------------------------------------- +## + +test critcl-util-undef-2.0 {util-undef} -setup { + set here [critcl::cache] + file mkdir $env(HOME)/.critcl-tests-[pid] + critcl::cache $env(HOME)/.critcl-tests-[pid] +} -body { + critcl::util::undef C foo + inspect C +} -cleanup { + critcl::cache $here + unset here + file delete -force $env(HOME)/.critcl-tests-[pid] +} -result [viewFile [localPath test/assets/undef-2.0]] + +# ------------------------------------------------------------------------- +testsuiteCleanup + +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/punk86.vfs/lib_tcl8/sqlite3.40.0/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/sqlite3.40.0/pkgIndex.tcl new file mode 100644 index 00000000..a94b1327 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/sqlite3.40.0/pkgIndex.tcl @@ -0,0 +1,12 @@ +# -*- tcl -*- +# Tcl package index file, version 1.1 +# +# Note sqlite*3* init specifically +# +if {[package vsatisfies [package provide Tcl] 9.0-]} { + package ifneeded sqlite3 3.40.0 \ + [list load [file join $dir tcl9sqlite3400.dll] Sqlite3] +} else { + package ifneeded sqlite3 3.40.0 \ + [list load [file join $dir sqlite3400.dll] Sqlite3] +} diff --git a/src/vfs/punk86.vfs/lib_tcl8/sqlite3.40.0/sqlite3400.dll b/src/vfs/punk86.vfs/lib_tcl8/sqlite3.40.0/sqlite3400.dll new file mode 100644 index 00000000..a57ed2eb Binary files /dev/null and b/src/vfs/punk86.vfs/lib_tcl8/sqlite3.40.0/sqlite3400.dll differ diff --git a/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/csv.tcl b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/csv.tcl new file mode 100644 index 00000000..4d3bd55d --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/csv.tcl @@ -0,0 +1,366 @@ +# +# Copyright (c) 2015, Ashok P. Nadkarni +# All rights reserved. +# +# See the file license.terms for license +# + +namespace eval tclcsv { + variable script_dir + set script_dir [file dirname [info script]] +} + +# Like _sniff above but only considers delimiters +proc tclcsv::_sniff {chan delimiters} { + set seek_pos [chan tell $chan] + if {$seek_pos == -1} { + error "Channel is not seekable" + } + + # TBD - what if delimiters or quotes is empty? + # TBD - what if no rows ? + + set escapes [list \\ ""] + set quotes [list \" '] + set combinations {} + foreach delimiter $delimiters { + unset -nocomplain width_frequencies + try { + set nrows 0 + while {[gets $chan line] >= 0} { + if {$line eq ""} continue + set row [split $line $delimiter] + set n [llength $row] + incr width_frequencies($n) + incr nrows + if {$nrows > 100} break + } + } finally { + chan seek $chan $seek_pos + } + if {![info exists width_frequencies]} continue + set sorted_frequencies [lsort -stride 2 -decreasing -integer -index 1 [array get width_frequencies]] + set mode [lindex $sorted_frequencies 0] + # Fraction of the occurences where the mode frequency occurs + set mode_frac [expr {[lindex $sorted_frequencies 1] / double($nrows)}] + lappend combinations [list $delimiter $mode $mode_frac] + } + + # Sort the candidates such that + # - those where the mode fraction is higher are preferred under + # the assumption that the more lines that have the same number + # of occurences of that character, the greater the likelihood + # that character is the delimiter + # - those where the mode is higher is preferred under the assumption + # that greater occurences of a character within a line are + # less likely to be by chance + set comparator { + {a b} { + lassign $a adelim amode afrac + lassign $b bdelim bmode bfrac + + #return [expr {(sqrt($amode)*$afrac) > (sqrt($bmode)*$bfrac)}] + set aweight [expr {(sqrt($amode)*$afrac)}] + set bweight [expr {(sqrt($bmode)*$bfrac)}] + if {$aweight > $bweight} { + return 1 + } elseif {$aweight < $bweight} { + return -1 + } else { + return 0 + } + } + } + set winner [lindex [lsort -decreasing -command [list apply $comparator] $combinations] 0] + set delimiter [lindex $winner 0] + set nfields [lindex $winner 1] + + # We have picked a delimiter. Now figure out whether + # quotes are in use. By default " is assumed to be the quote char + # If we find sufficient number of fields beginning with and ending + # with ' then we assume that is the quote character. + # Along the way we also check if + # - initial spaces are to be skipped + # - quotes are doubled + # - an escape character is in use + # - comment character + try { + set nrows 0 + while {[gets $chan line] >= 0} { + if {$line eq ""} continue + set row [split $line $delimiter] + set n [llength $row] + if {$n == $nfields} { + lappend good $row + } elseif {$n < $nfields} { + lappend short $row + } else { + lappend long $row + } + incr nrows + if {$nrows > 100} break + } + set ngood [llength $good] + if {$ngood == 0} { + error "Failed to find lines with expected number of fields" + } + foreach row $good { + set findex 0 + set doublequotecount 0 + set singlequotecount 0 + foreach field $row { + # Check for quotes + if {[regexp {^\s*".*"$} $field]} { + incr doublequotecount + } elseif {[regexp {^\s*'.*'$} $field]} { + incr singlequotecount + } + # Keep track of leading spaces per column + if {[string index $field 0] eq " "} { + incr nspaces($findex) + } + incr findex + } + if {$singlequotecount > $doublequotecount} { + set quotechar ' + } else { + # Note even though double quote is the default do not + # explicitly mark as such unless we have actually seen it + if {$doublequotecount > 0} { + set quotechar \" + } + } + } + + # Check if quotes are doubled + if {[info exists quotechar]} { + set ch $quotechar + } else { + set ch \"; # Default quote char + } + + foreach row $good { + foreach field $row { + # TBD - how to check if quotes are doubled? + if {[regexp "\\s*${ch}\[^${ch}\]*${ch}${ch}" $field]} { + incr doublequote + } elseif {[regexp "\\s*${ch}\[^${ch}\]*(\[^\[:alnum:\]\])${ch}" $field -> esc]} { + incr esc_chars($esc) + } + } + if {(![info exists doublequote]) && [info exists esc_chars]} { + set esc_list [lsort -decreasing -integer -stride 2 -index 1 [array get esc_chars]] + set escape [lindex $esc_list 0] + } + } + + # If every column that had a field beginning with a space also + # had all fields in that column beginning with a space then + # we assume leading spaces are to be skipped. + if {[info exists nspaces]} { + set skipleadingspace 1 + foreach {col space_count} [array get nspaces] { + if {$space_count != $ngood} { + set skipleadingspace 0 + break + } + } + } + # If the bulk of short lines begin with the same character, + # assume it is the comment character + if {[info exists short]} { + foreach row $short { + set line [string trim [join $row $delimiter]] + incr comment([string index $line 0]) + } + set nshort [llength $short] + foreach {ch count} [array get comment] { + if {[expr {double($count)/$nshort}] > 0.8} { + set commentchar $ch + break + } + } + } + + # TBD - perhaps long lines can also be used since long lines + # can result from delimiters embedded within quotes + + } finally { + chan seek $chan $seek_pos + } + + set dialect [list -delimiter $delimiter] + if {[info exists skipleadingspace]} { + lappend dialect -skipleadingspace $skipleadingspace + } + if {[info exists quotechar]} { + lappend dialect -quote $quotechar + } + if {[info exists commentchar]} { + lappend dialect -comment $commentchar + } + if {[info exists doublequote]} { + lappend dialect -doublequote 1 + } else { + if {[info exists escape]} { + lappend dialect -escape $escape + } + } + + + return $dialect +} + +proc tclcsv::sniff_header {args} { + if {[llength $args] == 0} { + error "wrong # args: should be \"sniff_header ?options? channel\"" + } + set chan [lindex $args end] + + set seek_pos [chan tell $chan] + if {$seek_pos == -1} { + error "Channel is not seekable" + } + + try { + set rows [csv_read {*}[lrange $args 0 end-1] -nrows 100 $chan] + if {[llength $rows] < 2} { + error "Insufficient rows in CSV data to sniff headers." + } + set width [llength [lindex $rows 0]] + set types {} + for {set findex 0} {$findex < $width} {incr findex} { + dict set types $findex type unknown + dict set types $findex length [string length [lindex $rows 1 $findex]] + } + foreach row [lrange $rows 1 end] { + if {[llength $row] != $width} continue + for {set findex 0} {$findex < $width} {incr findex} { + set val [lindex $row $findex] + if {[string length $val] != [dict get $types $findex length]} { + dict set types $findex length -1 + } + set field_type [dict get $types $findex type] + if {$field_type eq "string"} continue + # Note values starting with 0 treated as strings (eg. zip codes) + # Exceptions are 0 and 0.something + if {[string index $val 0] eq "0" && + [string length $val] > 1 && + [string index $val 1] ne "."} { + dict set types $findex type string + continue + } + if {$field_type eq "real"} { + if {![string is double -strict $val]} { + dict set types $findex type string + } + continue + } + # field_type is integer or unknown. Our check for + # integer is not [string is wide] because we want to + # treat as decimal numbers and not parse as octals or hex + if {[regexp {^\d+$} $val]} { + dict set types $findex type integer + } elseif {[string is double -strict $val]} { + dict set types $findex type real + } else { + dict set types $findex type string + } + } + } + } finally { + chan seek $chan $seek_pos + } + + # If we could determine that any one column was a non-string type + # (integer or real) but the header field for that column is not + # of that type, we immediately conclude the first row is a header. + # In addition, in the case of columns that are of fixed width, + # we take a vote, where every time the field in first row of the + # fixed width column is of a different width we raise the probability + # of header existence and if of the same width, we lower the probability. + set probably_header 0 + set row [lindex $rows 0] + for {set findex 0} {$findex < $width} {incr findex} { + set field [lindex $row $findex] + set type [dict get $types $findex type] + if {($type eq "integer" && ![string is wide -strict $field]) || + ($type eq "real" && ![string is double -strict $field]) + } { + # The type of the first row field is different. Assume header + set probably_header 1 + break + } + set len [dict get $types $findex length] + if {$len >= 0} { + if {$len == [string length $field]} { + incr probably_header -1 + } else { + incr probably_header 1 + } + } + } + + set field_types {} + for {set findex 0} {$findex < $width} {incr findex} { + set type [dict get $types $findex type] + # $type can be unknown if the loop above did a continue right + # at the top for every line + if {$type eq "unknown"} { + set type string + } + lappend field_types $type + } + + if {$probably_header > 0} { + return [list $field_types $row] + } else { + return [list $field_types] + } +} + +proc tclcsv::dialect {dialect {direction read}} { + variable dialects + set dialects [dict create] + dict set dialects excel [list \ + -delimiter , \ + -quote \" \ + -doublequote 1 \ + -skipleadingspace 0] + dict set dialects excel-tab [dict merge [dict get $dialects excel] [list -delimiter \t]] + proc [namespace current]::dialect {dialect {direction read}} { + variable dialects + set opts [dict get $dialects $dialect] + if {$direction eq "write"} { + # Remove options not understood by writes + dict unset opts -skipleadingspace + } + return $opts + } + return [dialect $dialect $direction] +} + +proc tclcsv::sniff {args} { + if {[llength $args] == 0} { + error "wrong # args: should be \"sniff ?options? channel\"" + } + set chan [lindex $args end] + + array set opts [dict merge [dict create \ + -delimiters [list "," ";" ":" "\t"] \ + ] \ + [lrange $args 0 end-1]] + + return [_sniff $chan $opts(-delimiters)] +} + +proc tclcsv::dialectpicker args { + variable script_dir + uplevel #0 {package require Tk; package require snit} + uplevel #0 [list source [file join $script_dir widgets.tcl]] + uplevel 1 tclcsv::dialectpicker $args +} + +namespace eval tclcsv { + namespace export csv_read csv_write sniff sniff_header dialect +} diff --git a/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/pkgIndex.tcl new file mode 100644 index 00000000..718878cc --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/pkgIndex.tcl @@ -0,0 +1,6 @@ +# +# Tcl package index file +# +package ifneeded tclcsv 2.3 \ + "[list load [file join $dir tclcsv23.dll] tclcsv] ; + [list source [file join $dir csv.tcl]]" diff --git a/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/tclcsv23.dll b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/tclcsv23.dll new file mode 100644 index 00000000..f46c1c81 Binary files /dev/null and b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/tclcsv23.dll differ diff --git a/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/widgets.tcl b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/widgets.tcl new file mode 100644 index 00000000..33c8b210 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tclcsv2.3/widgets.tcl @@ -0,0 +1,890 @@ +# +# Copyright (c) 2015, Ashok P. Nadkarni +# All rights reserved. +# +# See the file license.terms for license +# + +package require msgcat + +namespace eval tclcsv { + namespace import ::msgcat::* + # critcl TEA install does not copy message files. So for now + # keep root strings here. + ::msgcat::mcmset "" { + encoding_l "Character encoding" + + header_line_l "First line contains a header" + skip_empty_l "Skip lines that are empty" + quote_doubled_l "Quotes are represented by doubling" + ignore_leading_space_l "Ignore leading space in fields" + + delimiter_char_l Delimiter + comment_char_l "Comment character" + quote_char_l "Quote character" + escape_char_l "Escape character" + + none_l None + space_l Space + tab_l Tab + hash_l "Hash (#)" + semicolon_l "Semicolon (;)" + comma_l Comma + dquote_l "Double quote (\")" + squote_l "Single quote (')" + backslash_l "Backslash (\)" + other_l Other + + include_l Include + heading_l Heading + type_l Type + } +} +# TBD ::msgcat::mcload [file join [file dirname [info script]] msgs] + +namespace eval tclcsv::sframe { + # sframe.tcl - from http://wiki.tcl.tk/9223 + # Paul Walton + # Create a ttk-compatible, scrollable frame widget. + # Usage: + # sframe new ?-toplevel true? ?-anchor nsew? + # -> + # + # sframe content + # -> + + namespace ensemble create + namespace export * + + # Create a scrollable frame or window. + proc new {path args} { + # Use the ttk theme's background for the canvas and toplevel + set bg [ttk::style lookup TFrame -background] + if { [ttk::style theme use] eq "aqua" } { + # Use a specific color on the aqua theme as 'ttk::style lookup' is not accurate. + set bg "#e9e9e9" + } + + # Create the main frame or toplevel. + if { [dict exists $args -toplevel] && [dict get $args -toplevel] } { + toplevel $path -bg $bg + } else { + ttk::frame $path + } + + # Create a scrollable canvas with scrollbars which will always be the same size as the main frame. + set canvas [canvas $path.canvas -bg $bg -bd 0 -highlightthickness 0 -yscrollcommand [list $path.scrolly set] -xscrollcommand [list $path.scrollx set]] + ttk::scrollbar $path.scrolly -orient vertical -command [list $canvas yview] + ttk::scrollbar $path.scrollx -orient horizontal -command [list $canvas xview] + + # Create a container frame which will always be the same size as the canvas or content, whichever is greater. + # This allows the child content frame to be properly packed and also is a surefire way to use the proper ttk background. + set container [ttk::frame $canvas.container] + pack propagate $container 0 + + # Create the content frame. Its size will be determined by its contents. This is useful for determining if the + # scrollbars need to be shown. + set content [ttk::frame $container.content] + + # Pack the content frame and place the container as a canvas item. + set anchor "n" + if { [dict exists $args -anchor] } { + set anchor [dict get $args -anchor] + } + pack $content -anchor $anchor + $canvas create window 0 0 -window $container -anchor nw + + # Grid the scrollable canvas sans scrollbars within the main frame. + grid $canvas -row 0 -column 0 -sticky nsew + grid rowconfigure $path 0 -weight 1 + grid columnconfigure $path 0 -weight 1 + + # Make adjustments when the sframe is resized or the contents change size. + bind $path.canvas [list [namespace current]::resize $path] + + # Mousewheel bindings for scrolling. + bind [winfo toplevel $path] [list +[namespace current] scroll $path yview %W %D] + bind [winfo toplevel $path] [list +[namespace current] scroll $path xview %W %D] + + return $path + } + + + # Given the toplevel path of an sframe widget, return the path of the child frame suitable for content. + proc content {path} { + return $path.canvas.container.content + } + + + # Make adjustments when the the sframe is resized or the contents change size. + proc resize {path} { + set canvas $path.canvas + set container $canvas.container + set content $container.content + + # Set the size of the container. At a minimum use the same width & height as the canvas. + set width [winfo width $canvas] + set height [winfo height $canvas] + + # If the requested width or height of the content frame is greater then use that width or height. + if { [winfo reqwidth $content] > $width } { + set width [winfo reqwidth $content] + } + if { [winfo reqheight $content] > $height } { + set height [winfo reqheight $content] + } + $container configure -width $width -height $height + + # Configure the canvas's scroll region to match the height and width of the container. + $canvas configure -scrollregion [list 0 0 $width $height] + + # Show or hide the scrollbars as necessary. + # Horizontal scrolling. + if { [winfo reqwidth $content] > [winfo width $canvas] } { + grid $path.scrollx -row 1 -column 0 -sticky ew + } else { + grid forget $path.scrollx + } + # Vertical scrolling. + if { [winfo reqheight $content] > [winfo height $canvas] } { + grid $path.scrolly -row 0 -column 1 -sticky ns + } else { + grid forget $path.scrolly + } + return + } + + + # Handle mousewheel scrolling. + proc scroll {path view W D} { + if { [winfo exists $path.canvas] && [string match $path.canvas* $W] } { + $path.canvas $view scroll [expr {-$D}] units + } + return + } +} + +#------------------------------------------------------------------------------ +# Copied from Csaba Nemethi's tablelist package +# tablelist::strRange +# +# Gets the largest initial (for alignment = left or center) or final (for +# alignment = right) range of characters from str whose width, when displayed +# in the given font, is no greater than pixels decremented by the width of +# snipStr. Returns a string obtained from this substring by appending (for +# alignment = left or center) or prepending (for alignment = right) (part of) +# snipStr to it. +#------------------------------------------------------------------------------ +proc tclcsv::fit_text {win str font pixels alignment snipStr} { + if {$pixels < 0} { + return "" + } + + set width [font measure $font -displayof $win $str] + if {$width <= $pixels} { + return $str + } + + set snipWidth [font measure $font -displayof $win $snipStr] + if {$pixels <= $snipWidth} { + set str $snipStr + set snipStr "" + } else { + incr pixels -$snipWidth + } + + if {[string compare $alignment "right"] == 0} { + set idx [expr {[string length $str]*($width - $pixels)/$width}] + set subStr [string range $str $idx end] + set width [font measure $font -displayof $win $subStr] + if {$width < $pixels} { + while 1 { + incr idx -1 + set subStr [string range $str $idx end] + set width [font measure $font -displayof $win $subStr] + if {$width > $pixels} { + incr idx + set subStr [string range $str $idx end] + return $snipStr$subStr + } elseif {$width == $pixels} { + return $snipStr$subStr + } + } + } elseif {$width == $pixels} { + return $snipStr$subStr + } else { + while 1 { + incr idx + set subStr [string range $str $idx end] + set width [font measure $font -displayof $win $subStr] + if {$width <= $pixels} { + return $snipStr$subStr + } + } + } + + } else { + set idx [expr {[string length $str]*$pixels/$width - 1}] + set subStr [string range $str 0 $idx] + set width [font measure $font -displayof $win $subStr] + if {$width < $pixels} { + while 1 { + incr idx + set subStr [string range $str 0 $idx] + set width [font measure $font -displayof $win $subStr] + if {$width > $pixels} { + incr idx -1 + set subStr [string range $str 0 $idx] + return $subStr$snipStr + } elseif {$width == $pixels} { + return $subStr$snipStr + } + } + } elseif {$width == $pixels} { + return $subStr$snipStr + } else { + while 1 { + incr idx -1 + set subStr [string range $str 0 $idx] + set width [font measure $font -displayof $win $subStr] + if {$width <= $pixels} { + return $subStr$snipStr + } + } + } + } +} + +# +# And finally, my own code + +# format text in a label, truncating and adding ellipsis as necessary. +# Also show "" as for better visual display +proc tclcsv::format_label {win text {align left} {font TkDefaultFont}} { + # Window has not been mapped yet. + if {$text eq ""} { + set text + } + set nchars [string length $text] + if {$nchars > 10} { + set nchars 10 + set width [font measure $font -displayof $win [string repeat a $nchars]] + set text [fit_text $win $text $font $width $align \u2026]; # Ellipsis + } + $win configure -text $text +} + +# A megawidget to permit various options for parsing CSV to be configured +snit::widget tclcsv::dialectpicker { + hulltype ttk::frame + + # + # Options related to parsing the CSV. These can be specified by the + # caller to initialize the settings for reading CSV data. They can + # then be changed interactively by the user through the various + # displayed widgets which are attached to them via -textvariable or + # -variable + + # File encoding + option -encoding -default utf-8 -readonly 1 -configuremethod SetOptEncoding + + # Special character settings + option -delimiter -default \t -configuremethod SetOptDelimiter -readonly 1 + option -comment -default "" -configuremethod SetOptCharPicker -readonly 1 + option -escape -default "" -configuremethod SetOptCharPicker -readonly 1 + option -quote -default \" -configuremethod SetOptCharPicker -readonly 1 + # Holds the "Other" entry content for specifying special characters + # Array indexed by option + variable _other; # Array contents of "Other" entry boxes indexed by option + + option -skipblanklines -default 1 -readonly 1 + option -skipleadingspace -default 0 -readonly 1 + option -doublequote -default 1 -readonly 1 + option -headerpresent -default 0 -readonly 1 + + # + # The three main data frames containing the options, the special + # character configuration and the sample data + variable _optf; # Option frame + variable _charf; # Character picker frame + variable _dataf; # Data frame + + + # If specified, the column metadata widgets are displayed + # (name, type etc.). The value must be a dictionary keyed by a + # data type token, with nested keys align and display (both optional) + option -columntypes -default "" -readonly 1 -configuremethod SetOptColumnTypes + # Array mapping display strings to column type tokens + variable _column_type_display_to_token + + # Stores display strings of column types. Array indexed by col number + variable _column_type_display_strings + + # Stores information whether a column is included or not and column heading, + # Only used if caller specified the -columntypes option + # Arrays indexed by column number + variable _included_columns + variable _column_headings + + # Store state information about the channel we are reading from + # path - path to file - ONLY PRESENT IF PASSED IN PATH INSTEAD OF CHANNEL + # name - channel name + # original_position - original seek position + # original_encoding - encoding to be restored + variable _channel + + variable _max_data_lines 6; # How many sample lines to read + variable _num_data_lines; # Number actually read + variable _data_grid_first_data_row; # First row that contains actual values + variable _data_grid_first_data_col; # First col that contains actual values + + constructor {args} { + if {[llength $args] == 0} { + error "wrong # args: should be \"dialectpicker ?options? channel\"" + } + set chan [lindex $args end] + set args [lrange $args 0 end-1] + + $hull configure -borderwidth 0 + + array set _included_columns {} + + # Init channel and remember original settings for restoring in + # destructor + $self ChanInit $chan + + # The three main frames + set _optf [ttk::frame $win.f-opt -padding 4] + set _charf [ttk::frame $win.f-char] + set _dataf [tclcsv::sframe new $win.f-data -anchor w] + + # File character encoding + ttk::frame $_optf.f-encoding + ttk::label $_optf.f-encoding.l -text [mc encoding_l] + ttk::combobox $_optf.f-encoding.cb -textvariable [myvar options(-encoding)] -values [lsort [encoding names]] -state readonly + bind $_optf.f-encoding.cb <> [mymethod Redisplay] + pack $_optf.f-encoding.l $_optf.f-encoding.cb -side left -fill both -expand n + # Data processing objects + foreach {opt text} { + -headerpresent header_line_l + -doublequote quote_doubled_l + -skipblanklines skip_empty_l + -skipleadingspace ignore_leading_space_l + } { + ttk::checkbutton $_optf.cb$opt -variable [myvar options($opt)] -text [mc $text] -command [mymethod Redisplay] + } + + # Delimiter selection + set delimiterf [$self MakeCharPickerFrame -delimiter delimiter_char_l \ + [list tab_l \t space_l { } comma_l , semicolon_l ";"] \ + \t] + + # Comment char + set commentf [$self MakeCharPickerFrame -comment comment_char_l \ + [list none_l "" hash_l "#"]] + + # Quote char + set quotef [$self MakeCharPickerFrame -quote quote_char_l \ + [list none_l "" dquote_l "\"" squote_l "'"] \"] + + # Escape char + set escapef [$self MakeCharPickerFrame -escape escape_char_l \ + [list none_l "" backslash_l "\\"]] + + # Start laying out the widgets + + # Options + grid $_optf.f-encoding - -sticky ew + grid $_optf.cb-headerpresent $_optf.cb-skipblanklines -sticky ew + grid $_optf.cb-doublequote $_optf.cb-skipleadingspace -sticky ew + grid columnconfigure $_optf all -weight 1 -uniform width + + pack $_optf -fill none -expand n -pady 4 -anchor w + + # Special characters + grid $delimiterf $commentf $quotef $escapef -padx 2 -pady 2 -sticky news + grid columnconfigure $_charf all -uniform width -weight 1 + pack $_charf -fill none -expand n -pady 4 -anchor w + + # Sample data frame + pack [ttk::separator $win.sep] -fill x -expand n -pady 4 + pack $_dataf -fill both -expand y -anchor nw + + $self configurelist $args + + $self Redisplay + } + + destructor { + # Restore channel to its initial state if it is still open + if {[info exists _channel(name)] && + $_channel(name) in [chan names]} { + if {[info exists _channel(path)]} { + # We opened the channel ourselves so close it. + close $_channel(name) + } else { + chan configure $_channel(name) -encoding $_channel(original_encoding) + chan seek $_channel(name) $_channel(original_position) + } + } + } + + # -columntypes option handler + method SetOptColumnTypes {opt val} { + # Make sure the types returned by sniff_header are included + if {![dict exists $val string]} { + dict set val string {display String align left} + } + if {![dict exists $val real]} { + dict set val real {display {Real number} align right} + } + if {![dict exists $val integer]} { + dict set val integer {display Integer align right} + } + set options(-columntypes) $val + + dict for {tok meta} $options(-columntypes) { + # Fill in any display strings that are not set + if {![dict exists $meta display] || + [dict get $meta display] eq ""} { + dict set options(-columntypes) $tok display $tok + } + # Likewise, fill in alignment + if {![dict exists $meta align] || + [dict get $meta align] ni {left right center centre}} { + dict set options(-columntypes) $tok align left + } + + # Build map of display strings to tokens + set _column_type_display_to_token([dict get $options(-columntypes) $tok display]) $tok + } + } + + # -encoding handler + method SetOptEncoding {opt val} { + if {$val ni [encoding names]} { + error "Unknown encoding \"$val\"." + } + set options($opt) $val + $_optf.cb-encoding set $options(-encoding) + } + + # -delimiter handler. Unlike other special characters this cannot be "" + method SetOptDelimiter {opt val} { + if {[string length $val] != 1} { + error "Invalid value for option $opt. Must be a single character." + } + if {$val in [list \t { } "," ";"]} { + set options($opt) $val + } else { + set _other($opt) $val + set options($opt) "other" + } + } + + # Handler for special character related option. + method SetOptCharPicker {opt val} { + if {[string length $val] > 1} { + error "Invalid value for option $opt. Must be a single character or the empty string." + } + set predefs [dict create \ + -comment [list # ""] \ + -quote [list \" ' ""] \ + -escape [list \\ ""]] + if {$val in [dict get $predefs $opt]} { + set options($opt) $val + } else { + set _other($opt) $val + set options($opt) "other" + } + } + + # Creates a "Other" entry widget $e that enforces max one character + # and is tied to a set of radio buttons + # $opt is the associated option. + method MakeCharPickerEntry {opt {default_rb_value {}}} { + set e $_charf.f${opt}.e-other + ttk::entry $e -textvariable [myvar _other($opt)] -width 2 -validate all -validatecommand [mymethod ValidateCharPickerEntry %d $opt %s %P $default_rb_value] + return $e + } + + # Validation callback for the "Other" entry fields. Ensures no more + # than one char and also configures radio buttons based on content + method ValidateCharPickerEntry {validation_type opt old new {default_rb_value {}}} { + if {$validation_type == -1} { + # Revalidation + } else { + # Prevalidation + # Don't allow more than one char in field + if {[string length $new] > 1} { + return 0 + } + } + if {[string length $new] == 0} { + if {$options($opt) eq "other"} { + # "Other" radio selected and empty field, reset radio button + # We used to reset to the default button but that does not work + # well when changing the content of the Other entry field + if {0} { + set options($opt) $default_rb_value + } + } + } else { + set options($opt) "other" + } + after idle after 0 [mymethod Redisplay] + return 1 + } + + # Make a labelled frame containing the radiobuttons for selecting + # characters used for special purposes. + method MakeCharPickerFrame {opt title rblist {default_rb_value {}}} { + set f [ttk::labelframe $_charf.f$opt -text [mc $title]] + set rbi -1 + foreach {label value} $rblist { + set w [ttk::radiobutton $f.rb[incr rbi] -text [mc $label] -value $value -variable [myvar options($opt)] -command [mymethod Redisplay]] + grid $w - -sticky ew + } + set w [ttk::radiobutton $f.rb-other -text Other -value "other" -variable [myvar options($opt)] -command [mymethod Redisplay]] + set e [$self MakeCharPickerEntry $opt $default_rb_value] + grid $w $e -sticky w + grid columnconfigure $f all -uniform width + return $f + } + + # Called when entire display has to be redone, for example when the + # delimiter is changed + method Redisplay {} { + if {$options(-delimiter) eq "other" && + (![info exists _other(-delimiter)] || $_other(-delimiter) eq "")} { + focus $_charf.f-delimiter.e-other + return + } + + set rows [$self ChanRead] + set nrows [llength $rows] + # Find the max number of columns + set ncols 0 + foreach row $rows { + if {[llength $row] > $ncols} { + set ncols [llength $row] + } + } + set f [tclcsv::sframe content $_dataf] + destroy {*}[winfo children $f] + array unset _included_columns * + + if {$nrows == 0 || $ncols == 0} { + grid [ttk::label $f.l-nodata -text "No data to display"] -sticky nw + return + } + + if {[dict size $options(-columntypes)]} { + set _data_grid_first_data_row 4 + set _data_grid_first_data_col 1 + grid [ttk::label $f.l-colname -text [mc heading_l]] -sticky ew -padx 1 -row 1 -column 0 + grid [ttk::label $f.l-coltype -text [mc type_l]] -sticky ew -padx 1 -row 2 -column 0 + grid [ttk::separator $f.sep-0 -orient horizontal] -sticky ew -padx 1 -row 3 -column 0 -pady 4 + } else { + set _data_grid_first_data_row 2 + set _data_grid_first_data_col 0 + } + set grid_col $_data_grid_first_data_col + set type_display_strings [$self ColumnTypeDisplayStrings] + for {set j 0} {$j < $ncols} {incr j; incr grid_col} { + # Widget for whether to include the column when reading data + set _included_columns($j) 1 + set cb [ttk::checkbutton $f.cb-colinc-$j -text [mc include_l] -variable [myvar _included_columns($j)] -command [mymethod IncludeColumn $j]] + grid $cb -sticky ew -padx 1 -row 0 -column $grid_col + + if {[dict size $options(-columntypes)]} { + # Entry boxes for column heading + set e [ttk::entry $f.e-heading-$j -textvariable [myvar _column_headings($j)]] + grid $e -sticky ew -padx 1 -row 1 -column $grid_col + + # Widget for specifying type of the column (for alignment) + set combo [ttk::combobox $f.cb-type-$j -width 8 -textvariable [myvar _column_type_display_strings($j)] -values $type_display_strings -state readonly] + bind $combo <> [mymethod ChangeColumnType $j] + grid $combo -sticky ew -padx 1 -row 2 -column $grid_col + + } + # Separate the meta fields from data + grid [ttk::separator $f.sep-$grid_col -orient horizontal] -sticky ew -padx 1 -row [expr {$_data_grid_first_data_row-1}] -column $grid_col -pady 4 + } + + # grid_row tracks the row in the display widget + # i tracks the data row index + set grid_row $_data_grid_first_data_row + set grid_col $_data_grid_first_data_col + set i 0 + if {$options(-headerpresent)} { + # If we are displaying the column metadata, the header + # (or its substitute) is displayed there so won't display it here. + # Instead fill in the column meta header entries if they are + # not defined or are empty. + if {[dict size $options(-columntypes)]} { + for {set j 0} {$j < $ncols} {incr j; incr grid_col} { + if {![info exists _column_headings($j)] || + $_column_headings($j) eq ""} { + set _column_headings($j) [lindex $rows $i $j] + } + } + } else { + for {set j 0} {$j < $ncols} {incr j; incr grid_col} { + set l [ttk::label $f.l-$grid_row-$j -font [list {*}[font configure TkDefaultFont] -weight bold]] + tclcsv::format_label $l [lindex $rows $i $j] + grid $l -row $grid_row -column $grid_col -sticky ew -padx 1 + } + incr grid_row + } + incr i; # Skip first line of data + } + for {} {$i < $nrows} {incr i; incr grid_row} { + set grid_col $_data_grid_first_data_col + for {set j 0} {$j < $ncols} {incr j; incr grid_col} { + if {[$self ColumnAlignment $j] eq "right"} { + set anchor e + } else { + set anchor w + } + set l [ttk::label $f.l-$grid_row-$j -background white -anchor $anchor] + tclcsv::format_label $l [lindex $rows $i $j] + grid $l -row $grid_row -column $grid_col -sticky ew -padx 1 + } + } + after 0 after idle [list tclcsv::sframe resize $_dataf] + return + } + + method DataGridRowIndexStart {} { + return $_data_grid_first_data_row + } + + method DataGridRowIndexLimit {} { + # The last data grid row depends on whether a header is marked + # present and if it is displayed as part of column metadata + # in the "Heading" line + set first [$self DataGridRowIndexStart] + set limit [expr {$first + $_num_data_lines}] + if {[dict size $options(-columntypes)] && $options(-headerpresent)} { + incr limit -1 + } + return $limit + } + + # Handler when user clicks on the include column checkboxes + method IncludeColumn {ci} { + set f [tclcsv::sframe content $_dataf] + set ri [$self DataGridRowIndexStart] + set limit [$self DataGridRowIndexLimit] + if {$_included_columns($ci)} { + while {$ri < $limit} { + $f.l-$ri-$ci configure -state enabled + incr ri + } + } else { + while {$ri < $limit} { + $f.l-$ri-$ci configure -state disabled + incr ri + } + } + return + } + + # Handler for changing a column's type. Changes the sample alignment + method ChangeColumnType {ci} { + set f [tclcsv::sframe content $_dataf] + set ri [$self DataGridRowIndexStart] + set limit [$self DataGridRowIndexLimit] + if {[$self ColumnAlignment $ci] eq "right"} { + set anchor e + } else { + set anchor w + } + while {$ri < $limit} { + $f.l-$ri-$ci configure -anchor $anchor + incr ri + } + return + } + + # Constructs the list of display strings corresponding to column + # type tokens. + method ColumnTypeDisplayStrings {} { + set l {} + # Note we do not just get the keys from _column_type_display_to_token + # because that would be in random order + dict for {key meta} $options(-columntypes) { + lappend l [dict get $meta display] + } + return $l + } + + # Returns the alignment for a column (left or right) + method ColumnAlignment {ci} { + if {[info exists _column_type_display_strings($ci)]} { + set display $_column_type_display_strings($ci) + set coltype $_column_type_display_to_token($display) + return [dict get $options(-columntypes) $coltype align] + } + return "left" + } + + # Save the channel settings and initialize it. Sniffs likely + # CSV format + method ChanInit {chan} { + # See if we were passed in a channel or a path + if {$chan ni [chan names]} { + # Not a channel. Presume it is a file. + set _channel(path) $chan + set chan [open $chan r] + } + + set _channel(original_encoding) [chan configure $chan -encoding] + set _channel(original_position) [chan tell $chan] + if {$_channel(original_position) == -1} { + error "Channel does not support seeking." + } + set _channel(name) $chan + + # Guess the format of the CSV + array set options [tclcsv::sniff $chan] + if {[llength [tclcsv::sniff_header $chan]] > 1} { + set options(-headerpresent) 1 + } else { + set options(-headerpresent) 0 + } + # Note above setting will be overwritten by options passed by app + + return + } + + # Parse CSV from the channel based on the current option settings. + # Sets up the header and type by sniffing the channel + method ChanRead {} { + set opts [$self CollectCsvOptions] + if {[dict get $opts -delimiter] eq ""} { + error "Delimiter must be specified." + } + + lappend opts -nrows $_max_data_lines + + # Rewind the file to where we started from + chan seek $_channel(name) $_channel(original_position) + chan configure $_channel(name) -encoding $options(-encoding) + + # Figure out the header if necessary but only overwrite existing + # headers if number of columns has changed + if {[dict size $options(-columntypes)]} { + set headers [tclcsv::sniff_header {*}$opts $_channel(name)] + set types [lindex $headers 0] + if {![info exists _column_type_display_strings] || + [array size _column_type_display_strings] != [llength $types]} { + array unset _column_type_display_strings * + for {set i 0} {$i < [llength $types]} {incr i} { + set coltype [lindex $types $i] + set _column_type_display_strings($i) [dict get $options(-columntypes) $coltype display] + } + } + if {[llength $headers] > 1} { + set headings [lindex $headers 1] + if {![info exists _column_headings] || + [array size _column_headings] != [llength $headings]} { + array unset _column_headings * + for {set i 0} {$i < [llength $headings]} {incr i} { + set _column_headings($i) [lindex $headings $i] + } + } + } + } + set rows [tclcsv::csv_read {*}$opts $_channel(name)] + chan seek $_channel(name) $_channel(original_position) + set _num_data_lines [llength $rows] + return $rows + } + + method CollectCsvOptions {} { + foreach opt {-delimiter -comment -escape -quote -skipleadingspace -skipblanklines -doublequote} { + if {$options($opt) ne "other"} { + lappend opts $opt $options($opt) + } elseif {[info exists _other($opt)]} { + lappend opts $opt $_other($opt) + } else { + lappend opts $opt "" + } + } + return $opts + } + + # Returns the channel + method channel {} { + return $_channel(name) + } + + # Returns the current setting of -encoding + method encoding {} { + # Not part of dialectsettings because that can be passed directly + # to csv_read + return $options(-encoding) + } + + # Returns the settings related to the CSV dialect and fields to be + # included. Can be passed + # to cvs_read + method dialect {} { + set opts [$self CollectCsvOptions] + if {[dict get $opts -delimiter] eq ""} { + dict unset opts -delimiter + } + if {$options(-headerpresent)} { + lappend opts -startline 1 + } + set ncols [array size _included_columns] + set included {} + for {set i 0} {$i < $ncols} {incr i} { + if {[info exists _included_columns($i)] && $_included_columns($i)} { + lappend included $i + } + } + if {[llength $included] == 0} { + # Exclude all + lappend opts -excludefields [lsort -integer [array names _included_columns]] + } elseif {[llength $included] != $ncols} { + # Only subset of columns included + lappend opts -includefields $included + } + return $opts + } + + # Returns the current settings related to column types and names + method columnsettings {} { + if {[dict size $options(-columntypes)] == 0} { + error "Option -columntypes was not specified." + } + set ncols [array size _included_columns] + set header {} + for {set i 0} {$i < $ncols} {incr i} { + # Note some rows may have extra fields so always check if + # corresponding array entry actually exists + + if {![info exists _included_columns($i)] || + !$_included_columns($i)} { + continue; # Skip this columns + } + if {[info exists _column_headings($i)] && $_column_headings($i) ne ""} { + set heading $_column_headings($i) + } else { + set heading "Column_$i" + } + if {[info exists _column_type_display_strings($i)]} { + set display $_column_type_display_strings($i) + set type $_column_type_display_to_token($display) + } else { + set type "string" + } + lappend header [list heading $heading type $type] + } + return $header + } +} + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/d_config.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/d_config.tcl new file mode 100644 index 00000000..29de11d7 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/d_config.tcl @@ -0,0 +1,10 @@ +# (c) 2022 Andreas Kupries +# Error wrapper for deprecated package +# Deprecated: +# - doctools::config +# Replacement: +# - struct::map + +error "The package doctools::config is stage 2 deprecated. Use struct::map instead." +package provide doctools::config 0.1 +return diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/d_paths.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/d_paths.tcl new file mode 100644 index 00000000..3a1f44a8 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/d_paths.tcl @@ -0,0 +1,10 @@ +# (c) 2019 Andreas Kupries +# Redirection wrapper for deprecated package +# Deprecated: +# - doctools::paths +# Replacement: +# - fileutil::paths + +error "The package doctools::paths is stage 2 deprecated. Use fileutil::paths instead." +package provide doctools::paths 0.1 +return diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/p_config.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/p_config.tcl new file mode 100644 index 00000000..df9f3b40 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/p_config.tcl @@ -0,0 +1,10 @@ +# (c) 2019 Andreas Kupries +# Redirection wrapper for deprecated package +# Deprecated: +# - configuration +# Replacement: +# - struct::map + +error "The package configuration is stage 2 deprecated. Use struct::map instead." +package provide configuration 1 +return diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/p_paths.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/p_paths.tcl new file mode 100644 index 00000000..91edabed --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/p_paths.tcl @@ -0,0 +1,9 @@ +# (c) 2019 Andreas Kupries +# Redirection wrapper for deprecated package +# Deprecated: +# - paths +# Replacement: +# - fileutil::paths + +error "The package paths is stage 2 deprecated. Use fileutil::paths instead." +return diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/pkgIndex.tcl new file mode 100644 index 00000000..8875dbb8 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/0compatibility/pkgIndex.tcl @@ -0,0 +1,29 @@ +# Compatibility wrapper for deprecated packages. +## +# Stages +# [D1] Next Release - Noted deprecated, with redirection wrappers +# [D2] Release After - Wrappers become Blockers, throwing error noting redirection +# [D3] Release Beyond - All removed. +## +# Currently in deprecation +# - D1 doctools::path (doctools2base) +# - D1 doctools::config (doctools2base) +# - D1 configuration (pt) +# - D1 paths (pt) +# +# :Attention: +# - Original `doctools::paths` Tcl 8.4 required +# Replacement `fileutilutil::paths` Tcl 8.5 required! + +if {![package vsatisfies [package provide Tcl] 8.4]} {return} + +package ifneeded configuration 1 [list source [file join $dir p_config.tcl]] +package ifneeded doctools::config 0.1 [list source [file join $dir d_config.tcl]] +package ifneeded doctools::paths 0.1 [list source [file join $dir d_paths.tcl]] +package ifneeded paths 1 [list source [file join $dir p_paths.tcl]] + +if {![package vsatisfies [package provide Tcl] 8.5]} {return} + + +if {![package vsatisfies [package provide Tcl] 8.6]} {return} + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/aes/aes.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/aes/aes.tcl new file mode 100644 index 00000000..6a1849bd --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/aes/aes.tcl @@ -0,0 +1,625 @@ +# aes.tcl - +# +# Copyright (c) 2005 Thorsten Schloermann +# Copyright (c) 2005 Pat Thoyts +# Copyright (c) 2013 Andreas Kupries +# +# A Tcl implementation of the Advanced Encryption Standard (US FIPS PUB 197) +# +# AES is a block cipher with a block size of 128 bits and a variable +# key size of 128, 192 or 256 bits. +# The algorithm works on each block as a 4x4 state array. There are 4 steps +# in each round: +# SubBytes a non-linear substitution step using a predefined S-box +# ShiftRows cyclic transposition of rows in the state matrix +# MixColumns transformation upon columns in the state matrix +# AddRoundKey application of round specific sub-key +# +# ------------------------------------------------------------------------- +# 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.5 + +namespace eval ::aes { + variable uid + if {![info exists uid]} { set uid 0 } + + namespace export aes + + # constants + + # S-box + variable sbox { + 0x63 0x7c 0x77 0x7b 0xf2 0x6b 0x6f 0xc5 0x30 0x01 0x67 0x2b 0xfe 0xd7 0xab 0x76 + 0xca 0x82 0xc9 0x7d 0xfa 0x59 0x47 0xf0 0xad 0xd4 0xa2 0xaf 0x9c 0xa4 0x72 0xc0 + 0xb7 0xfd 0x93 0x26 0x36 0x3f 0xf7 0xcc 0x34 0xa5 0xe5 0xf1 0x71 0xd8 0x31 0x15 + 0x04 0xc7 0x23 0xc3 0x18 0x96 0x05 0x9a 0x07 0x12 0x80 0xe2 0xeb 0x27 0xb2 0x75 + 0x09 0x83 0x2c 0x1a 0x1b 0x6e 0x5a 0xa0 0x52 0x3b 0xd6 0xb3 0x29 0xe3 0x2f 0x84 + 0x53 0xd1 0x00 0xed 0x20 0xfc 0xb1 0x5b 0x6a 0xcb 0xbe 0x39 0x4a 0x4c 0x58 0xcf + 0xd0 0xef 0xaa 0xfb 0x43 0x4d 0x33 0x85 0x45 0xf9 0x02 0x7f 0x50 0x3c 0x9f 0xa8 + 0x51 0xa3 0x40 0x8f 0x92 0x9d 0x38 0xf5 0xbc 0xb6 0xda 0x21 0x10 0xff 0xf3 0xd2 + 0xcd 0x0c 0x13 0xec 0x5f 0x97 0x44 0x17 0xc4 0xa7 0x7e 0x3d 0x64 0x5d 0x19 0x73 + 0x60 0x81 0x4f 0xdc 0x22 0x2a 0x90 0x88 0x46 0xee 0xb8 0x14 0xde 0x5e 0x0b 0xdb + 0xe0 0x32 0x3a 0x0a 0x49 0x06 0x24 0x5c 0xc2 0xd3 0xac 0x62 0x91 0x95 0xe4 0x79 + 0xe7 0xc8 0x37 0x6d 0x8d 0xd5 0x4e 0xa9 0x6c 0x56 0xf4 0xea 0x65 0x7a 0xae 0x08 + 0xba 0x78 0x25 0x2e 0x1c 0xa6 0xb4 0xc6 0xe8 0xdd 0x74 0x1f 0x4b 0xbd 0x8b 0x8a + 0x70 0x3e 0xb5 0x66 0x48 0x03 0xf6 0x0e 0x61 0x35 0x57 0xb9 0x86 0xc1 0x1d 0x9e + 0xe1 0xf8 0x98 0x11 0x69 0xd9 0x8e 0x94 0x9b 0x1e 0x87 0xe9 0xce 0x55 0x28 0xdf + 0x8c 0xa1 0x89 0x0d 0xbf 0xe6 0x42 0x68 0x41 0x99 0x2d 0x0f 0xb0 0x54 0xbb 0x16 + } + # inverse S-box + variable xobs { + 0x52 0x09 0x6a 0xd5 0x30 0x36 0xa5 0x38 0xbf 0x40 0xa3 0x9e 0x81 0xf3 0xd7 0xfb + 0x7c 0xe3 0x39 0x82 0x9b 0x2f 0xff 0x87 0x34 0x8e 0x43 0x44 0xc4 0xde 0xe9 0xcb + 0x54 0x7b 0x94 0x32 0xa6 0xc2 0x23 0x3d 0xee 0x4c 0x95 0x0b 0x42 0xfa 0xc3 0x4e + 0x08 0x2e 0xa1 0x66 0x28 0xd9 0x24 0xb2 0x76 0x5b 0xa2 0x49 0x6d 0x8b 0xd1 0x25 + 0x72 0xf8 0xf6 0x64 0x86 0x68 0x98 0x16 0xd4 0xa4 0x5c 0xcc 0x5d 0x65 0xb6 0x92 + 0x6c 0x70 0x48 0x50 0xfd 0xed 0xb9 0xda 0x5e 0x15 0x46 0x57 0xa7 0x8d 0x9d 0x84 + 0x90 0xd8 0xab 0x00 0x8c 0xbc 0xd3 0x0a 0xf7 0xe4 0x58 0x05 0xb8 0xb3 0x45 0x06 + 0xd0 0x2c 0x1e 0x8f 0xca 0x3f 0x0f 0x02 0xc1 0xaf 0xbd 0x03 0x01 0x13 0x8a 0x6b + 0x3a 0x91 0x11 0x41 0x4f 0x67 0xdc 0xea 0x97 0xf2 0xcf 0xce 0xf0 0xb4 0xe6 0x73 + 0x96 0xac 0x74 0x22 0xe7 0xad 0x35 0x85 0xe2 0xf9 0x37 0xe8 0x1c 0x75 0xdf 0x6e + 0x47 0xf1 0x1a 0x71 0x1d 0x29 0xc5 0x89 0x6f 0xb7 0x62 0x0e 0xaa 0x18 0xbe 0x1b + 0xfc 0x56 0x3e 0x4b 0xc6 0xd2 0x79 0x20 0x9a 0xdb 0xc0 0xfe 0x78 0xcd 0x5a 0xf4 + 0x1f 0xdd 0xa8 0x33 0x88 0x07 0xc7 0x31 0xb1 0x12 0x10 0x59 0x27 0x80 0xec 0x5f + 0x60 0x51 0x7f 0xa9 0x19 0xb5 0x4a 0x0d 0x2d 0xe5 0x7a 0x9f 0x93 0xc9 0x9c 0xef + 0xa0 0xe0 0x3b 0x4d 0xae 0x2a 0xf5 0xb0 0xc8 0xeb 0xbb 0x3c 0x83 0x53 0x99 0x61 + 0x17 0x2b 0x04 0x7e 0xba 0x77 0xd6 0x26 0xe1 0x69 0x14 0x63 0x55 0x21 0x0c 0x7d + } +} + +# aes::Init -- +# +# Initialise our AES state and calculate the key schedule. An initialization +# vector is maintained in the state for modes that require one. The key must +# be binary data of the correct size and the IV must be 16 bytes. +# +# Nk: columns of the key-array +# Nr: number of rounds (depends on key-length) +# Nb: columns of the text-block, is always 4 in AES +# +proc ::aes::Init {mode key iv} { + switch -exact -- $mode { + ecb - cbc { } + cfb - ofb { + return -code error "$mode mode not implemented" + } + default { + return -code error "invalid mode \"$mode\":\ + must be one of ecb or cbc." + } + } + + set size [expr {[string length $key] << 3}] + switch -exact -- $size { + 128 {set Nk 4; set Nr 10; set Nb 4} + 192 {set Nk 6; set Nr 12; set Nb 4} + 256 {set Nk 8; set Nr 14; set Nb 4} + default { + return -code error "invalid key size \"$size\":\ + must be one of 128, 192 or 256." + } + } + + variable uid + set Key [namespace current]::[incr uid] + upvar #0 $Key state + if {[binary scan $iv Iu4 state(I)] != 1} { + return -code error "invalid initialization vector: must be 16 bytes" + } + array set state [list M $mode K $key Nk $Nk Nr $Nr Nb $Nb W {}] + ExpandKey $Key + return $Key +} + +# aes::Reset -- +# +# Reset the initialization vector for the specified key. This permits the +# key to be reused for encryption or decryption without the expense of +# re-calculating the key schedule. +# +proc ::aes::Reset {Key iv} { + upvar #0 $Key state + if {[binary scan $iv Iu4 state(I)] != 1} { + return -code error "invalid initialization vector: must be 16 bytes" + } + return +} + +# aes::Final -- +# +# Clean up the key state +# +proc ::aes::Final {Key} { + # FRINK: nocheck + unset $Key +} + +# ------------------------------------------------------------------------- + +# 5.1 Cipher: Encipher a single block of 128 bits. +proc ::aes::EncryptBlock {Key block} { + upvar #0 $Key state + if {[binary scan $block Iu4 data] != 1} { + return -code error "invalid block size: blocks must be 16 bytes" + } + + if {$state(M) eq {cbc}} { + # Loop unrolled. + lassign $data d0 d1 d2 d3 + lassign $state(I) s0 s1 s2 s3 + set data [list \ + [expr {$d0 ^ $s0}] \ + [expr {$d1 ^ $s1}] \ + [expr {$d2 ^ $s2}] \ + [expr {$d3 ^ $s3}] ] + } + + set data [AddRoundKey $Key 0 $data] + for {set n 1} {$n < $state(Nr)} {incr n} { + set data [AddRoundKey $Key $n [MixColumns [ShiftRows [SubBytes $data]]]] + } + set data [AddRoundKey $Key $n [ShiftRows [SubBytes $data]]] + + # Bug 2993029: + # Force all elements of data into the 32bit range. + # Loop unrolled + set res [Clamp32 $data] + + set state(I) $res + binary format Iu4 $res +} + +# 5.3: Inverse Cipher: Decipher a single 128 bit block. +proc ::aes::DecryptBlock {Key block} { + upvar #0 $Key state + if {[binary scan $block Iu4 data] != 1} { + return -code error "invalid block size: block must be 16 bytes" + } + set iv $data + + set n $state(Nr) + set data [AddRoundKey $Key $state(Nr) $data] + for {incr n -1} {$n > 0} {incr n -1} { + set data [InvMixColumns [AddRoundKey $Key $n [InvSubBytes [InvShiftRows $data]]]] + } + set data [AddRoundKey $Key $n [InvSubBytes [InvShiftRows $data]]] + + if {$state(M) eq {cbc}} { + lassign $data d0 d1 d2 d3 + lassign $state(I) s0 s1 s2 s3 + set data [list \ + [expr {($d0 ^ $s0) & 0xffffffff}] \ + [expr {($d1 ^ $s1) & 0xffffffff}] \ + [expr {($d2 ^ $s2) & 0xffffffff}] \ + [expr {($d3 ^ $s3) & 0xffffffff}] ] + } else { + # Bug 2993029: + # The integrated clamping we see above only happens for CBC mode. + set data [Clamp32 $data] + } + + set state(I) $iv + binary format Iu4 $data +} + +proc ::aes::Clamp32 {data} { + # Force all elements into 32bit range. + lassign $data d0 d1 d2 d3 + list \ + [expr {$d0 & 0xffffffff}] \ + [expr {$d1 & 0xffffffff}] \ + [expr {$d2 & 0xffffffff}] \ + [expr {$d3 & 0xffffffff}] +} + +# 5.2: KeyExpansion +proc ::aes::ExpandKey {Key} { + upvar #0 $Key state + set Rcon [list 0x00000000 0x01000000 0x02000000 0x04000000 0x08000000 \ + 0x10000000 0x20000000 0x40000000 0x80000000 0x1b000000 \ + 0x36000000 0x6c000000 0xd8000000 0xab000000 0x4d000000] + # Split the key into Nk big-endian words + binary scan $state(K) I* W + set max [expr {$state(Nb) * ($state(Nr) + 1)}] + set i $state(Nk) + set h [expr {$i - 1}] + set j 0 + for {} {$i < $max} {incr i; incr h; incr j} { + set temp [lindex $W $h] + if {($i % $state(Nk)) == 0} { + set sub [SubWord [RotWord $temp]] + set rc [lindex $Rcon [expr {$i/$state(Nk)}]] + set temp [expr {$sub ^ $rc}] + } elseif {$state(Nk) > 6 && ($i % $state(Nk)) == 4} { + set temp [SubWord $temp] + } + lappend W [expr {[lindex $W $j] ^ $temp}] + } + set state(W) $W +} + +# 5.2: Key Expansion: Apply S-box to each byte in the 32 bit word +proc ::aes::SubWord {w} { + variable sbox + set s3 [lindex $sbox [expr {($w >> 24) & 255}]] + set s2 [lindex $sbox [expr {($w >> 16) & 255}]] + set s1 [lindex $sbox [expr {($w >> 8 ) & 255}]] + set s0 [lindex $sbox [expr { $w & 255}]] + return [expr {($s3 << 24) | ($s2 << 16) | ($s1 << 8) | $s0}] +} + +proc ::aes::InvSubWord {w} { + variable xobs + set s3 [lindex $xobs [expr {($w >> 24) & 255}]] + set s2 [lindex $xobs [expr {($w >> 16) & 255}]] + set s1 [lindex $xobs [expr {($w >> 8 ) & 255}]] + set s0 [lindex $xobs [expr { $w & 255}]] + return [expr {($s3 << 24) | ($s2 << 16) | ($s1 << 8) | $s0}] +} + +# 5.2: Key Expansion: Rotate a 32bit word by 8 bits +proc ::aes::RotWord {w} { + return [expr {(($w << 8) | (($w >> 24) & 0xff)) & 0xffffffff}] +} + +# 5.1.1: SubBytes() Transformation +proc ::aes::SubBytes {words} { + lassign $words w0 w1 w2 w3 + list [SubWord $w0] [SubWord $w1] [SubWord $w2] [SubWord $w3] +} + +# 5.3.2: InvSubBytes() Transformation +proc ::aes::InvSubBytes {words} { + lassign $words w0 w1 w2 w3 + list [InvSubWord $w0] [InvSubWord $w1] [InvSubWord $w2] [InvSubWord $w3] +} + +# 5.1.2: ShiftRows() Transformation +proc ::aes::ShiftRows {words} { + for {set n0 0} {$n0 < 4} {incr n0} { + set n1 [expr {($n0 + 1) % 4}] + set n2 [expr {($n0 + 2) % 4}] + set n3 [expr {($n0 + 3) % 4}] + lappend r [expr {( [lindex $words $n0] & 0xff000000) + | ([lindex $words $n1] & 0x00ff0000) + | ([lindex $words $n2] & 0x0000ff00) + | ([lindex $words $n3] & 0x000000ff) + }] + } + return $r +} + + +# 5.3.1: InvShiftRows() Transformation +proc ::aes::InvShiftRows {words} { + for {set n0 0} {$n0 < 4} {incr n0} { + set n1 [expr {($n0 + 1) % 4}] + set n2 [expr {($n0 + 2) % 4}] + set n3 [expr {($n0 + 3) % 4}] + lappend r [expr {( [lindex $words $n0] & 0xff000000) + | ([lindex $words $n3] & 0x00ff0000) + | ([lindex $words $n2] & 0x0000ff00) + | ([lindex $words $n1] & 0x000000ff) + }] + } + return $r +} + +# 5.1.3: MixColumns() Transformation +proc ::aes::MixColumns {words} { + set r {} + foreach w $words { + set r0 [expr {(($w >> 24) & 255)}] + set r1 [expr {(($w >> 16) & 255)}] + set r2 [expr {(($w >> 8 ) & 255)}] + set r3 [expr {( $w & 255)}] + + set s0 [expr {[GFMult2 $r0] ^ [GFMult3 $r1] ^ $r2 ^ $r3}] + set s1 [expr {$r0 ^ [GFMult2 $r1] ^ [GFMult3 $r2] ^ $r3}] + set s2 [expr {$r0 ^ $r1 ^ [GFMult2 $r2] ^ [GFMult3 $r3]}] + set s3 [expr {[GFMult3 $r0] ^ $r1 ^ $r2 ^ [GFMult2 $r3]}] + + lappend r [expr {($s0 << 24) | ($s1 << 16) | ($s2 << 8) | $s3}] + } + return $r +} + +# 5.3.3: InvMixColumns() Transformation +proc ::aes::InvMixColumns {words} { + set r {} + foreach w $words { + set r0 [expr {(($w >> 24) & 255)}] + set r1 [expr {(($w >> 16) & 255)}] + set r2 [expr {(($w >> 8 ) & 255)}] + set r3 [expr {( $w & 255)}] + + set s0 [expr {[GFMult0e $r0] ^ [GFMult0b $r1] ^ [GFMult0d $r2] ^ [GFMult09 $r3]}] + set s1 [expr {[GFMult09 $r0] ^ [GFMult0e $r1] ^ [GFMult0b $r2] ^ [GFMult0d $r3]}] + set s2 [expr {[GFMult0d $r0] ^ [GFMult09 $r1] ^ [GFMult0e $r2] ^ [GFMult0b $r3]}] + set s3 [expr {[GFMult0b $r0] ^ [GFMult0d $r1] ^ [GFMult09 $r2] ^ [GFMult0e $r3]}] + + lappend r [expr {($s0 << 24) | ($s1 << 16) | ($s2 << 8) | $s3}] + } + return $r +} + +# 5.1.4: AddRoundKey() Transformation +proc ::aes::AddRoundKey {Key round words} { + upvar #0 $Key state + set r {} + set n [expr {$round * $state(Nb)}] + foreach w $words { + lappend r [expr {$w ^ [lindex $state(W) $n]}] + incr n + } + return $r +} + +# ------------------------------------------------------------------------- +# ::aes::GFMult* +# +# some needed functions for multiplication in a Galois-field +# +proc ::aes::GFMult2 {number} { + # this is a tabular representation of xtime (multiplication by 2) + # it is used instead of calculation to prevent timing attacks + set xtime { + 0x00 0x02 0x04 0x06 0x08 0x0a 0x0c 0x0e 0x10 0x12 0x14 0x16 0x18 0x1a 0x1c 0x1e + 0x20 0x22 0x24 0x26 0x28 0x2a 0x2c 0x2e 0x30 0x32 0x34 0x36 0x38 0x3a 0x3c 0x3e + 0x40 0x42 0x44 0x46 0x48 0x4a 0x4c 0x4e 0x50 0x52 0x54 0x56 0x58 0x5a 0x5c 0x5e + 0x60 0x62 0x64 0x66 0x68 0x6a 0x6c 0x6e 0x70 0x72 0x74 0x76 0x78 0x7a 0x7c 0x7e + 0x80 0x82 0x84 0x86 0x88 0x8a 0x8c 0x8e 0x90 0x92 0x94 0x96 0x98 0x9a 0x9c 0x9e + 0xa0 0xa2 0xa4 0xa6 0xa8 0xaa 0xac 0xae 0xb0 0xb2 0xb4 0xb6 0xb8 0xba 0xbc 0xbe + 0xc0 0xc2 0xc4 0xc6 0xc8 0xca 0xcc 0xce 0xd0 0xd2 0xd4 0xd6 0xd8 0xda 0xdc 0xde + 0xe0 0xe2 0xe4 0xe6 0xe8 0xea 0xec 0xee 0xf0 0xf2 0xf4 0xf6 0xf8 0xfa 0xfc 0xfe + 0x1b 0x19 0x1f 0x1d 0x13 0x11 0x17 0x15 0x0b 0x09 0x0f 0x0d 0x03 0x01 0x07 0x05 + 0x3b 0x39 0x3f 0x3d 0x33 0x31 0x37 0x35 0x2b 0x29 0x2f 0x2d 0x23 0x21 0x27 0x25 + 0x5b 0x59 0x5f 0x5d 0x53 0x51 0x57 0x55 0x4b 0x49 0x4f 0x4d 0x43 0x41 0x47 0x45 + 0x7b 0x79 0x7f 0x7d 0x73 0x71 0x77 0x75 0x6b 0x69 0x6f 0x6d 0x63 0x61 0x67 0x65 + 0x9b 0x99 0x9f 0x9d 0x93 0x91 0x97 0x95 0x8b 0x89 0x8f 0x8d 0x83 0x81 0x87 0x85 + 0xbb 0xb9 0xbf 0xbd 0xb3 0xb1 0xb7 0xb5 0xab 0xa9 0xaf 0xad 0xa3 0xa1 0xa7 0xa5 + 0xdb 0xd9 0xdf 0xdd 0xd3 0xd1 0xd7 0xd5 0xcb 0xc9 0xcf 0xcd 0xc3 0xc1 0xc7 0xc5 + 0xfb 0xf9 0xff 0xfd 0xf3 0xf1 0xf7 0xf5 0xeb 0xe9 0xef 0xed 0xe3 0xe1 0xe7 0xe5 + } + lindex $xtime $number +} + +proc ::aes::GFMult3 {number} { + # multliply by 2 (via GFMult2) and add the number again on the result (via XOR) + expr {$number ^ [GFMult2 $number]} +} + +proc ::aes::GFMult09 {number} { + # 09 is: (02*02*02) + 01 + expr {[GFMult2 [GFMult2 [GFMult2 $number]]] ^ $number} +} + +proc ::aes::GFMult0b {number} { + # 0b is: (02*02*02) + 02 + 01 + #return [expr [GFMult2 [GFMult2 [GFMult2 $number]]] ^ [GFMult2 $number] ^ $number] + #set g0 [GFMult2 $number] + expr {[GFMult09 $number] ^ [GFMult2 $number]} +} + +proc ::aes::GFMult0d {number} { + # 0d is: (02*02*02) + (02*02) + 01 + set temp [GFMult2 [GFMult2 $number]] + expr {[GFMult2 $temp] ^ ($temp ^ $number)} +} + +proc ::aes::GFMult0e {number} { + # 0e is: (02*02*02) + (02*02) + 02 + set temp [GFMult2 [GFMult2 $number]] + expr {[GFMult2 $temp] ^ ($temp ^ [GFMult2 $number])} +} + +# ------------------------------------------------------------------------- + +# aes::Encrypt -- +# +# Encrypt a blocks of plain text and returns blocks of cipher text. +# The input data must be a multiple of the block size (16). +# +proc ::aes::Encrypt {Key data} { + set len [string length $data] + if {($len % 16) != 0} { + return -code error "invalid block size: AES requires 16 byte blocks" + } + + set result {} + for {set i 0} {$i < $len} {incr i 1} { + set block [string range $data $i [incr i 15]] + append result [EncryptBlock $Key $block] + } + return $result +} + +# aes::Decrypt -- +# +# Decrypt blocks of cipher text and returns blocks of plain text. +# The input data must be a multiple of the block size (16). +# +proc ::aes::Decrypt {Key data} { + set len [string length $data] + if {($len % 16) != 0} { + return -code error "invalid block size: AES requires 16 byte blocks" + } + + set result {} + for {set i 0} {$i < $len} {incr i 1} { + set block [string range $data $i [incr i 15]] + append result [DecryptBlock $Key $block] + } + return $result +} + +# ------------------------------------------------------------------------- +# chan event handler for chunked file reading. +# +proc ::aes::Chunk {Key in {out {}} {chunksize 4096}} { + upvar #0 $Key state + + #puts ||CHUNK.X||i=$in|o=$out|c=$chunksize|eof=[eof $in] + + if {[eof $in]} { + chan event $in readable {} + set state(reading) 0 + } + + set data [read $in $chunksize] + + #puts ||CHUNK.R||i=$in|o=$out|c=$chunksize|eof=[eof $in]||[string length $data]||$data|| + + # Do nothing when data was read at all. + if {$data eq {}} return + + if {[eof $in]} { + #puts CHUNK.Z + set data [Pad $data 16] + } + + #puts ||CHUNK.P||i=$in|o=$out|c=$chunksize|eof=[eof $in]||[string length $data]||$data|| + + if {$out eq {}} { + append state(output) [$state(cmd) $Key $data] + } else { + puts -nonewline $out [$state(cmd) $Key $data] + } +} + +proc ::aes::SetOneOf {lst item} { + set ndx [lsearch -glob $lst "${item}*"] + if {$ndx == -1} { + set err [join $lst ", "] + return -code error "invalid mode \"$item\": must be one of $err" + } + lindex $lst $ndx +} + +proc ::aes::CheckSize {what size thing} { + if {[string length $thing] != $size} { + return -code error "invalid value for $what: must be $size bytes long" + } + return $thing +} + +proc ::aes::Pad {data blocksize {fill \0}} { + set len [string length $data] + if {$len == 0} { + set data [string repeat $fill $blocksize] + } elseif {($len % $blocksize) != 0} { + set pad [expr {$blocksize - ($len % $blocksize)}] + append data [string repeat $fill $pad] + } + return $data +} + +proc ::aes::Pop {varname {nth 0}} { + upvar 1 $varname args + set r [lindex $args $nth] + set args [lreplace $args $nth $nth] + return $r +} + +proc ::aes::aes {args} { + array set opts {-dir encrypt -mode cbc -key {} -in {} -out {} -chunksize 4096 -hex 0} + set opts(-iv) [string repeat \0 16] + set modes {ecb cbc} + set dirs {encrypt decrypt} + while {([llength $args] > 1) && [string match -* [set option [lindex $args 0]]]} { + switch -exact -- $option { + -mode { set opts(-mode) [SetOneOf $modes [Pop args 1]] } + -dir { set opts(-dir) [SetOneOf $dirs [Pop args 1]] } + -iv { set opts(-iv) [CheckSize -iv 16 [Pop args 1]] } + -key { set opts(-key) [Pop args 1] } + -in { set opts(-in) [Pop args 1] } + -out { set opts(-out) [Pop args 1] } + -chunksize { set opts(-chunksize) [Pop args 1] } + -hex { set opts(-hex) 1 } + -- { Pop args ; break } + default { + set err [join [lsort [array names opts]] ", "] + return -code error "bad option \"$option\":\ + must be one of $err" + } + } + Pop args + } + + if {$opts(-key) eq {}} { + return -code error "no key provided: the -key option is required" + } + + set r {} + if {$opts(-in) eq {}} { + + if {[llength $args] != 1} { + return -code error "wrong \# args:\ + should be \"aes ?options...? -key keydata plaintext\"" + } + + set data [Pad [lindex $args 0] 16] + set Key [Init $opts(-mode) $opts(-key) $opts(-iv)] + if {[string equal $opts(-dir) "encrypt"]} { + set r [Encrypt $Key $data] + } else { + set r [Decrypt $Key $data] + } + + if {$opts(-out) ne {}} { + puts -nonewline $opts(-out) $r + set r {} + } + Final $Key + + } else { + + if {[llength $args] != 0} { + return -code error "wrong \# args:\ + should be \"aes ?options...? -key keydata -in channel\"" + } + + set Key [Init $opts(-mode) $opts(-key) $opts(-iv)] + + set readcmd [list [namespace origin Chunk] \ + $Key $opts(-in) $opts(-out) \ + $opts(-chunksize)] + + upvar 1 $Key state + set state(reading) 1 + if {[string equal $opts(-dir) "encrypt"]} { + set state(cmd) Encrypt + } else { + set state(cmd) Decrypt + } + set state(output) "" + chan event $opts(-in) readable $readcmd + if {[info commands ::tkwait] != {}} { + tkwait variable [subst $Key](reading) + } else { + vwait [subst $Key](reading) + } + if {$opts(-out) == {}} { + set r $state(output) + } + Final $Key + } + + if {$opts(-hex)} { + binary scan $r H* r + } + return $r +} + +# ------------------------------------------------------------------------- + +package provide aes 1.2.1 + +# ------------------------------------------------------------------------- +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/aes/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/aes/pkgIndex.tcl new file mode 100644 index 00000000..83cc80fe --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/aes/pkgIndex.tcl @@ -0,0 +1,5 @@ +if {![package vsatisfies [package provide Tcl] 8.5]} { + # PRAGMA: returnok + return +} +package ifneeded aes 1.2.1 [list source [file join $dir aes.tcl]] diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/S3.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/S3.tcl new file mode 100644 index 00000000..dfdaf424 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/S3.tcl @@ -0,0 +1,1960 @@ +# S3.tcl +# +###Abstract +# This presents an interface to Amazon's S3 service. +# The Amazon S3 service allows for reliable storage +# and retrieval of data via HTTP. +# +# Copyright (c) 2006,2008 Darren New. All Rights Reserved. +# +###Copyright +# NO WARRANTIES OF ANY TYPE ARE PROVIDED. +# COPYING OR USE INDEMNIFIES THE AUTHOR IN ALL WAYS. +# +# This software is licensed under essentially the same +# terms as Tcl. See LICENSE.txt for the terms. +# +###Revision String +# SCCS: %Z% %M% %I% %E% %U% +# +###Change history: +# 0.7.2 - added -default-bucket. +# 0.8.0 - fixed bug in getLocal using wrong prefix. +# Upgraded to Tcl 8.5 release version. +# 1.0.0 - added SetAcl, GetAcl, and -acl keep option. +# + +package require Tcl 8.5 + +# This is by Darren New too. +# It is a SAX package to format XML for easy retrieval. +# It should be in the same distribution as S3. +package require xsxp + +# These three are required to do the auth, so always require them. +# Note that package registry and package fileutil are required +# by the individual routines that need them. Grep for "package". +package require sha1 +package require md5 +package require base64 + +package provide S3 1.0.3 + +namespace eval S3 { + variable config ; # A dict holding the current configuration. + variable config_orig ; # Holds configuration to "reset" back to. + variable debug 0 ; # Turns on or off S3::debug + variable debuglog 0 ; # Turns on or off debugging into a file + variable bgvar_counter 0 ; # Makes unique names for bgvars. + + set config_orig [dict create \ + -reset false \ + -retries 3 \ + -accesskeyid "" -secretaccesskey "" \ + -service-access-point "s3.amazonaws.com" \ + -slop-seconds 3 \ + -use-tls false \ + -bucket-prefix "TclS3" \ + -default-compare "always" \ + -default-separator "/" \ + -default-acl "" \ + -default-bucket "" \ + ] + + set config $config_orig +} + +# Internal, for development. Print a line, and maybe log it. +proc S3::debuglogline {line} { + variable debuglog + puts $line + if {$debuglog} { + set x [open debuglog.txt a] + puts $x $line + close $x + } +} + +# Internal, for development. Print debug info properly formatted. +proc S3::debug {args} { + variable debug + variable debuglog + if {!$debug} return + set res "" + if {"-hex" == [lindex $args 0]} { + set str [lindex $args 1] + foreach ch [split $str {}] { + scan $ch %c val + append res [format %02x $val] + append res " " + } + debuglogline $res + return + } + if {"-dict" == [lindex $args 0]} { + set dict [lindex $args 1] + debuglogline "DEBUG dict:" + foreach {key val} $dict { + set val [string map [list \ + \r \\r \n \\n \0 \\0 ] $val] + debuglogline "$key=$val" + } + return + } + set x [string map [list \ + \r \\r \n \\n \0 \\0 ] $args] + debuglogline "DEBUG: $x" +} + +# Internal. Throws an error if keys have not been initialized. +proc S3::checkinit {} { + variable config + set error "S3 must be initialized with -accesskeyid and -secretaccesskey before use" + set e1 {S3 usage -accesskeyid "S3 identification not initialized"} + set e2 {S3 usage -secretaccesskey "S3 identification not initialized"} + if {[dict get $config -accesskeyid] eq ""} { + error $error "" $e1 + } + if {[dict get $config -secretaccesskey] eq ""} { + error $error "" $e2 + } +} + +# Internal. Calculates the Content-Type for a given file name. +# Naturally returns application/octet-stream if anything goes wrong. +proc S3::contenttype {fname} { + if {$::tcl_platform(platform) == "windows"} { + set extension [file extension $fname] + uplevel #0 package require registry + set key "\\\\HKEY_CLASSES_ROOT\\" + set key "HKEY_CLASSES_ROOT\\" + if {"." != [string index $extension 0]} {append key .} + append key $extension + set ct "application/octet-stream" + if {$extension != ""} { + catch {set ct [registry get $key {Content Type}]} caught + } + } else { + # Assume something like Unix. + if {[file readable /etc/mime.types]} { + set extension [string trim [file extension $fname] "."] + set f [open /etc/mime.types r] + while {-1 != [gets $f line] && ![info exists c]} { + set line [string trim $line] + if {[string match "#*" $line]} continue + if {0 == [string length $line]} continue + set items [split $line] + for {set i 1} {$i < [llength $items]} {incr i} { + if {[lindex $items $i] eq $extension} { + set c [lindex $items 0] + break + } + } + } + close $f + if {![info exists c]} { + set ct "application/octet-stream" + } else { + set ct [string trim $c] + } + } else { + # No /etc/mime.types here. + if {[catch {exec file -i $fname} res]} { + set ct "application/octet-stream" + } else { + set ct [string range $res [expr {1+[string first : $res]}] end] + if {-1 != [string first ";" $ct]} { + set ct [string range $ct 0 [string first ";" $ct]] + } + set ct [string trim $ct "; "] + } + } + } + return $ct +} + +# Change current configuration. Not object-oriented, so only one +# configuration is tracked per interpreter. +proc S3::Configure {args} { + variable config + variable config_orig + if {[llength $args] == 0} {return $config} + if {[llength $args] == 1 && ![dict exists $config [lindex $args 0]]} { + error "Bad option \"[lindex $args 0]\": must be [join [dict keys $config] ,\ ]" "" [list S3 usage [lindex $args 0] "Bad option to config"] + } + if {[llength $args] == 1} {return [dict get $config [lindex $args 0]]} + if {[llength $args] % 2 != 0} { + error "Config args must be -name val -name val" "" [list S3 usage [lindex $args end] "Odd number of config args"] + } + set new $config + foreach {tag val} $args { + if {![dict exists $new $tag]} { + error "Bad option \"$tag\": must be [join [dict keys $config] ,\ ]" "" [list S3 usage $tag "Bad option to config"] + } + dict set new $tag $val + if {$tag eq "-reset" && $val} { + set new $config_orig + } + } + if {[dict get $config -use-tls]} { + error "TLS for S3 not yet implemented!" "" \ + [list S3 notyet -use-tls $config] + } + set config $new ; # Only update if all went well + return $config +} + +# Suggest a unique bucket name based on usename and config info. +proc S3::SuggestBucket {{usename ""}} { + checkinit + if {$usename eq ""} {set usename [::S3::Configure -bucket-prefix]} + if {$usename eq ""} { + error "S3::SuggestBucket requires name or -bucket-prefix set" \ + "" [list S3 usage -bucket-prefix] + } + return $usename\.[::S3::Configure -accesskeyid] +} + +# Calculate authorization token for REST interaction. +# Doesn't work yet for "Expires" type headers. Hence, only for "REST". +# We specifically don't call checkinit because it's called in all +# callers and we don't want to throw an error inside here. +# Caveat Emptor if you expect otherwise. +# This is internal, but useful enough you might want to invoke it. +proc S3::authREST {verb resource content-type headers args} { + if {[llength $args] != 0} { + set body [lindex $args 0] ; # we use [info exists] later + } + if {${content-type} != "" && [dict exists $headers content-type]} { + set content-type [dict get $headers content-type] + } + dict unset headers content-type + set verb [string toupper $verb] + if {[info exists body]} { + set content-md5 [::base64::encode [::md5::md5 $body]] + dict set headers content-md5 ${content-md5} + dict set headers content-length [string length $body] + } elseif {[dict exists $headers content-md5]} { + set content-md5 [dict get $headers content-md5] + } else { + set content-md5 "" + } + if {[dict exists $headers x-amz-date]} { + set date "" + dict unset headers date + } elseif {[dict exists $headers date]} { + set date [dict get $headers date] + } else { + set date [clock format [clock seconds] -gmt true -format \ + "%a, %d %b %Y %T %Z"] + dict set headers date $date + } + if {${content-type} != ""} { + dict set headers content-type ${content-type} + } + dict set headers host s3.amazonaws.com + set xamz "" + foreach key [lsort [dict keys $headers x-amz-*]] { + # Assume each is seen only once, for now, and is canonical already. + append xamz \n[string trim $key]:[string trim [dict get $headers $key]] + } + set xamz [string trim $xamz] + # Hmmm... Amazon lies. No \n after xamz if xamz is empty. + if {0 != [string length $xamz]} {append xamz \n} + set signthis \ + "$verb\n${content-md5}\n${content-type}\n$date\n$xamz$resource" + S3::debug "Sign this:" $signthis ; S3::debug -hex $signthis + set sig [::sha1::hmac [S3::Configure -secretaccesskey] $signthis] + set sig [binary format H* $sig] + set sig [string trim [::base64::encode $sig]] + dict set headers authorization "AWS [S3::Configure -accesskeyid]:$sig" + return $headers +} + +# Internal. Takes resource and parameters, tacks them together. +# Useful enough you might want to invoke it yourself. +proc S3::to_url {resource parameters} { + if {0 == [llength $parameters]} {return $resource} + if {-1 == [string first "?" $resource]} { + set front ? + } else { + set front & + } + foreach {key value} $parameters { + append resource $front $key "=" $value + set front & + } + return $resource +} + +# Internal. Encode a URL, including utf-8 versions. +# Useful enough you might want to invoke it yourself. +proc S3::encode_url {orig} { + set res "" + set re {[-a-zA-Z0-9/.,_]} + foreach ch [split $orig ""] { + if {[regexp $re $ch]} { + append res $ch + } else { + foreach uch [split [encoding convertto utf-8 $ch] ""] { + append res "%" + binary scan $uch H2 hex + append res $hex + } + } + } + if {$res ne $orig} { + S3::debug "URL Encoded:" $orig $res + } + return $res +} + +# This is used internally to either queue an event-driven +# item or to simply call the next routine, depending on +# whether the current transaction is supposed to be running +# in the background or not. +proc S3::nextdo {routine thunk direction args} { + global errorCode + S3::debug "nextdo" $routine $thunk $direction $args + if {[dict get $thunk blocking]} { + return [S3::$routine $thunk] + } else { + if {[llength $args] == 2} { + # fcopy failed! + S3::fail $thunk "S3 fcopy failed: [lindex $args 1]" "" \ + [list S3 socket $errorCode] + } else { + fileevent [dict get $thunk S3chan] $direction \ + [list S3::$routine $thunk] + if {$direction == "writable"} { + fileevent [dict get $thunk S3chan] readable {} + } else { + fileevent [dict get $thunk S3chan] writable {} + } + } + } +} + +# The proverbial It. Do a REST call to Amazon S3 service. +proc S3::REST {orig} { + variable config + checkinit + set EndPoint [dict get $config -service-access-point] + + # Save the original stuff first. + set thunk [dict create orig $orig] + + # Now add to thunk's top-level the important things + if {[dict exists $thunk orig resultvar]} { + dict set thunk blocking 0 + } else { + dict set thunk blocking 1 + } + if {[dict exists $thunk orig S3chan]} { + dict set thunk S3chan [dict get $thunk orig S3chan] + } elseif {[dict get $thunk blocking]} { + dict set thunk S3chan [socket $EndPoint 80] + } else { + dict set thunk S3chan [socket -async $EndPoint 80] + } + fconfigure [dict get $thunk S3chan] -translation binary -encoding binary + + dict set thunk verb [dict get $thunk orig verb] + dict set thunk resource [S3::encode_url [dict get $thunk orig resource]] + if {[dict exists $orig rtype]} { + dict set thunk resource \ + [dict get $thunk resource]?[dict get $orig rtype] + } + if {[dict exists $orig headers]} { + dict set thunk headers [dict get $orig headers] + } else { + dict set thunk headers [dict create] + } + if {[dict exists $orig infile]} { + dict set thunk infile [dict get $orig infile] + } + if {[dict exists $orig content-type]} { + dict set thunk content-type [dict get $orig content-type] + } else { + if {[dict exists $thunk infile]} { + set zz [dict get $thunk infile] + } else { + set zz [dict get $thunk resource] + } + if {-1 != [string first "?" $zz]} { + set zz [string range $zz 0 [expr {[string first "?" $zz]-1}]] + set zz [string trim $zz] + } + if {$zz != ""} { + catch {dict set thunk content-type [S3::contenttype $zz]} + } else { + dict set thunk content-type application/octet-stream + dict set thunk content-type "" + } + } + set p {} + if {[dict exist $thunk orig parameters]} { + set p [dict get $thunk orig parameters] + } + dict set thunk url [S3::to_url [dict get $thunk resource] $p] + + if {[dict exists $thunk orig inbody]} { + dict set thunk headers [S3::authREST \ + [dict get $thunk verb] [dict get $thunk resource] \ + [dict get $thunk content-type] [dict get $thunk headers] \ + [dict get $thunk orig inbody] ] + } else { + dict set thunk headers [S3::authREST \ + [dict get $thunk verb] [dict get $thunk resource] \ + [dict get $thunk content-type] [dict get $thunk headers] ] + } + # Not the best place to put this code. + if {![info exists body] && [dict exists $thunk infile]} { + set size [file size [dict get $thunk infile]] + set x [dict get $thunk headers] + dict set x content-length $size + dict set thunk headers $x + } + + + # Ready to go! + return [S3::nextdo send_headers $thunk writable] +} + +# Internal. Send the headers to Amazon. Might block if you have +# really small socket buffers, but Amazon doesn't want +# data that big anyway. +proc S3::send_headers {thunk} { + S3::debug "Send-headers" $thunk + set s3 [dict get $thunk S3chan] + puts $s3 "[dict get $thunk verb] [dict get $thunk url] HTTP/1.0" + S3::debug ">> [dict get $thunk verb] [dict get $thunk url] HTTP/1.0" + foreach {key val} [dict get $thunk headers] { + puts $s3 "$key: $val" + S3::debug ">> $key: $val" + } + puts $s3 "" + flush $s3 + return [S3::nextdo send_body $thunk writable] +} + +# Internal. Send the body to Amazon. +proc S3::send_body {thunk} { + global errorCode + set s3 [dict get $thunk S3chan] + if {[dict exists $thunk orig inbody]} { + # Send a string. Let's guess that even in non-blocking + # mode, this is small enough or Tcl's smart enough that + # we don't blow up the buffer. + puts -nonewline $s3 [dict get $thunk orig inbody] + flush $s3 + return [S3::nextdo read_headers $thunk readable] + } elseif {![dict exists $thunk orig infile]} { + # No body, no file, so nothing more to do. + return [S3::nextdo read_headers $thunk readable] + } elseif {[dict get $thunk blocking]} { + # A blocking file copy. Still not too hard. + if {[catch {set inchan [open [dict get $thunk infile] r]} caught]} { + S3::fail $thunk "S3 could not open infile - $caught" "" \ + [list S3 local [dict get $thunk infile] $errorCode] + } + fconfigure $inchan -translation binary -encoding binary + fileevent $s3 readable {} + fileevent $s3 writable {} + if {[catch {fcopy $inchan $s3 ; flush $s3 ; close $inchan} caught]} { + S3::fail $thunk "S3 could not copy infile - $caught" "" \ + [list S3 local [dict get $thunk infile] $errorCode] + } + S3::nextdo read_headers $thunk readable + } else { + # The hard one. Background file copy. + fileevent $s3 readable {} + fileevent $s3 writable {} + if {[catch {set inchan [open [dict get $thunk infile] r]} caught]} { + S3::fail $thunk "S3 could not open infile - $caught" "" \ + [list S3 local [dict get $thunk infile] $errorCode] + } + fconfigure $inchan -buffering none -translation binary -encoding binary + fconfigure $s3 -buffering none -translation binary \ + -encoding binary -blocking 0 ; # Doesn't work without this? + dict set thunk inchan $inchan ; # So we can close it. + fcopy $inchan $s3 -command \ + [list S3::nextdo read_headers $thunk readable] + } +} + +# Internal. The first line has come back. Grab out the +# stuff we care about. +proc S3::parse_status {thunk line} { + # Got the status line + S3::debug "<< $line" + dict set thunk httpstatusline [string trim $line] + dict set thunk outheaders [dict create] + regexp {^HTTP/1.. (...) (.*)$} $line junk code message + dict set thunk httpstatus $code + dict set thunk httpmessage [string trim $message] + return $thunk +} + +# A line of header information has come back. Grab it. +# This probably is unhappy with multiple lines for one +# header. +proc S3::parse_header {thunk line} { + # Got a header line. For now, assume no continuations. + S3::debug "<< $line" + set line [string trim $line] + set left [string range $line 0 [expr {[string first ":" $line]-1}]] + set right [string range $line [expr {[string first ":" $line]+1}] end] + set left [string trim [string tolower $left]] + set right [string trim $right] + dict set thunk outheaders $left $right + return $thunk +} + +# I don't know if HTTP requires a blank line after the headers if +# there's no body. + +# Internal. Read all the headers, and throw if we get EOF before +# we get any headers at all. +proc S3::read_headers {thunk} { + set s3 [dict get $thunk S3chan] + flush $s3 + fconfigure $s3 -blocking [dict get $thunk blocking] + if {[dict get $thunk blocking]} { + # Blocking. Just read to a blank line. Otherwise, + # if we use nextdo here, we wind up nesting horribly. + # If we're not blocking, of course, we're returning + # to the event loop each time, so that's OK. + set count [gets $s3 line] + if {[eof $s3]} { + S3::fail $thunk "S3 EOF during status line read" "" "S3 socket EOF" + } + set thunk [S3::parse_status $thunk $line] + while {[string trim $line] != ""} { + set count [gets $s3 line] + if {$count == -1 && 0 == [dict size [dict get $thunk outheaders]]} { + S3::fail $thunk "S3 EOF during headers read" "" "S3 socket EOF" + } + if {[string trim $line] != ""} { + set thunk [S3::parse_header $thunk $line] + } + } + return [S3::nextdo read_body $thunk readable] + } else { + # Non-blocking, so we have to reenter for each line. + # First, fix up the file handle, tho. + if {[dict exists $thunk inchan]} { + close [dict get $thunk inchan] + dict unset thunk inchan + } + # Now get one header. + set count [gets $s3 line] + if {[eof $s3]} { + fileevent $s3 readable {} + fileevent $s3 writable {} + if {![dict exists $thunk httpstatusline]} { + S3::fail $thunk "S3 EOF during status line read" "" "S3 socket EOF" + } elseif {0 == [dict size [dict get $thunk outheaders]]} { + S3::fail $thunk "S3 EOF during header read" "" "S3 socket EOF" + } + } + if {$count < 0} return ; # Wait for a whole line + set line [string trim $line] + if {![dict exists $thunk httpstatus]} { + set thunk [S3::parse_status $thunk $line] + S3::nextdo read_headers $thunk readable ; # New thunk here. + } elseif {$line != ""} { + set thunk [S3::parse_header $thunk $line] + S3::nextdo read_headers $thunk readable ; # New thunk here. + } else { + # Got an empty line. Switch to copying the body. + S3::nextdo read_body $thunk readable + } + } +} + +# Internal. Read the body of the response. +proc S3::read_body {thunk} { + set s3 [dict get $thunk S3chan] + if {[dict get $thunk blocking]} { + # Easy. Just read it. + if {[dict exists $thunk orig outchan]} { + fcopy $s3 [dict get $thunk orig outchan] + } else { + set x [read $s3] + dict set thunk outbody $x + #S3::debug "Body: $x" -- Disable unconditional wasteful conversion to string + #Need better debug system which does this only when active. + } + return [S3::nextdo all_done $thunk readable] + } else { + # Nonblocking mode. + if {[dict exists $thunk orig outchan]} { + fileevent $s3 readable {} + fileevent $s3 writable {} + fcopy $s3 [dict get $thunk orig outchan] -command \ + [list S3::nextdo all_done $thunk readable] + } else { + dict append thunk outbody [read $s3] + if {[eof $s3]} { + # We're done. + S3::nextdo all_done $thunk readable + } else { + S3::nextdo read_body $thunk readable + } + } + } +} + +# Internal. Convenience function. +proc S3::fail {thunk error errorInfo errorCode} { + S3::all_done $thunk $error $errorInfo $errorCode +} + +# Internal. We're all done the transaction. Clean up everything, +# potentially record errors, close channels, etc etc etc. +proc S3::all_done {thunk {error ""} {errorInfo ""} {errorCode ""}} { + set s3 [dict get $thunk S3chan] + catch { + fileevent $s3 readable {} + fileevent $s3 writable {} + } + if {![dict exists $thunk orig S3chan]} { + catch {close $s3} + } + set res [dict get $thunk orig] + catch { + dict set res httpstatus [dict get $thunk httpstatus] + dict set res httpmessage [dict get $thunk httpmessage] + dict set res outheaders [dict get $thunk outheaders] + } + if {![dict exists $thunk orig outchan]} { + if {[dict exists $thunk outbody]} { + dict set res outbody [dict get $thunk outbody] + } else { + # Probably HTTP failure + dict set rest outbody {} + } + } + if {$error ne ""} { + dict set res error $error + dict set res errorInfo $errorInfo + dict set res errorCode $errorCode + } + if {![dict get $thunk blocking]} { + after 0 [list uplevel #0 \ + [list set [dict get $thunk orig resultvar] $res]] + } + if {$error eq "" || ![dict get $thunk blocking] || \ + ([dict exists $thunk orig throwsocket] && \ + "return" == [dict get $thunk orig throwsocket])} { + return $res + } else { + error $error $errorInfo $errorCode + } +} + +# Internal. Parse the lst and make sure it has only keys from the 'valid' list. +# Used to parse arguments going into the higher-level functions. +proc S3::parseargs1 {lst valid} { + if {[llength $lst] % 2 != 0} { + error "Option list must be even -name val pairs" \ + "" [list S3 usage [lindex $lst end] $lst] + } + foreach {key val} $lst { + # Sadly, lsearch applies -glob to the wrong thing for our needs + set found 0 + foreach v $valid { + if {[string match $v $key]} {set found 1 ; break} + } + if {!$found} { + error "Option list has invalid -key" \ + "" [list S3 usage $key $lst] + } + } + return $lst ; # It seems OK +} + +# Internal. Create a variable for higher-level functions to vwait. +proc S3::bgvar {} { + variable bgvar_counter + incr bgvar_counter + set name ::S3::bgvar$bgvar_counter + return $name +} + +# Internal. Given a request and the arguments, run the S3::REST in +# the foreground or the background as appropriate. Also, do retries +# for internal errors. +proc S3::maybebackground {req myargs} { + variable config + global errorCode errorInfo + set mytries [expr {1+[dict get $config -retries]}] + set delay 2000 + dict set req throwsocket return + while {1} { + if {![dict exists $myargs -blocking] || [dict get $myargs -blocking]} { + set dict [S3::REST $req] + } else { + set res [bgvar] + dict set req resultvar $res + S3::REST $req + vwait $res + set dict [set $res] + unset $res ; # clean up temps + } + if {[dict exists $dict error]} { + set code [dict get $dict errorCode] + if {"S3" != [lindex $code 0] || "socket" != [lindex $code 1]} { + error [dict get $dict error] \ + [dict get $dict errorInfo] \ + [dict get $dict errorCode] + } + } + incr mytries -1 + incr delay $delay ; if {20000 < $delay} {set delay 20000} + if {"500" ne [dict get $dict httpstatus] || $mytries <= 0} { + return $dict + } + if {![dict exists $myargs -blocking] || [dict get $myargs -blocking]} { + after $delay + } else { + set timer [bgvar] + after $delay [list set $timer 1] + vwait $timer + unset $timer + } + } +} + +# Internal. Maybe throw an HTTP error if httpstatus not in 200 range. +proc S3::throwhttp {dict} { + set hs [dict get $dict httpstatus] + if {![string match "2??" $hs]} { + error "S3 received non-OK HTTP result of $hs" "" \ + [list S3 remote $hs $dict] + } +} + +# Public. Returns the list of buckets for this user. +proc S3::ListAllMyBuckets {args} { + checkinit ; # I know this gets done later. + set myargs [S3::parseargs1 $args {-blocking -parse-xml -result-type}] + if {![dict exists $myargs -result-type]} { + dict set myargs -result-type names + } + if {![dict exists $myargs -blocking]} { + dict set myargs -blocking true + } + set restype [dict get $myargs -result-type] + if {$restype eq "REST" && [dict exists $myargs -parse-xml]} { + error "Do not use REST with -parse-xml" "" \ + [list S3 usage -parse-xml $args] + } + if {![dict exists $myargs -parse-xml]} { + # We need to fetch the results. + set req [dict create verb GET resource /] + set dict [S3::maybebackground $req $myargs] + if {$restype eq "REST"} { + return $dict ; #we're done! + } + S3::throwhttp $dict ; #make sure it worked. + set xml [dict get $dict outbody] + } else { + set xml [dict get $myargs -parse-xml] + } + # Here, we either already returned the dict, or the XML is in "xml". + if {$restype eq "xml"} {return $xml} + if {[catch {set pxml [::xsxp::parse $xml]}]} { + error "S3 invalid XML structure" "" [list S3 usage xml $xml] + } + if {$restype eq "pxml"} {return $pxml} + if {$restype eq "dict" || $restype eq "names"} { + set buckets [::xsxp::fetch $pxml "Buckets" %CHILDREN] + set names {} ; set dates {} + foreach bucket $buckets { + lappend names [::xsxp::fetch $bucket "Name" %PCDATA] + lappend dates [::xsxp::fetch $bucket "CreationDate" %PCDATA] + } + if {$restype eq "names"} { + return $names + } else { + return [dict create \ + Owner/ID [::xsxp::fetch $pxml "Owner/ID" %PCDATA] \ + Owner/DisplayName \ + [::xsxp::fetch $pxml "Owner/DisplayName" %PCDATA] \ + Bucket/Name $names Bucket/Date $dates \ + ] + } + } + if {$restype eq "owner"} { + return [list [::xsxp::fetch $pxml Owner/ID %PCDATA] \ + [::xsxp::fetch $pxml Owner/DisplayName %PCDATA] ] + } + error "ListAllMyBuckets requires -result-type to be REST, xml, pxml, dict, owner, or names" "" [list S3 usage -result-type $args] +} + +# Public. Create a bucket. +proc S3::PutBucket {args} { + checkinit + set myargs [S3::parseargs1 $args {-blocking -bucket -acl}] + if {![dict exists $myargs -acl]} { + dict set myargs -acl [S3::Configure -default-acl] + } + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict exists $myargs -bucket]} { + error "PutBucket requires -bucket" "" [list S3 usage -bucket $args] + } + + set req [dict create verb PUT resource /[dict get $myargs -bucket]] + if {[dict exists $myargs -acl]} { + dict set req headers [list x-amz-acl [dict get $myargs -acl]] + } + set dict [S3::maybebackground $req $myargs] + S3::throwhttp $dict + return "" ; # until we decide what to return. +} + +# Public. Delete a bucket. +proc S3::DeleteBucket {args} { + checkinit + set myargs [S3::parseargs1 $args {-blocking -bucket}] + if {![dict exists $myargs -bucket]} { + error "DeleteBucket requires -bucket" "" [list S3 usage -bucket $args] + } + dict set myargs -bucket [string trim [dict get $args -bucket] "/ "] + + set req [dict create verb DELETE resource /[dict get $myargs -bucket]] + set dict [S3::maybebackground $req $myargs] + S3::throwhttp $dict + return "" ; # until we decide what to return. +} + +# Internal. Suck out the one and only answer from the list, if needed. +proc S3::firstif {list myargs} { + if {[dict exists $myargs -max-keys]} { + return [lindex $list 0] + } else { + return $list + } +} + +# Public. Get the list of resources within a bucket. +proc S3::GetBucket {args} { + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -parse-xml -max-keys + -result-type -prefix -delimiter + -TEST + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "GetBucket requires -bucket" "" [list S3 usage -bucket $args] + } + if {[dict get $myargs -bucket] eq ""} { + error "GetBucket requires -bucket nonempty" "" \ + [list S3 usage -bucket $args] + } + if {![dict exists $myargs -result-type]} { + dict set myargs -result-type names + } + if {[dict get $myargs -result-type] eq "REST" && \ + [dict exists $myargs "-parse-xml"]} { + error "GetBucket can't have -parse-xml with REST result" "" \ + [list S3 usage -parse-xml $args] + } + set req [dict create verb GET resource /[dict get $myargs -bucket]] + set parameters {} + # Now, just to make test cases easier... + if {[dict exists $myargs -TEST]} { + dict set parameters max-keys [dict get $myargs -TEST] + } + # Back to your regularly scheduled argument parsing + if {[dict exists $myargs -max-keys]} { + dict set parameters max-keys [dict get $myargs -max-keys] + } + if {[dict exists $myargs -prefix]} { + set p [dict get $myargs -prefix] + if {[string match "/*" $p]} { + set p [string range $p 1 end] + } + dict set parameters prefix $p + } + if {[dict exists $myargs -delimiter]} { + dict set parameters delimiter [dict get $myargs -delimiter] + } + set nextmarker0 {} ; # We use this for -result-type dict. + if {![dict exists $myargs -parse-xml]} { + # Go fetch answers. + # Current xaction in "0" vars, with accumulation in "L" vars. + # Ultimate result of this loop is $RESTL, a list of REST results. + set RESTL [list] + while {1} { + set req0 $req ; dict set req0 parameters $parameters + set REST0 [S3::maybebackground $req0 $myargs] + S3::throwhttp $REST0 + lappend RESTL $REST0 + if {[dict exists $myargs -max-keys]} { + # We were given a limit, so just return the answer. + break + } + set pxml0 [::xsxp::parse [dict get $REST0 outbody]] + set trunc0 [expr "true" eq \ + [::xsxp::fetch $pxml0 IsTruncated %PCDATA]] + if {!$trunc0} { + # We've retrieved the final block, so go parse it. + set nextmarker0 "" ; # For later. + break + } + # Find the highest contents entry. (Would have been + # easier if Amazon always supplied NextMarker.) + set nextmarker0 {} + foreach {only tag} {Contents Key CommonPrefixes Prefix} { + set only0 [::xsxp::only $pxml0 $only] + if {0 < [llength $only0]} { + set k0 [::xsxp::fetch [lindex $only0 end] $tag %PCDATA] + if {[string compare $nextmarker0 $k0] < 0} { + set nextmarker0 $k0 + } + } + } + if {$nextmarker0 eq ""} {error "Internal Error in S3 library"} + # Here we have the next marker, so fetch the next REST + dict set parameters marker $nextmarker0 + # Note - $nextmarker0 is used way down below again! + } + # OK, at this point, the caller did not provide the xml via -parse-xml + # And now we have a list of REST results. So let's process. + if {[dict get $myargs -result-type] eq "REST"} { + return [S3::firstif $RESTL $myargs] + } + set xmlL [list] + foreach entry $RESTL { + lappend xmlL [dict get $entry outbody] + } + unset RESTL ; # just to save memory + } else { + # Well, we've parsed out the XML from the REST, + # so we're ready for -parse-xml + set xmlL [list [dict get $myargs -parse-xml]] + } + if {[dict get $myargs -result-type] eq "xml"} { + return [S3::firstif $xmlL $myargs] + } + set pxmlL [list] + foreach xml $xmlL { + lappend pxmlL [::xsxp::parse $xml] + } + unset xmlL + if {[dict get $myargs -result-type] eq "pxml"} { + return [S3::firstif $pxmlL $myargs] + } + # Here, for result types of "names" and "dict", + # we need to actually parse out all the results. + if {[dict get $myargs -result-type] eq "names"} { + # The easy one. + set names [list] + foreach pxml $pxmlL { + set con0 [::xsxp::only $pxml Contents] + set con1 [::xsxp::only $pxml CommonPrefixes] + lappend names {*}[concat [::xsxp::fetchall $con0 Key %PCDATA] \ + [::xsxp::fetchall $con1 Prefix %PCDATA]] + } + return [lsort $names] + } elseif {[dict get $myargs -result-type] eq "dict"} { + # The harder one. + set last0 [lindex $pxmlL end] + set res [dict create] + foreach thing {Name Prefix Marker MaxKeys IsTruncated} { + dict set res $thing [::xsxp::fetch $last0 $thing %PCDATA?] + } + dict set res NextMarker $nextmarker0 ; # From way up above. + set Prefix [list] + set names {Key LastModified ETag Size Owner/ID Owner/DisplayName StorageClass} + foreach name $names {set $name [list]} + foreach pxml $pxmlL { + foreach tag [::xsxp::only $pxml CommonPrefixes] { + lappend Prefix [::xsxp::fetch $tag Prefix %PCDATA] + } + foreach tag [::xsxp::only $pxml Contents] { + foreach name $names { + lappend $name [::xsxp::fetch $tag $name %PCDATA] + } + } + } + dict set res CommonPrefixes/Prefix $Prefix + foreach name $names {dict set res $name [set $name]} + return $res + } else { + # The hardest one ;-) + error "GetBucket Invalid result type, must be REST, xml, pxml, names, or dict" "" [list S3 usage -result-type $args] + } +} + +# Internal. Compare a resource to a file. +# Returns 1 if they're different, 0 if they're the same. +# Note that using If-Modified-Since and/or If-Match,If-None-Match +# might wind up being more efficient than pulling the head +# and checking. However, this allows for slop, checking both +# the etag and the date, only generating local etag if the +# date and length indicate they're the same, and so on. +# Direction is G or P for Get or Put. +# Assumes the source always exists. Obviously, Get and Put will throw if not, +# but not because of this. +proc S3::compare {myargs direction} { + variable config + global errorInfo + set compare [dict get $myargs -compare] + if {$compare ni {always never exists missing newer date checksum different}} { + error "-compare must be always, never, exists, missing, newer, date, checksum, or different" "" \ + [list S3 usage -compare $myargs] + } + if {"never" eq $compare} {return 0} + if {"always" eq $compare} {return 1} + if {[dict exists $myargs -file] && [file exists [dict get $myargs -file]]} { + set local_exists 1 + } else { + set local_exists 0 + } + # Avoid hitting S3 if we don't need to. + if {$direction eq "G" && "exists" eq $compare} {return $local_exists} + if {$direction eq "G" && "missing" eq $compare} { + return [expr !$local_exists] + } + # We need to get the headers from the resource. + set req [dict create \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource] \ + verb HEAD ] + set res [S3::maybebackground $req $myargs] + set httpstatus [dict get $res httpstatus] + if {"404" eq $httpstatus} { + set remote_exists 0 + } elseif {[string match "2??" $httpstatus]} { + set remote_exists 1 + } else { + error "S3: Neither 404 or 2xx on conditional compare" "" \ + [list S3 remote $httpstatus $res] + } + if {$direction eq "P"} { + if {"exists" eq $compare} {return $remote_exists} + if {"missing" eq $compare} {return [expr {!$remote_exists}]} + if {!$remote_exists} {return 1} + } elseif {$direction eq "G"} { + # Actually already handled above, but it never hurts... + if {"exists" eq $compare} {return $local_exists} + if {"missing" eq $compare} {return [expr {!$local_exists}]} + } + set outheaders [dict get $res outheaders] + if {[dict exists $outheaders content-length]} { + set remote_length [dict get $outheaders content-length] + } else { + set remote_length -1 + } + if {[dict exists $outheaders etag]} { + set remote_etag [string tolower \ + [string trim [dict get $outheaders etag] \"]] + } else { + set remote_etag "YYY" + } + if {[dict exists $outheaders last-modified]} { + set remote_date [clock scan [dict get $outheaders last-modified]] + } else { + set remote_date -1 + } + if {[dict exists $myargs -content]} { + # Probably should work this out better... + #set local_length [string length [encoding convert-to utf-8 \ + #[dict get $myargs -content]]] + set local_length [string length [dict get $myargs -content]] + } elseif {$local_exists} { + if {[catch {file size [dict get $myargs -file]} local_length]} { + error "S3: Couldn't stat [dict get $myargs -file]" "" \ + [list S3 local $errorInfo] + } + } else { + set local_length -2 + } + if {[dict exists $myargs -content]} { + set local_date [clock seconds] + } elseif {$local_exists} { + set local_date [file mtime [dict get $myargs -file]] + # Shouldn't throw, since [file size] worked. + } else { + set local_date -2 + } + if {$direction eq "P"} { + if {"newer" eq $compare} { + if {$remote_date < $local_date - [dict get $config -slop-seconds]} { + return 1 ; # Yes, local is newer + } else { + return 0 ; # Older, or the same + } + } + } elseif {$direction eq "G"} { + if {"newer" eq $compare} { + if {$local_date < $remote_date - [dict get $config -slop-seconds]} { + return 1 ; # Yes, remote is later. + } else { + return 0 ; # Local is older or same. + } + } + } + if {[dict get $config -slop-seconds] <= abs($local_date - $remote_date)} { + set date_diff 1 ; # Difference is greater + } else { + set date_diff 0 ; # Difference negligible + } + if {"date" eq $compare} {return $date_diff} + if {"different" eq $compare && [dict exists $myargs -file] && $date_diff} { + return 1 + } + # Date's the same, but we're also interested in content, so check the rest + # Only others to handle are checksum and different-with-matching-dates + if {$local_length != $remote_length} {return 1} ; #easy quick case + if {[dict exists $myargs -file] && $local_exists} { + if {[catch { + # Maybe deal with making this backgroundable too? + set local_etag [string tolower \ + [::md5::md5 -hex -filename [dict get $myargs -file]]] + } caught]} { + # Maybe you can stat but not read it? + error "S3 could not hash file" "" \ + [list S3 local [dict get $myargs -file] $errorInfo] + } + } elseif {[dict exists $myargs -content]} { + set local_etag [string tolower \ + [string tolower [::md5::md5 -hex [dict get $myargs -content]]]] + } else { + set local_etag "XXX" + } + # puts "local: $local_etag\nremote: $remote_etag" + if {$local_etag eq $remote_etag} {return 0} {return 1} +} + +# Internal. Calculates the ACL based on file permissions. +proc S3::calcacl {myargs} { + # How would one work this under Windows, then? + # Silly way: invoke [exec cacls $filename], + # parse the result looking for Everyone:F or Everyone:R + # Messy security if someone replaces the cacls.exe or something. + error "S3 Not Yet Implemented" "" [list S3 notyet calcacl $myargs] + set result [S3::Configure -default-acl] + catch { + set chmod [file attributes [dict get $myargs -file] -permissions] + set chmod [expr {$chmod & 6}] + if {$chmod == 0} {set result private} + if {$chmod == 2} {set result public-write} + if {$chmod == 6} {set result public-read-write} + } +} + +# Public. Put a resource into a bucket. +proc S3::Put {args} { + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -file -content -resource -acl + -content-type -x-amz-meta-* -compare + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Put requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -blocking]} { + dict set myargs -blocking true + } + if {![dict exists $myargs -file] && ![dict exists $myargs -content]} { + error "Put requires -file or -content" "" [list S3 usage -file $args] + } + if {[dict exists $myargs -file] && [dict exists $myargs -content]} { + error "Put says -file, -content mutually exclusive" "" [list S3 usage -file $args] + } + if {![dict exists $myargs -resource]} { + error "Put requires -resource" "" [list S3 usage -resource $args] + } + if {![dict exists $myargs -compare]} { + dict set myargs -compare [S3::Configure -default-compare] + } + if {![dict exists $myargs -acl] && "" ne [S3::Configure -default-acl]} { + dict set myargs -acl [S3::Configure -default-acl] + } + if {[dict exists $myargs -file] && \ + "never" ne [dict get $myargs -compare] && \ + ![file exists [dict get $myargs -file]]} { + error "Put -file doesn't exist: [dict get $myargs -file]" \ + "" [list S3 usage -file $args] + } + # Clean up bucket, and take one leading slash (if any) off resource. + if {[string match "/*" [dict get $myargs -resource]]} { + dict set myargs -resource \ + [string range [dict get $myargs -resource] 1 end] + } + # See if we need to copy it. + set comp [S3::compare $myargs P] + if {!$comp} {return 0} ; # skip it, then. + + # Oookeydookey. At this point, we're actually going to send + # the file, so all we need to do is build the request array. + set req [dict create verb PUT \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource]] + if {[dict exists $myargs -file]} { + dict set req infile [dict get $myargs -file] + } else { + dict set req inbody [dict get $myargs -content] + } + if {[dict exists $myargs -content-type]} { + dict set req content-type [dict get $myargs -content-type] + } + set headers {} + foreach xhead [dict keys $myargs -x-amz-meta-*] { + dict set headers [string range $xhead 1 end] [dict get $myargs $xhead] + } + set xmlacl "" ; # For calc and keep + if {[dict exists $myargs -acl]} { + if {[dict get $myargs -acl] eq "calc"} { + # We could make this more complicated by + # assigning it to xmlacl after building it. + dict set myargs -acl [S3::calcacl $myargs] + } elseif {[dict get $myargs -acl] eq "keep"} { + dict set myargs -acl [S3::Configure -default-acl] + catch { + set xmlacl [S3::GetAcl \ + -bucket [dict get $myargs -bucket] \ + -resource [dict get $myargs -resource] \ + -blocking [dict get $myargs -blocking] \ + -result-type xml] + } + } + dict set headers x-amz-acl [dict get $myargs -acl] + } + dict set req headers $headers + # That should do it. + set res [S3::maybebackground $req $myargs] + S3::throwhttp $res + if {"<" == [string index $xmlacl 0]} { + # Set the saved ACL back on the new object + S3::PutAcl \ + -bucket [dict get $myargs -bucket] \ + -resource [dict get $myargs -resource] \ + -blocking [dict get $myargs -blocking] \ + -acl $xmlacl + } + return 1 ; # Yep, we copied it! +} + +# Public. Get a resource from a bucket. +proc S3::Get {args} { + global errorCode + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -file -content -resource -timestamp + -headers -compare + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Get requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -file] && ![dict exists $myargs -content]} { + error "Get requires -file or -content" "" [list S3 usage -file $args] + } + if {[dict exists $myargs -file] && [dict exists $myargs -content]} { + error "Get says -file, -content mutually exclusive" "" [list S3 usage -file $args] + } + if {![dict exists $myargs -resource]} { + error "Get requires -resource" "" [list S3 usage -resource $args] + } + if {![dict exists $myargs -compare]} { + dict set myargs -compare [S3::Configure -default-compare] + } + # Clean up bucket, and take one leading slash (if any) off resource. + if {[string match "/*" [dict get $myargs -resource]]} { + dict set myargs -resource \ + [string range [dict get $myargs -resource] 1 end] + } + # See if we need to copy it. + if {"never" eq [dict get $myargs -compare]} {return 0} + if {[dict exists $myargs -content]} { + set comp 1 + } else { + set comp [S3::compare $myargs G] + } + if {!$comp} {return 0} ; # skip it, then. + + # Oookeydookey. At this point, we're actually going to fetch + # the file, so all we need to do is build the request array. + set req [dict create verb GET \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource]] + if {[dict exists $myargs -file]} { + set pre_exists [file exists [dict get $myargs -file]] + if {[catch { + set x [open [dict get $myargs -file] w] + fconfigure $x -translation binary -encoding binary + } caught]} { + error "Get could not create file [dict get $myargs -file]" "" \ + [list S3 local -file $errorCode] + } + dict set req outchan $x + } + # That should do it. + set res [S3::maybebackground $req $myargs] + if {[dict exists $req outchan]} { + catch {close [dict get $req outchan]} + if {![string match "2??" [dict get $res httpstatus]] && !$pre_exists} { + catch {file delete -force -- [dict get $myargs -file]} + } + } + S3::throwhttp $res + if {[dict exists $myargs -headers]} { + uplevel 1 \ + [list set [dict get $myargs -headers] [dict get $res outheaders]] + } + if {[dict exists $myargs -content]} { + uplevel 1 \ + [list set [dict get $myargs -content] [dict get $res outbody]] + } + if {[dict exists $myargs -timestamp] && [dict exists $myargs -file]} { + if {"aws" eq [dict get $myargs -timestamp]} { + catch { + set t [dict get $res outheaders last-modified] + set t [clock scan $t -gmt true] + file mtime [dict get $myargs -file] $t + } + } + } + return 1 ; # Yep, we copied it! +} + +# Public. Get information about a resource in a bucket. +proc S3::Head {args} { + global errorCode + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -resource -headers -dict -status + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Head requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -resource]} { + error "Head requires -resource" "" [list S3 usage -resource $args] + } + # Clean up bucket, and take one leading slash (if any) off resource. + if {[string match "/*" [dict get $myargs -resource]]} { + dict set myargs -resource \ + [string range [dict get $myargs -resource] 1 end] + } + set req [dict create verb HEAD \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource]] + set res [S3::maybebackground $req $myargs] + if {[dict exists $myargs -dict]} { + uplevel 1 \ + [list set [dict get $myargs -dict] $res] + } + if {[dict exists $myargs -headers]} { + uplevel 1 \ + [list set [dict get $myargs -headers] [dict get $res outheaders]] + } + if {[dict exists $myargs -status]} { + set x [list [dict get $res httpstatus] [dict get $res httpmessage]] + uplevel 1 \ + [list set [dict get $myargs -status] $x] + } + return [string match "2??" [dict get $res httpstatus]] +} + +# Public. Get the full ACL from an object and parse it into something useful. +proc S3::GetAcl {args} { + global errorCode + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -resource -result-type -parse-xml + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {![dict exists $myargs -result-type]} { + dict set myargs -result-type "dict" + } + set restype [dict get $myargs -result-type] + if {$restype eq "REST" && [dict exists $myargs -parse-xml]} { + error "Do not use REST with -parse-xml" "" \ + [list S3 usage -parse-xml $args] + } + if {![dict exists $myargs -parse-xml]} { + # We need to fetch the results. + if {"" eq [dict get $myargs -bucket]} { + error "GetAcl requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -resource]} { + error "GetAcl requires -resource" "" [list S3 usage -resource $args] + } + # Clean up bucket, and take one leading slash (if any) off resource. + if {[string match "/*" [dict get $myargs -resource]]} { + dict set myargs -resource \ + [string range [dict get $myargs -resource] 1 end] + } + set req [dict create verb GET \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource] \ + rtype acl] + set dict [S3::maybebackground $req $myargs] + if {$restype eq "REST"} { + return $dict ; #we're done! + } + S3::throwhttp $dict ; #make sure it worked. + set xml [dict get $dict outbody] + } else { + set xml [dict get $myargs -parse-xml] + } + if {[dict get $myargs -result-type] == "xml"} { + return $xml + } + set pxml [xsxp::parse $xml] + if {[dict get $myargs -result-type] == "pxml"} { + return $pxml + } + if {[dict get $myargs -result-type] == "dict"} { + array set resdict {} + set owner [xsxp::fetch $pxml Owner/ID %PCDATA] + set grants [xsxp::fetch $pxml AccessControlList %CHILDREN] + foreach grant $grants { + set perm [xsxp::fetch $grant Permission %PCDATA] + set id "" + catch {set id [xsxp::fetch $grant Grantee/ID %PCDATA]} + if {$id == ""} { + set id [xsxp::fetch $grant Grantee/URI %PCDATA] + } + lappend resdict($perm) $id + } + return [dict create owner $owner acl [array get resdict]] + } + error "GetAcl requires -result-type to be REST, xml, pxml or dict" "" [list S3 usage -result-type $args] +} + +# Make one Grant thingie +proc S3::engrant {who what} { + if {$who == "AuthenticatedUsers" || $who == "AllUsers"} { + set who http://acs.amazonaws.com/groups/global/$who + } + if {-1 != [string first "//" $who]} { + set type Group ; set tag URI + } elseif {-1 != [string first "@" $who]} { + set type AmazonCustomerByEmail ; set tag EmailAddress + } else { + set type CanonicalUser ; set tag ID + } + set who [string map {< < > > & &} $who] + set what [string toupper $what] + set xml "<$tag>$who" + append xml "$what" + return $xml +} + +# Make the owner header +proc S3::enowner {owner} { + return "$owner" + return "\n$owner" +} + +proc S3::endacl {} { + return "\n" +} + +# Public. Set the ACL on an existing object. +proc S3::PutAcl {args} { + global errorCode + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -resource -acl -owner + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "PutAcl requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -resource]} { + error "PutAcl requires -resource" "" [list S3 usage -resource $args] + } + if {![dict exists $myargs -acl]} { + dict set myargs -acl [S3::Configure -default-acl] + } + dict set myargs -acl [string trim [dict get $myargs -acl]] + if {[dict get $myargs -acl] == ""} { + dict set myargs -acl [S3::Configure -default-acl] + } + if {[dict get $myargs -acl] == ""} { + error "PutAcl requires -acl" "" [list D3 usage -resource $args] + } + # Clean up bucket, and take one leading slash (if any) off resource. + if {[string match "/*" [dict get $myargs -resource]]} { + dict set myargs -resource \ + [string range [dict get $myargs -resource] 1 end] + } + # Now, figure out the XML to send. + set acl [dict get $myargs -acl] + set owner "" + if {"<" != [string index $acl 0] && ![dict exists $myargs -owner]} { + # Grab the owner off the resource + set req [dict create verb GET \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource] \ + rtype acl] + set dict [S3::maybebackground $req $myargs] + S3::throwhttp $dict ; #make sure it worked. + set xml [dict get $dict outbody] + set pxml [xsxp::parse $xml] + set owner [xsxp::fetch $pxml Owner/ID %PCDATA] + } + if {[dict exists $myargs -owner]} { + set owner [dict get $myargs -owner] + } + set xml [enowner $owner] + if {"" == $acl || "private" == $acl} { + append xml [engrant $owner FULL_CONTROL] + append xml [endacl] + } elseif {"public-read" == $acl} { + append xml [engrant $owner FULL_CONTROL] + append xml [engrant AllUsers READ] + append xml [endacl] + } elseif {"public-read-write" == $acl} { + append xml [engrant $owner FULL_CONTROL] + append xml [engrant AllUsers READ] + append xml [engrant AllUsers WRITE] + append xml [endacl] + } elseif {"authenticated-read" == $acl} { + append xml [engrant $owner FULL_CONTROL] + append xml [engrant AuthenticatedUsers READ] + append xml [endacl] + } elseif {"<" == [string index $acl 0]} { + set xml $acl + } elseif {[llength $acl] % 2 != 0} { + error "S3::PutAcl -acl must be xml, private, public-read, public-read-write, authenticated-read, or a dictionary" \ + "" [list S3 usage -acl $acl] + } else { + # ACL in permission/ID-list format. + if {[dict exists $acl owner] && [dict exists $acl acl]} { + set xml [S3::enowner [dict get $acl owner]] + set acl [dict get $acl acl] + } + foreach perm {FULL_CONTROL READ READ_ACP WRITE WRITE_ACP} { + if {[dict exists $acl $perm]} { + foreach id [dict get $acl $perm] { + append xml [engrant $id $perm] + } + } + } + append xml [endacl] + } + set req [dict create verb PUT \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource] \ + inbody $xml \ + rtype acl] + set res [S3::maybebackground $req $myargs] + S3::throwhttp $res ; #make sure it worked. + return $xml +} + +# Public. Delete a resource from a bucket. +proc S3::Delete {args} { + global errorCode + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -resource -status + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Delete requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -resource]} { + error "Delete requires -resource" "" [list S3 usage -resource $args] + } + # Clean up bucket, and take one leading slash (if any) off resource. + if {[string match "/*" [dict get $myargs -resource]]} { + dict set myargs -resource \ + [string range [dict get $myargs -resource] 1 end] + } + set req [dict create verb DELETE \ + resource /[dict get $myargs -bucket]/[dict get $myargs -resource]] + set res [S3::maybebackground $req $myargs] + if {[dict exists $myargs -status]} { + set x [list [dict get $res httpstatus] [dict get $res httpmessage]] + uplevel 1 \ + [list set [dict get $myargs -status] $x] + } + return [string match "2??" [dict get $res httpstatus]] +} + +# Some helper routines for Push, Pull, and Sync + +# Internal. Filter for fileutil::find. +proc S3::findfilter {dirs name} { + # In particular, skip links, devices, etc. + if {$dirs} { + return [expr {[file isdirectory $name] || [file isfile $name]}] + } else { + return [file isfile $name] + } +} + +# Internal. Get list of local files, appropriately trimmed. +proc S3::getLocal {root dirs} { + # Thanks to Michael Cleverly for this first line... + set base [file normalize [file join [pwd] $root]] + if {![string match "*/" $base]} { + set base $base/ + } + set files {} ; set bl [string length $base] + foreach file [fileutil::find $base [list S3::findfilter $dirs]] { + if {[file isdirectory $file]} { + lappend files [string range $file $bl end]/ + } else { + lappend files [string range $file $bl end] + } + } + set files [lsort $files] + # At this point, $files is a sorted list of all the local files, + # with a trailing / on any directories included in the list. + return $files +} + +# Internal. Get list of remote resources, appropriately trimmed. +proc S3::getRemote {bucket prefix blocking} { + set prefix [string trim $prefix " /"] + if {0 != [string length $prefix]} {append prefix /} + set res [S3::GetBucket -bucket $bucket -prefix $prefix \ + -result-type names -blocking $blocking] + set names {} ; set pl [string length $prefix] + foreach name $res { + lappend names [string range $name $pl end] + } + return [lsort $names] +} + +# Internal. Create any directories we need to put the file in place. +proc S3::makeDirs {directory suffix} { + set sofar {} + set nodes [split $suffix /] + set nodes [lrange $nodes 0 end-1] + foreach node $nodes { + lappend sofar $node + set tocheck [file join $directory {*}$sofar] + if {![file exists $tocheck]} { + catch {file mkdir $tocheck} + } + } +} + +# Internal. Default progress monitor for push, pull, toss. +proc S3::ignore {args} {} ; # default progress monitor + +# Internal. For development and testing. Progress monitor. +proc S3::printargs {args} {puts $args} ; # For testing. + +# Public. Send a local directory tree to S3. +proc S3::Push {args} { + uplevel #0 package require fileutil + global errorCode errorInfo + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -prefix -directory + -compare -x-amz-meta-* -acl -delete -error -progress + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Push requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -directory]} { + error "Push requires -directory" "" [list S3 usage -directory $args] + } + # Set default values. + set defaults " + -acl \"[S3::Configure -default-acl]\" + -compare [S3::Configure -default-compare] + -prefix {} -delete 0 -error continue -progress ::S3::ignore -blocking 1" + foreach {key val} $defaults { + if {![dict exists $myargs $key]} {dict set myargs $key $val} + } + # Pull out arguments for convenience + foreach i {progress prefix directory bucket blocking} { + set $i [dict get $myargs -$i] + } + set prefix [string trimright $prefix /] + set meta [dict filter $myargs key x-amz-meta-*] + # We're readdy to roll here. + uplevel 1 [list {*}$progress args $myargs] + if {[catch { + set local [S3::getLocal $directory 0] + } caught]} { + error "Push could not walk local directory - $caught" \ + $errorInfo $errorCode + } + uplevel 1 [list {*}$progress local $local] + if {[catch { + set remote [S3::getRemote $bucket $prefix $blocking] + } caught]} { + error "Push could not walk remote directory - $caught" \ + $errorInfo $errorCode + } + uplevel 1 [list {*}$progress remote $remote] + set result [dict create] + set result0 [dict create \ + filescopied 0 bytescopied 0 compareskipped 0 \ + errorskipped 0 filesdeleted 0 filesnotdeleted 0] + foreach suffix $local { + uplevel 1 [list {*}$progress copy $suffix start] + set err [catch { + S3::Put -bucket $bucket -blocking $blocking \ + -file [file join $directory $suffix] \ + -resource $prefix/$suffix \ + -acl [dict get $myargs -acl] \ + {*}$meta \ + -compare [dict get $myargs -compare]} caught] + if {$err} { + uplevel 1 [list {*}$progress copy $suffix $errorCode] + dict incr result0 errorskipped + dict set result $suffix $errorCode + if {[dict get $myargs -error] eq "throw"} { + error "Push failed to Put - $caught" $errorInfo $errorCode + } elseif {[dict get $myargs -error] eq "break"} { + break + } + } else { + if {$caught} { + uplevel 1 [list {*}$progress copy $suffix copied] + dict incr result0 filescopied + dict incr result0 bytescopied \ + [file size [file join $directory $suffix]] + dict set result $suffix copied + } else { + uplevel 1 [list {*}$progress copy $suffix skipped] + dict incr result0 compareskipped + dict set result $suffix skipped + } + } + } + # Now do deletes, if so desired + if {[dict get $myargs -delete]} { + foreach suffix $remote { + if {$suffix ni $local} { + set err [catch { + S3::Delete -bucket $bucket -blocking $blocking \ + -resource $prefix/$suffix } caught] + if {$err} { + uplevel 1 [list {*}$progress delete $suffix $errorCode] + dict incr result0 filesnotdeleted + dict set result $suffix notdeleted + } else { + uplevel 1 [list {*}$progress delete $suffix {}] + dict incr result0 filesdeleted + dict set result $suffix deleted + } + } + } + } + dict set result {} $result0 + uplevel 1 [list {*}$progress finished $result] + return $result +} + +# Public. Fetch a portion of a remote bucket into a local directory tree. +proc S3::Pull {args} { + # This is waaaay to similar to Push for comfort. + # Fold it up later. + uplevel #0 package require fileutil + global errorCode errorInfo + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -prefix -directory + -compare -timestamp -delete -error -progress + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Pull requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -directory]} { + error "Pull requires -directory" "" [list S3 usage -directory $args] + } + # Set default values. + set defaults " + -timestamp now + -compare [S3::Configure -default-compare] + -prefix {} -delete 0 -error continue -progress ::S3::ignore -blocking 1" + foreach {key val} $defaults { + if {![dict exists $myargs $key]} {dict set myargs $key $val} + } + # Pull out arguments for convenience + foreach i {progress prefix directory bucket blocking} { + set $i [dict get $myargs -$i] + } + set prefix [string trimright $prefix /] + # We're readdy to roll here. + uplevel 1 [list {*}$progress args $myargs] + if {[catch { + set local [S3::getLocal $directory 1] + } caught]} { + error "Pull could not walk local directory - $caught" \ + $errorInfo $errorCode + } + uplevel 1 [list {*}$progress local $local] + if {[catch { + set remote [S3::getRemote $bucket $prefix $blocking] + } caught]} { + error "Pull could not walk remote directory - $caught" \ + $errorInfo $errorCode + } + uplevel 1 [list {*}$progress remote $remote] + set result [dict create] + set result0 [dict create \ + filescopied 0 bytescopied 0 compareskipped 0 \ + errorskipped 0 filesdeleted 0 filesnotdeleted 0] + foreach suffix $remote { + uplevel 1 [list {*}$progress copy $suffix start] + set err [catch { + S3::makeDirs $directory $suffix + S3::Get -bucket $bucket -blocking $blocking \ + -file [file join $directory $suffix] \ + -resource $prefix/$suffix \ + -timestamp [dict get $myargs -timestamp] \ + -compare [dict get $myargs -compare]} caught] + if {$err} { + uplevel 1 [list {*}$progress copy $suffix $errorCode] + dict incr result0 errorskipped + dict set result $suffix $errorCode + if {[dict get $myargs -error] eq "throw"} { + error "Pull failed to Get - $caught" $errorInfo $errorCode + } elseif {[dict get $myargs -error] eq "break"} { + break + } + } else { + if {$caught} { + uplevel 1 [list {*}$progress copy $suffix copied] + dict incr result0 filescopied + dict incr result0 bytescopied \ + [file size [file join $directory $suffix]] + dict set result $suffix copied + } else { + uplevel 1 [list {*}$progress copy $suffix skipped] + dict incr result0 compareskipped + dict set result $suffix skipped + } + } + } + # Now do deletes, if so desired + if {[dict get $myargs -delete]} { + foreach suffix [lsort -decreasing $local] { + # Note, decreasing because we delete empty dirs + if {[string match "*/" $suffix]} { + set f [file join $directory $suffix] + catch {file delete -- $f} + if {![file exists $f]} { + uplevel 1 [list {*}$progress delete $suffix {}] + dict set result $suffix deleted + dict incr result0 filesdeleted + } + } elseif {$suffix ni $remote} { + set err [catch { + file delete [file join $directory $suffix] + } caught] + if {$err} { + uplevel 1 [list {*}$progress delete $suffix $errorCode] + dict incr result0 filesnotdeleted + dict set result $suffix notdeleted + } else { + uplevel 1 [list {*}$progress delete $suffix {}] + dict incr result0 filesdeleted + dict set result $suffix deleted + } + } + } + } + dict set result {} $result0 + uplevel 1 [list {*}$progress finished $result] + return $result +} + +# Public. Delete a collection of resources with the same prefix. +proc S3::Toss {args} { + # This is waaaay to similar to Push for comfort. + # Fold it up later. + global errorCode errorInfo + checkinit + set myargs [S3::parseargs1 $args { + -bucket -blocking -prefix + -error -progress + }] + if {![dict exists $myargs -bucket]} { + dict set myargs -bucket [S3::Configure -default-bucket] + } + dict set myargs -bucket [string trim [dict get $myargs -bucket] "/ "] + if {"" eq [dict get $myargs -bucket]} { + error "Toss requires -bucket" "" [list S3 usage -bucket $args] + } + if {![dict exists $myargs -prefix]} { + error "Toss requires -prefix" "" [list S3 usage -directory $args] + } + # Set default values. + set defaults "-error continue -progress ::S3::ignore -blocking 1" + foreach {key val} $defaults { + if {![dict exists $myargs $key]} {dict set myargs $key $val} + } + # Pull out arguments for convenience + foreach i {progress prefix bucket blocking} { + set $i [dict get $myargs -$i] + } + set prefix [string trimright $prefix /] + # We're readdy to roll here. + uplevel 1 [list {*}$progress args $myargs] + if {[catch { + set remote [S3::getRemote $bucket $prefix $blocking] + } caught]} { + error "Toss could not walk remote bucket - $caught" \ + $errorInfo $errorCode + } + uplevel 1 [list {*}$progress remote $remote] + set result [dict create] + set result0 [dict create \ + filescopied 0 bytescopied 0 compareskipped 0 \ + errorskipped 0 filesdeleted 0 filesnotdeleted 0] + # Now do deletes + foreach suffix $remote { + set err [catch { + S3::Delete -bucket $bucket -blocking $blocking \ + -resource $prefix/$suffix } caught] + if {$err} { + uplevel 1 [list {*}$progress delete $suffix $errorCode] + dict incr result0 filesnotdeleted + dict set result $suffix notdeleted + } else { + uplevel 1 [list {*}$progress delete $suffix {}] + dict incr result0 filesdeleted + dict set result $suffix deleted + } + } + dict set result {} $result0 + uplevel 1 [list {*}$progress finished $result] + return $result +} diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/pkgIndex.tcl new file mode 100644 index 00000000..1d4f1972 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/pkgIndex.tcl @@ -0,0 +1,9 @@ +# pkgIndex.tcl -- +# Copyright (c) 2006 Darren New +# This is for the Amazon S3 web service packages. + +if {![package vsatisfies [package provide Tcl] 8.5]} {return} + +package ifneeded xsxp 1.0 [list source [file join $dir xsxp.tcl]] +package ifneeded S3 1.0.3 [list source [file join $dir S3.tcl]] + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/xsxp.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/xsxp.tcl new file mode 100644 index 00000000..1b588de6 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/amazon-s3/xsxp.tcl @@ -0,0 +1,254 @@ +# xsxp.tcl -- +# +###Abstract +# Extremely Simple XML Parser +# +# This is pretty lame, but I needed something like this for S3, +# and at the time, TclDOM would not work with the new 8.5 Tcl +# due to version number problems. +# +# In addition, this is a pure-value implementation. There is no +# garbage to clean up in the event of a thrown error, for example. +# This simplifies the code for sufficiently small XML documents, +# which is what Amazon's S3 guarantees. +# +###Copyright +# Copyright (c) 2006 Darren New. +# All Rights Reserved. +# NO WARRANTIES OF ANY TYPE ARE PROVIDED. +# COPYING OR USE INDEMNIFIES THE AUTHOR IN ALL WAYS. +# See the license terms in LICENSE.txt +# +###Revision String +# SCCS: %Z% %M% %I% %E% %U% + +# xsxp::parse $xml +# Returns a parsed XML, or PXML. A pxml is a list. +# The first element is the name of the tag. +# The second element is a list of name/value pairs of the +# associated attribues, if any. +# The third thru final values are recursively PXML values. +# If the first element (element zero, that is) is "%PCDATA", +# then the attributes will be emtpy and the third element +# will be the text of the element. + +# xsxp::fetch $pxml $path ?$part? +# $pxml is a parsed XML, as returned from xsxp::parse. +# $path is a list of elements. Each element is the name of +# a child to look up, optionally followed by a hash ("#") +# and a string of digits. An emtpy list or an initial empty +# element selects $pxml. If no hash sign is present, the +# behavior is as if "#0" had been appended to that element. +# An element of $path scans the children at the indicated +# level for the n'th instance of a child whose tag matches +# the part of the element before the hash sign. If an element +# is simply "#" followed by digits, that indexed child is +# selected, regardless of the tags in the children. So +# an element of #3 will always select the fourth child +# of the node under consideration. +# $part defaults to %ALL. It can be one of the following: +# %ALL - returns the entire selected element. +# %TAGNAME - returns lindex 0 of the selected element. +# %ATTRIBUTES - returns lindex 1 of the selected element. +# %CHILDREN - returns lrange 2 through end of the selected element, +# resulting in a list of elements being returned. +# %PCDATA - returns a concatenation of all the bodies of +# direct children of this node whose tag is %PCDATA. +# Throws an error if no such children are found. That +# is, part=%PCDATA means return the textual content found +# in that node but not its children nodes. +# %PCDATA? - like %PCDATA, but returns an empty string if +# no PCDATA is found. + +# xsxp::fetchall $pxml_list $path ?$part? +# Iterates over each PXML in $pxml_list, selecting the indicated +# path from it, building a new list with the selected data, and +# returning that new list. For example, $pxml_list might be +# the %CHILDREN of a particular element, and the $path and $part +# might select from each child a sub-element in which we're interested. + +# xsxp::only $pxml $tagname +# Iterates over the direct children of $pxml and selects only +# those with $tagname as their tag. Returns a list of matching +# elements. + +# xsxp::prettyprint $pxml +# Outputs to stdout a nested-list notation of the parsed XML. + +package require xml +package provide xsxp 1.0 + +namespace eval xsxp { + + variable Stack + variable Cur + + proc Characterdatacommand {characterdata} { + variable Cur + # puts "characterdatacommand $characterdata" + set x [list %PCDATA {} $characterdata] + lappend Cur $x + } + + proc Elementstartcommand {name attlist args} { + # puts "elementstart $name {$attlist} $args" + variable Stack + variable Cur + lappend Stack $Cur + set Cur [list $name $attlist] + } + + proc Elementendcommand {args} { + # puts "elementend $args" + variable Stack + variable Cur + set x [lindex $Stack end] + lappend x $Cur + set Cur $x + set Stack [lrange $Stack 0 end-1] + } + + proc parse {xml} { + variable Cur + variable Stack + set Cur {} + set Stack {} + set parser [::xml::parser \ + -characterdatacommand [namespace code Characterdatacommand] \ + -elementstartcommand [namespace code Elementstartcommand] \ + -elementendcommand [namespace code Elementendcommand] \ + -ignorewhitespace 1 -final 1 + ] + $parser parse $xml + $parser free + # The following line is needed because the close of the last element + # appends the outermost element to the item on the top of the stack. + # Since there's nothing on the top of the stack at the close of the + # last element, we append the current element to an empty list. + # In essence, since we don't really have a terminating condition + # on the recursion, an empty stack is still treated like an element. + set Cur [lindex $Cur 0] + set Cur [Normalize $Cur] + return $Cur + } + + proc Normalize {pxml} { + # This iterates over pxml recursively, finding entries that + # start with multiple %PCDATA elements, and coalesces their + # content, so if an element contains only %PCDATA, it is + # guaranteed to have only one child. + # Not really necessary, given definition of part=%PCDATA + # However, it makes pretty-prints nicer (for AWS at least) + # and ends up with smaller lists. I have no idea why they + # would put quotes around an MD5 hash in hex, tho. + set dupl 1 + while {$dupl} { + set first [lindex $pxml 2] + set second [lindex $pxml 3] + if {[lindex $first 0] eq "%PCDATA" && [lindex $second 0] eq "%PCDATA"} { + set repl [list %PCDATA {} [lindex $first 2][lindex $second 2]] + set pxml [lreplace $pxml 2 3 $repl] + } else { + set dupl 0 + for {set i 2} {$i < [llength $pxml]} {incr i} { + set pxml [lreplace $pxml $i $i [Normalize [lindex $pxml $i]]] + } + } + } + return $pxml + } + + proc prettyprint {pxml {chan stdout} {indent 0}} { + puts -nonewline $chan [string repeat " " $indent] + if {[lindex $pxml 0] eq "%PCDATA"} { + puts $chan "%PCDATA: [lindex $pxml 2]" + return + } + puts -nonewline $chan "[lindex $pxml 0]" + foreach {name val} [lindex $pxml 1] { + puts -nonewline $chan " $name='$val'" + } + puts $chan "" + foreach node [lrange $pxml 2 end] { + prettyprint $node $chan [expr $indent+1] + } + } + + proc fetch {pxml path {part %ALL}} { + set path [string trim $path /] + if {-1 != [string first / $path]} { + set path [split $path /] + } + foreach element $path { + if {$pxml eq ""} {return ""} + foreach {tag count} [split $element #] { + if {$tag ne ""} { + if {$count eq ""} {set count 0} + set pxml [lrange $pxml 2 end] + while {0 <= $count && 0 != [llength $pxml]} { + if {$tag eq [lindex $pxml 0 0]} { + incr count -1 + if {$count < 0} { + # We're done. Go on to next element. + set pxml [lindex $pxml 0] + } else { + # Not done yet. Throw this away. + set pxml [lrange $pxml 1 end] + } + } else { + # Not what we want. + set pxml [lrange $pxml 1 end] + } + } + } else { # tag eq "" + if {$count eq ""} { + # Just select whole $pxml + } else { + set pxml [lindex $pxml [expr {2+$count}]] + } + } + break + } ; # done the foreach [split] loop + } ; # done all the elements. + if {$part eq "%ALL"} {return $pxml} + if {$part eq "%ATTRIBUTES"} {return [lindex $pxml 1]} + if {$part eq "%TAGNAME"} {return [lindex $pxml 0]} + if {$part eq "%CHILDREN"} {return [lrange $pxml 2 end]} + if {$part eq "%PCDATA" || $part eq "%PCDATA?"} { + set res "" ; set found 0 + foreach elem [lrange $pxml 2 end] { + if {"%PCDATA" eq [lindex $elem 0]} { + append res [lindex $elem 2] + set found 1 + } + } + if {$found || $part eq "%PCDATA?"} { + return $res + } else { + error "xsxp::fetch did not find requested PCDATA" + } + } + return $pxml ; # Don't know what he's after + } + + proc only {pxml tag} { + set res {} + foreach element [lrange $pxml 2 end] { + if {[lindex $element 0] eq $tag} { + lappend res $element + } + } + return $res + } + + proc fetchall {pxml_list path {part %ALL}} { + set res [list] + foreach pxml $pxml_list { + lappend res [fetch $pxml $path $part] + } + return $res + } +} + +namespace export xsxp parse prettyprint fetch + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/asn/asn.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/asn/asn.tcl new file mode 100644 index 00000000..cca460af --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/asn/asn.tcl @@ -0,0 +1,1580 @@ +#----------------------------------------------------------------------------- +# Copyright (C) 1999-2004 Jochen C. Loewer (loewerj@web.de) +# Copyright (C) 2004-2011 Michael Schlenker (mic42@users.sourceforge.net) +#----------------------------------------------------------------------------- +# +# A partial ASN decoder/encoder implementation in plain Tcl. +# +# See ASN.1 (X.680) and BER (X.690). +# See 'asn_ber_intro.txt' in this directory. +# +# This software is copyrighted by Jochen C. Loewer (loewerj@web.de). 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. +# +# written by Jochen Loewer +# 3 June, 1999 +# +# $Id: asn.tcl,v 1.20 2011/01/05 22:33:33 mic42 Exp $ +# +#----------------------------------------------------------------------------- + +# needed for using wide() +package require Tcl 8.4 + +namespace eval asn { + # Encoder commands + namespace export \ + asnSequence \ + asnSequenceFromList \ + asnSet \ + asnSetFromList \ + asnApplicationConstr \ + asnApplication \ + asnContext\ + asnContextConstr\ + asnChoice \ + asnChoiceConstr \ + asnInteger \ + asnEnumeration \ + asnBoolean \ + asnOctetString \ + asnNull \ + asnUTCTime \ + asnNumericString \ + asnPrintableString \ + asnIA5String\ + asnBMPString\ + asnUTF8String\ + asnBitString \ + asnObjectIdentifer + + # Decoder commands + namespace export \ + asnGetResponse \ + asnGetInteger \ + asnGetEnumeration \ + asnGetOctetString \ + asnGetSequence \ + asnGetSet \ + asnGetApplication \ + asnGetNumericString \ + asnGetPrintableString \ + asnGetIA5String \ + asnGetBMPString \ + asnGetUTF8String \ + asnGetObjectIdentifier \ + asnGetBoolean \ + asnGetUTCTime \ + asnGetBitString \ + asnGetContext + + # general BER utility commands + namespace export \ + asnPeekByte \ + asnGetLength \ + asnRetag \ + asnPeekTag \ + asnTag + +} + +#----------------------------------------------------------------------------- +# Implementation notes: +# +# See the 'asn_ber_intro.txt' in this directory for an introduction +# into BER/DER encoding of ASN.1 information. Bibliography information +# +# A Layman's Guide to a Subset of ASN.1, BER, and DER +# +# An RSA Laboratories Technical Note +# Burton S. Kaliski Jr. +# Revised November 1, 1993 +# +# Supersedes June 3, 1991 version, which was also published as +# NIST/OSI Implementors' Workshop document SEC-SIG-91-17. +# PKCS documents are available by electronic mail to +# . +# +# Copyright (C) 1991-1993 RSA Laboratories, a division of RSA +# Data Security, Inc. License to copy this document is granted +# provided that it is identified as "RSA Data Security, Inc. +# Public-Key Cryptography Standards (PKCS)" in all material +# mentioning or referencing this document. +# 003-903015-110-000-000 +# +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# asnLength : Encode some length data. Helper command. +#----------------------------------------------------------------------------- + +proc ::asn::asnLength {len} { + + if {$len < 0} { + return -code error "Negative length octet requested" + } + if {$len < 128} { + # short form: ISO X.690 8.1.3.4 + return [binary format c $len] + } + # long form: ISO X.690 8.1.3.5 + # try to use a minimal encoding, + # even if not required by BER, but it is required by DER + # take care for signed vs. unsigned issues + if {$len < 256 } { + return [binary format H2c 81 [expr {$len - 256}]] + } + if {$len < 32769} { + # two octet signed value + return [binary format H2S 82 $len] + } + if {$len < 65536} { + return [binary format H2S 82 [expr {$len - 65536}]] + } + if {$len < 8388608} { + # three octet signed value + return [binary format H2cS 83 [expr {$len >> 16}] [expr {($len & 0xFFFF) - 65536}]] + } + if {$len < 16777216} { + # three octet signed value + return [binary format H2cS 83 [expr {($len >> 16) -256}] [expr {($len & 0xFFFF) -65536}]] + } + if {$len < 2147483649} { + # four octet signed value + return [binary format H2I 84 $len] + } + if {$len < 4294967296} { + # four octet unsigned value + return [binary format H2I 84 [expr {$len - 4294967296}]] + } + if {$len < 1099511627776} { + # five octet unsigned value + return [binary format H2 85][string range [binary format W $len] 3 end] + } + if {$len < 281474976710656} { + # six octet unsigned value + return [binary format H2 86][string range [binary format W $len] 2 end] + } + if {$len < 72057594037927936} { + # seven octet value + return [binary format H2 87][string range [binary format W $len] 1 end] + } + + # must be a 64-bit wide signed value + return [binary format H2W 88 $len] +} + +#----------------------------------------------------------------------------- +# asnSequence : Assumes that the arguments are already ASN encoded. +#----------------------------------------------------------------------------- + +proc ::asn::asnSequence {args} { + asnSequenceFromList $args +} + +proc ::asn::asnSequenceFromList {lst} { + # The sequence tag is 0x30. The length is arbitrary and thus full + # length coding is required. The arguments have to be BER encoded + # already. Constructed value, definite-length encoding. + + set out "" + foreach part $lst { + append out $part + } + set len [string length $out] + return [binary format H2a*a$len 30 [asnLength $len] $out] +} + + +#----------------------------------------------------------------------------- +# asnSet : Assumes that the arguments are already ASN encoded. +#----------------------------------------------------------------------------- + +proc ::asn::asnSet {args} { + asnSetFromList $args +} + +proc ::asn::asnSetFromList {lst} { + # The set tag is 0x31. The length is arbitrary and thus full + # length coding is required. The arguments have to be BER encoded + # already. + + set out "" + foreach part $lst { + append out $part + } + set len [string length $out] + return [binary format H2a*a$len 31 [asnLength $len] $out] +} + + +#----------------------------------------------------------------------------- +# asnApplicationConstr +#----------------------------------------------------------------------------- + +proc ::asn::asnApplicationConstr {appNumber args} { + # Packs the arguments into a constructed value with application tag. + + set out "" + foreach part $args { + append out $part + } + set code [expr {0x060 + $appNumber}] + set len [string length $out] + return [binary format ca*a$len $code [asnLength $len] $out] +} + +#----------------------------------------------------------------------------- +# asnApplication +#----------------------------------------------------------------------------- + +proc ::asn::asnApplication {appNumber data} { + # Packs the arguments into a constructed value with application tag. + + set code [expr {0x040 + $appNumber}] + set len [string length $data] + return [binary format ca*a$len $code [asnLength $len] $data] +} + +#----------------------------------------------------------------------------- +# asnContextConstr +#----------------------------------------------------------------------------- + +proc ::asn::asnContextConstr {contextNumber args} { + # Packs the arguments into a constructed value with application tag. + + set out "" + foreach part $args { + append out $part + } + set code [expr {0x0A0 + $contextNumber}] + set len [string length $out] + return [binary format ca*a$len $code [asnLength $len] $out] +} + +#----------------------------------------------------------------------------- +# asnContext +#----------------------------------------------------------------------------- + +proc ::asn::asnContext {contextNumber data} { + # Packs the arguments into a constructed value with application tag. + set code [expr {0x080 + $contextNumber}] + set len [string length $data] + return [binary format ca*a$len $code [asnLength $len] $data] +} +#----------------------------------------------------------------------------- +# asnChoice +#----------------------------------------------------------------------------- + +proc ::asn::asnChoice {appNumber args} { + # Packs the arguments into a choice construction. + + set out "" + foreach part $args { + append out $part + } + set code [expr {0x080 + $appNumber}] + set len [string length $out] + return [binary format ca*a$len $code [asnLength $len] $out] +} + +#----------------------------------------------------------------------------- +# asnChoiceConstr +#----------------------------------------------------------------------------- + +proc ::asn::asnChoiceConstr {appNumber args} { + # Packs the arguments into a choice construction. + + set out "" + foreach part $args { + append out $part + } + set code [expr {0x0A0 + $appNumber}] + set len [string length $out] + return [binary format ca*a$len $code [asnLength $len] $out] +} + +#----------------------------------------------------------------------------- +# asnInteger : Encode integer value. +#----------------------------------------------------------------------------- + +proc ::asn::asnInteger {number} { + asnIntegerOrEnum 02 $number +} + +#----------------------------------------------------------------------------- +# asnEnumeration : Encode enumeration value. +#----------------------------------------------------------------------------- + +proc ::asn::asnEnumeration {number} { + asnIntegerOrEnum 0a $number +} + +#----------------------------------------------------------------------------- +# asnIntegerOrEnum : Common code for Integers and Enumerations +# No Bignum version, as we do not expect large Enums. +#----------------------------------------------------------------------------- + +proc ::asn::asnIntegerOrEnum {tag number} { + # The integer tag is 0x02 , the Enum Tag 0x0a otherwise identical. + # The length is 1, 2, 3, or 4, coded in a + # single byte. This can be done directly, no need to go through + # asnLength. The value itself is written in big-endian. + + # Known bug/issue: The command cannot handle very wide integers, i.e. + # anything above 8 bytes length. Use asnBignumInteger for those. + + # check if we really have an int + set num $number + incr num + + if {($number >= -128) && ($number < 128)} { + return [binary format H2H2c $tag 01 $number] + } + if {($number >= -32768) && ($number < 32768)} { + return [binary format H2H2S $tag 02 $number] + } + if {($number >= -8388608) && ($number < 8388608)} { + set numberb [expr {$number & 0xFFFF}] + set numbera [expr {($number >> 16) & 0xFF}] + return [binary format H2H2cS $tag 03 $numbera $numberb] + } + if {($number >= -2147483648) && ($number < 2147483648)} { + return [binary format H2H2I $tag 04 $number] + } + if {($number >= -549755813888) && ($number < 549755813888)} { + set numberb [expr {$number & 0xFFFFFFFF}] + set numbera [expr {($number >> 32) & 0xFF}] + return [binary format H2H2cI $tag 05 $numbera $numberb] + } + if {($number >= -140737488355328) && ($number < 140737488355328)} { + set numberb [expr {$number & 0xFFFFFFFF}] + set numbera [expr {($number >> 32) & 0xFFFF}] + return [binary format H2H2SI $tag 06 $numbera $numberb] + } + if {($number >= -36028797018963968) && ($number < 36028797018963968)} { + set numberc [expr {$number & 0xFFFFFFFF}] + set numberb [expr {($number >> 32) & 0xFFFF}] + set numbera [expr {($number >> 48) & 0xFF}] + return [binary format H2H2cSI $tag 07 $numbera $numberb $numberc] + } + if {($number >= -9223372036854775808) && ($number <= 9223372036854775807)} { + return [binary format H2H2W $tag 08 $number] + } + return -code error "Integer value to large to encode, use asnBigInteger" +} + +#----------------------------------------------------------------------------- +# asnBigInteger : Encode a long integer value using math::bignum +#----------------------------------------------------------------------------- + +proc ::asn::asnBigInteger {bignum} { + # require math::bignum only if it is used + package require math::bignum + + # this is a hack to check for bignum... + if {[llength $bignum] < 2 || ([lindex $bignum 0] ne "bignum")} { + return -code error "expected math::bignum value got \"$bignum\"" + } + if {[math::bignum::sign $bignum]} { + # generate two's complement form + set bits [math::bignum::bits $bignum] + set padding [expr {$bits % 8}] + set len [expr {int(ceil($bits / 8.0))}] + if {$padding == 0} { + # we need a complete extra byte for the sign + # unless this is a base 2 multiple + set test [math::bignum::fromstr 0] + math::bignum::setbit test [expr {$bits-1}] + if {[math::bignum::ne [math::bignum::abs $bignum] $test]} { + incr len + } + } + set exp [math::bignum::pow \ + [math::bignum::fromstr 256] \ + [math::bignum::fromstr $len]] + set bignum [math::bignum::add $bignum $exp] + set hex [math::bignum::tostr $bignum 16] + } else { + set bits [math::bignum::bits $bignum] + if {($bits % 8) == 0 && $bits > 0} { + set pad "00" + } else { + set pad "" + } + set hex $pad[math::bignum::tostr $bignum 16] + } + if {[string length $hex]%2} { + set hex "0$hex" + } + set octets [expr {(([string length $hex]+1)/2)}] + return [binary format H2a*H* 02 [asnLength $octets] $hex] +} + + +#----------------------------------------------------------------------------- +# asnBoolean : Encode a boolean value. +#----------------------------------------------------------------------------- + +proc ::asn::asnBoolean {bool} { + # The boolean tag is 0x01. The length is always 1, coded in + # a single byte. This can be done directly, no need to go through + # asnLength. The value itself is written in big-endian. + + return [binary format H2H2c 01 01 [expr {$bool ? 0x0FF : 0x0}]] +} + +#----------------------------------------------------------------------------- +# asnOctetString : Encode a string of arbitrary bytes +#----------------------------------------------------------------------------- + +proc ::asn::asnOctetString {string} { + # The octet tag is 0x04. The length is arbitrary, so we need + # 'asnLength' for full coding of the length. + + set len [string length $string] + return [binary format H2a*a$len 04 [asnLength $len] $string] +} + +#----------------------------------------------------------------------------- +# asnNull : Encode a null value +#----------------------------------------------------------------------------- + +proc ::asn::asnNull {} { + # Null has only one valid encoding + return \x05\x00 +} + +#----------------------------------------------------------------------------- +# asnBitstring : Encode a Bit String value +#----------------------------------------------------------------------------- + +proc ::asn::asnBitString {bitstring} { + # The bit string tag is 0x03. + # Bit strings can be either simple or constructed + # we always use simple encoding + + set bitlen [string length $bitstring] + set padding [expr {(8 - ($bitlen % 8)) % 8}] + set len [expr {($bitlen / 8) + 1}] + if {$padding != 0} { incr len } + + return [binary format H2a*cB* 03 [asnLength $len] $padding $bitstring] +} + +#----------------------------------------------------------------------------- +# asnUTCTime : Encode an UTC time string +#----------------------------------------------------------------------------- + +proc ::asn::asnUTCTime {UTCtimestring} { + # the utc time tag is 0x17. + # + # BUG: we do not check the string for well formedness + + set ascii [encoding convertto ascii $UTCtimestring] + set len [string length $ascii] + return [binary format H2a*a* 17 [asnLength $len] $ascii] +} + +#----------------------------------------------------------------------------- +# asnPrintableString : Encode a printable string +#----------------------------------------------------------------------------- +namespace eval asn { + variable nonPrintableChars {[^ A-Za-z0-9'()+,.:/?=-]} +} +proc ::asn::asnPrintableString {string} { + # the printable string tag is 0x13 + variable nonPrintableChars + # it is basically a restricted ascii string + if {[regexp $nonPrintableChars $string ]} { + return -code error "Illegal character in PrintableString." + } + + # check characters + set ascii [encoding convertto ascii $string] + return [asnEncodeString 13 $ascii] +} + +#----------------------------------------------------------------------------- +# asnIA5String : Encode an Ascii String +#----------------------------------------------------------------------------- +proc ::asn::asnIA5String {string} { + # the IA5 string tag is 0x16 + # check for extended charachers + if {[string length $string]!=[string bytelength $string]} { + return -code error "Illegal character in IA5String" + } + set ascii [encoding convertto ascii $string] + return [asnEncodeString 16 $ascii] +} + +#----------------------------------------------------------------------------- +# asnNumericString : Encode a Numeric String type +#----------------------------------------------------------------------------- +namespace eval asn { + variable nonNumericChars {[^0-9 ]} +} +proc ::asn::asnNumericString {string} { + # the Numeric String type has tag 0x12 + variable nonNumericChars + if {[regexp $nonNumericChars $string]} { + return -code error "Illegal character in Numeric String." + } + + return [asnEncodeString 12 $string] +} +#---------------------------------------------------------------------- +# asnBMPString: Encode a Tcl string as Basic Multinligval (UCS2) string +#----------------------------------------------------------------------- +proc asn::asnBMPString {string} { + if {$::tcl_platform(byteOrder) eq "littleEndian"} { + set bytes "" + foreach {lo hi} [split [encoding convertto unicode $string] ""] { + append bytes $hi $lo + } + } else { + set bytes [encoding convertto unicode $string] + } + return [asnEncodeString 1e $bytes] +} +#--------------------------------------------------------------------------- +# asnUTF8String: encode tcl string as UTF8 String +#---------------------------------------------------------------------------- +proc asn::asnUTF8String {string} { + return [asnEncodeString 0c [encoding convertto utf-8 $string]] +} +#----------------------------------------------------------------------------- +# asnEncodeString : Encode an RestrictedCharacter String +#----------------------------------------------------------------------------- +proc ::asn::asnEncodeString {tag string} { + set len [string length $string] + return [binary format H2a*a$len $tag [asnLength $len] $string] +} + +#----------------------------------------------------------------------------- +# asnObjectIdentifier : Encode an Object Identifier value +#----------------------------------------------------------------------------- +proc ::asn::asnObjectIdentifier {oid} { + # the object identifier tag is 0x06 + + if {[llength $oid] < 2} { + return -code error "OID must have at least two subidentifiers." + } + + # basic check that it is valid + foreach identifier $oid { + if {$identifier < 0} { + return -code error \ + "Malformed OID. Identifiers must be positive Integers." + } + } + + if {[lindex $oid 0] > 2} { + return -code error "First subidentifier must be 0,1 or 2" + } + if {[lindex $oid 1] > 39} { + return -code error \ + "Second subidentifier must be between 0 and 39" + } + + # handle the special cases directly + switch [llength $oid] { + 2 { return [binary format H2H2c 06 01 \ + [expr {[lindex $oid 0]*40+[lindex $oid 1]}]] } + default { + # This can probably be written much shorter. + # Just a first try that works... + # + set octets [binary format c \ + [expr {[lindex $oid 0]*40+[lindex $oid 1]}]] + foreach identifier [lrange $oid 2 end] { + set d 128 + if {$identifier < 128} { + set subidentifier [list $identifier] + } else { + set subidentifier [list] + # find the largest divisor + + while {($identifier / $d) >= 128} { + set d [expr {$d * 128}] + } + # and construct the subidentifiers + set remainder $identifier + while {$d >= 128} { + set coefficient [expr {($remainder / $d) | 0x80}] + set remainder [expr {$remainder % $d}] + set d [expr {$d / 128}] + lappend subidentifier $coefficient + } + lappend subidentifier $remainder + } + append octets [binary format c* $subidentifier] + } + return [binary format H2a*a* 06 \ + [asnLength [string length $octets]] $octets] + } + } + +} + +#----------------------------------------------------------------------------- +# asnGetResponse : Read a ASN response from a channel. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetResponse {sock data_var} { + upvar 1 $data_var data + + # We expect a sequence here (tag 0x30). The code below is an + # inlined replica of 'asnGetSequence', modified for reading from a + # channel instead of a string. + + set tag [read $sock 1] + + if {$tag == "\x30"} { + # The following code is a replica of 'asnGetLength', modified + # for reading the bytes from the channel instead of a string. + + set len1 [read $sock 1] + binary scan $len1 c num + set length [expr {($num + 0x100) % 0x100}] + + if {$length >= 0x080} { + # The byte the read is not the length, but a prefix, and + # the lower nibble tells us how many bytes follow. + + set len_length [expr {$length & 0x7f}] + + # BUG: We should not perform the value extraction for an + # BUG: improper length. It wastes cycles, and here it can + # BUG: cause us trouble, reading more data than there is + # BUG: on the channel. Depending on the channel + # BUG: configuration an attacker can induce us to block, + # BUG: causing a denial of service. + set lengthBytes [read $sock $len_length] + + switch $len_length { + 1 { + binary scan $lengthBytes c length + set length [expr {($length + 0x100) % 0x100}] + } + 2 { binary scan $lengthBytes S length } + 3 { binary scan \x00$lengthBytes I length } + 4 { binary scan $lengthBytes I length } + default { + return -code error \ + "length information too long ($len_length)" + } + } + } + + # Now that the length is known we get the remainder, + # i.e. payload, and construct proper in-memory BER encoded + # sequence. + + set rest [read $sock $length] + set data [binary format aa*a$length $tag [asnLength $length] $rest] + } else { + # Generate an error message if the data is not a sequence as + # we expected. + + set tag_hex "" + binary scan $tag H2 tag_hex + return -code error "unknown start tag [string length $tag] $tag_hex" + } +} + +if {[package vsatisfies [package present Tcl] 8.5.0]} { +############################################################################## +# Code for 8.5 +############################################################################## +#----------------------------------------------------------------------------- +# asnGetByte (8.5 version) : Retrieve a single byte from the data (unsigned) +#----------------------------------------------------------------------------- + +proc ::asn::asnGetByte {data_var byte_var} { + upvar 1 $data_var data $byte_var byte + + binary scan [string index $data 0] cu byte + set data [string range $data 1 end] + + return +} + +#----------------------------------------------------------------------------- +# asnPeekByte (8.5 version) : Retrieve a single byte from the data (unsigned) +# without removing it. +#----------------------------------------------------------------------------- + +proc ::asn::asnPeekByte {data_var byte_var {offset 0}} { + upvar 1 $data_var data $byte_var byte + + binary scan [string index $data $offset] cu byte + + return +} + +#----------------------------------------------------------------------------- +# asnGetLength (8.5 version) : Decode an ASN length value (See notes) +#----------------------------------------------------------------------------- + +proc ::asn::asnGetLength {data_var length_var} { + upvar 1 $data_var data $length_var length + + asnGetByte data length + if {$length == 0x080} { + return -code error "Indefinite length BER encoding not yet supported" + } + if {$length > 0x080} { + # The retrieved byte is a prefix value, and the integer in the + # lower nibble tells us how many bytes were used to encode the + # length data following immediately after this prefix. + + set len_length [expr {$length & 0x7f}] + + if {[string length $data] < $len_length} { + return -code error \ + "length information invalid, not enough octets left" + } + + asnGetBytes data $len_length lengthBytes + + switch $len_length { + 1 { binary scan $lengthBytes cu length } + 2 { binary scan $lengthBytes Su length } + 3 { binary scan \x00$lengthBytes Iu length } + 4 { binary scan $lengthBytes Iu length } + default { + binary scan $lengthBytes H* hexstr + scan $hexstr %llx length + } + } + } + return +} + +} else { +############################################################################## +# Code for Tcl 8.4 +############################################################################## +#----------------------------------------------------------------------------- +# asnGetByte : Retrieve a single byte from the data (unsigned) +#----------------------------------------------------------------------------- + +proc ::asn::asnGetByte {data_var byte_var} { + upvar 1 $data_var data $byte_var byte + + binary scan [string index $data 0] c byte + set byte [expr {($byte + 0x100) % 0x100}] + set data [string range $data 1 end] + + return +} + +#----------------------------------------------------------------------------- +# asnPeekByte : Retrieve a single byte from the data (unsigned) +# without removing it. +#----------------------------------------------------------------------------- + +proc ::asn::asnPeekByte {data_var byte_var {offset 0}} { + upvar 1 $data_var data $byte_var byte + + binary scan [string index $data $offset] c byte + set byte [expr {($byte + 0x100) % 0x100}] + + return +} + +#----------------------------------------------------------------------------- +# asnGetLength : Decode an ASN length value (See notes) +#----------------------------------------------------------------------------- + +proc ::asn::asnGetLength {data_var length_var} { + upvar 1 $data_var data $length_var length + + asnGetByte data length + if {$length == 0x080} { + return -code error "Indefinite length BER encoding not yet supported" + } + if {$length > 0x080} { + # The retrieved byte is a prefix value, and the integer in the + # lower nibble tells us how many bytes were used to encode the + # length data following immediately after this prefix. + + set len_length [expr {$length & 0x7f}] + + if {[string length $data] < $len_length} { + return -code error \ + "length information invalid, not enough octets left" + } + + asnGetBytes data $len_length lengthBytes + + switch $len_length { + 1 { + # Efficiently coded data will not go through this + # path, as small length values can be coded directly, + # without a prefix. + + binary scan $lengthBytes c length + set length [expr {($length + 0x100) % 0x100}] + } + 2 { binary scan $lengthBytes S length + set length [expr {($length + 0x10000) % 0x10000}] + } + 3 { binary scan \x00$lengthBytes I length + set length [expr {($length + 0x1000000) % 0x1000000}] + } + 4 { binary scan $lengthBytes I length + set length [expr {(wide($length) + 0x100000000) % 0x100000000}] + } + default { + binary scan $lengthBytes H* hexstr + # skip leading zeros which are allowed by BER + set hexlen [string trimleft $hexstr 0] + # check if it fits into a 64-bit signed integer + if {[string length $hexlen] > 16} { + return -code error -errorcode {ARITH IOVERFLOW + {Length value too large for normal use, try asnGetBigLength}} \ + "Length value to large" + } elseif { [string length $hexlen] == 16 \ + && ([string index $hexlen 0] & 0x8)} { + # check most significant bit, if set we need bignum + return -code error -errorcode {ARITH IOVERFLOW + {Length value too large for normal use, try asnGetBigLength}} \ + "Length value to large" + } else { + scan $hexstr "%lx" length + } + } + } + } + return +} + +} + +#----------------------------------------------------------------------------- +# asnRetag: Remove an explicit tag with the real newTag +# +#----------------------------------------------------------------------------- +proc ::asn::asnRetag {data_var newTag} { + upvar 1 $data_var data + set tag "" + set type "" + set len [asnPeekTag data tag type dummy] + asnGetBytes data $len tagbytes + set data [binary format c* $newTag]$data +} + +#----------------------------------------------------------------------------- +# asnGetBytes : Retrieve a block of 'length' bytes from the data. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetBytes {data_var length bytes_var} { + upvar 1 $data_var data $bytes_var bytes + + incr length -1 + set bytes [string range $data 0 $length] + incr length + set data [string range $data $length end] + + return +} + +#----------------------------------------------------------------------------- +# asnPeekTag : Decode the tag value +#----------------------------------------------------------------------------- + +proc ::asn::asnPeekTag {data_var tag_var tagtype_var constr_var} { + upvar 1 $data_var data $tag_var tag $tagtype_var tagtype $constr_var constr + + set type 0 + set offset 0 + asnPeekByte data type $offset + # check if we have a simple tag, < 31, which fits in one byte + + set tval [expr {$type & 0x1f}] + if {$tval == 0x1f} { + # long tag, max 64-bit with Tcl 8.4, unlimited with 8.5 bignum + asnPeekByte data tagbyte [incr offset] + set tval [expr {wide($tagbyte & 0x7f)}] + while {($tagbyte & 0x80)} { + asnPeekByte data tagbyte [incr offset] + set tval [expr {($tval << 7) + ($tagbyte & 0x7f)}] + } + } + + set tagtype [lindex {UNIVERSAL APPLICATION CONTEXT PRIVATE} \ + [expr {($type & 0xc0) >>6}]] + set tag $tval + set constr [expr {($type & 0x20) > 0}] + + return [incr offset] +} + +#----------------------------------------------------------------------------- +# asnTag : Build a tag value +#----------------------------------------------------------------------------- + +proc ::asn::asnTag {tagnumber {class UNIVERSAL} {tagstyle P}} { + set first 0 + if {$tagnumber < 31} { + # encode everything in one byte + set first $tagnumber + set bytes [list] + } else { + # multi-byte tag + set first 31 + set bytes [list [expr {$tagnumber & 0x7f}]] + set tagnumber [expr {$tagnumber >> 7}] + while {$tagnumber > 0} { + lappend bytes [expr {($tagnumber & 0x7f)+0x80}] + set tagnumber [expr {$tagnumber >>7}] + } + + } + + if {$tagstyle eq "C" || $tagstyle == 1 } {incr first 32} + switch -glob -- $class { + U* { ;# UNIVERSAL } + A* { incr first 64 ;# APPLICATION } + C* { incr first 128 ;# CONTEXT } + P* { incr first 192 ;# PRIVATE } + default { + return -code error "Unknown tag class \"$class\"" + } + } + if {[llength $bytes] > 0} { + # long tag + set rbytes [list] + for {set i [expr {[llength $bytes]-1}]} {$i >= 0} {incr i -1} { + lappend rbytes [lindex $bytes $i] + } + return [binary format cc* $first $rbytes ] + } + return [binary format c $first] +} + + + +#----------------------------------------------------------------------------- +# asnGetBigLength : Retrieve a length that can not be represented in 63-bit +#----------------------------------------------------------------------------- + +proc ::asn::asnGetBigLength {data_var biglength_var} { + + # Does any real world code really need this? + # If we encounter this, we are doomed to fail anyway, + # (there would be an Exabyte inside the data_var, ) + # + # So i implement it just for completeness. + # + package require math::bignum + + upvar 1 $data_var data $biglength_var length + + asnGetByte data length + if {$length == 0x080} { + return -code error "Indefinite length BER encoding not yet supported" + } + if {$length > 0x080} { + # The retrieved byte is a prefix value, and the integer in the + # lower nibble tells us how many bytes were used to encode the + # length data following immediately after this prefix. + + set len_length [expr {$length & 0x7f}] + + if {[string length $data] < $len_length} { + return -code error \ + "length information invalid, not enough octets left" + } + + asnGetBytes data $len_length lengthBytes + binary scan $lengthBytes H* hexlen + set length [math::bignum::fromstr $hexlen 16] + } + return +} + +#----------------------------------------------------------------------------- +# asnGetInteger : Retrieve integer. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetInteger {data_var int_var} { + # Tag is 0x02. + + upvar 1 $data_var data $int_var int + + asnGetByte data tag + + if {$tag != 0x02} { + return -code error \ + [format "Expected Integer (0x02), but got %02x" $tag] + } + + asnGetLength data len + asnGetBytes data $len integerBytes + + set int ? + + switch $len { + 1 { binary scan $integerBytes c int } + 2 { binary scan $integerBytes S int } + 3 { + # check for negative int and pad + scan [string index $integerBytes 0] %c byte + if {$byte & 128} { + binary scan \xff$integerBytes I int + } else { + binary scan \x00$integerBytes I int + } + } + 4 { binary scan $integerBytes I int } + 5 - + 6 - + 7 - + 8 { + # check for negative int and pad + scan [string index $integerBytes 0] %c byte + if {$byte & 128} { + set pad [string repeat \xff [expr {8-$len}]] + } else { + set pad [string repeat \x00 [expr {8-$len}]] + } + binary scan $pad$integerBytes W int + } + default { + # Too long, or prefix coding was used. + return -code error "length information too long" + } + } + return +} + +#----------------------------------------------------------------------------- +# asnGetBigInteger : Retrieve a big integer. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetBigInteger {data_var bignum_var} { + # require math::bignum only if it is used + package require math::bignum + + # Tag is 0x02. We expect that the length of the integer is coded with + # maximal efficiency, i.e. without a prefix 0x81 prefix. If a prefix + # is used this decoder will fail. + + upvar $data_var data $bignum_var bignum + + asnGetByte data tag + + if {$tag != 0x02} { + return -code error \ + [format "Expected Integer (0x02), but got %02x" $tag] + } + + asnGetLength data len + asnGetBytes data $len integerBytes + + binary scan [string index $integerBytes 0] H* hex_head + set head [expr 0x$hex_head] + set replacement_head [expr {$head & 0x7f}] + set integerBytes [string replace $integerBytes 0 0 [format %c $replacement_head]] + + binary scan $integerBytes H* hex + + set bignum [math::bignum::fromstr $hex 16] + + if {($head >> 7) && 1} { + set bigsub [math::bignum::pow [::math::bignum::fromstr 2] [::math::bignum::fromstr [expr {($len * 8) - 1}]]] + set bignum [math::bignum::sub $bignum $bigsub] + } + + return $bignum +} + + + + +#----------------------------------------------------------------------------- +# asnGetEnumeration : Retrieve an enumeration id +#----------------------------------------------------------------------------- + +proc ::asn::asnGetEnumeration {data_var enum_var} { + # This is like 'asnGetInteger', except for a different tag. + + upvar 1 $data_var data $enum_var enum + + asnGetByte data tag + + if {$tag != 0x0a} { + return -code error \ + [format "Expected Enumeration (0x0a), but got %02x" $tag] + } + + asnGetLength data len + asnGetBytes data $len integerBytes + set enum ? + + switch $len { + 1 { binary scan $integerBytes c enum } + 2 { binary scan $integerBytes S enum } + 3 { binary scan \x00$integerBytes I enum } + 4 { binary scan $integerBytes I enum } + default { + return -code error "length information too long" + } + } + return +} + +#----------------------------------------------------------------------------- +# asnGetOctetString : Retrieve arbitrary string. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetOctetString {data_var string_var} { + # Here we need the full decoder for length data. + + upvar 1 $data_var data $string_var string + + asnGetByte data tag + if {$tag != 0x04} { + return -code error \ + [format "Expected Octet String (0x04), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length temp + set string $temp + return +} + +#----------------------------------------------------------------------------- +# asnGetSequence : Retrieve Sequence data for further decoding. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetSequence {data_var sequence_var} { + # Here we need the full decoder for length data. + + upvar 1 $data_var data $sequence_var sequence + + asnGetByte data tag + if {$tag != 0x030} { + return -code error \ + [format "Expected Sequence (0x30), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length temp + set sequence $temp + return +} + +#----------------------------------------------------------------------------- +# asnGetSet : Retrieve Set data for further decoding. +#----------------------------------------------------------------------------- + +proc ::asn::asnGetSet {data_var set_var} { + # Here we need the full decoder for length data. + + upvar 1 $data_var data $set_var set + + asnGetByte data tag + if {$tag != 0x031} { + return -code error \ + [format "Expected Set (0x31), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length temp + set set $temp + return +} + +#----------------------------------------------------------------------------- +# asnGetApplication +#----------------------------------------------------------------------------- + +proc ::asn::asnGetApplication {data_var appNumber_var {content_var {}} {encodingType_var {}} } { + upvar 1 $data_var data $appNumber_var appNumber + + asnGetByte data tag + asnGetLength data length + + if {($tag & 0xC0) != 0x40} { + return -code error \ + [format "Expected Application, but got %02x" $tag] + } + if {$encodingType_var != {}} { + upvar 1 $encodingType_var encodingType + set encodingType [expr {($tag & 0x20) > 0}] + } + set appNumber [expr {$tag & 0x1F}] + if {[string length $content_var]} { + upvar 1 $content_var content + asnGetBytes data $length content + } + return +} + +#----------------------------------------------------------------------------- +# asnGetBoolean: decode a boolean value +#----------------------------------------------------------------------------- + +proc asn::asnGetBoolean {data_var bool_var} { + upvar 1 $data_var data $bool_var bool + + asnGetByte data tag + if {$tag != 0x01} { + return -code error \ + [format "Expected Boolean (0x01), but got %02x" $tag] + } + + asnGetLength data length + asnGetByte data byte + set bool [expr {$byte == 0 ? 0 : 1}] + return +} + +#----------------------------------------------------------------------------- +# asnGetUTCTime: Extract an UTC Time string from the data. Returns a string +# representing an UTC Time. +# +#----------------------------------------------------------------------------- + +proc asn::asnGetUTCTime {data_var utc_var} { + upvar 1 $data_var data $utc_var utc + + asnGetByte data tag + if {$tag != 0x17} { + return -code error \ + [format "Expected UTCTime (0x17), but got %02x" $tag] + } + + asnGetLength data length + asnGetBytes data $length bytes + + # this should be ascii, make it explicit + set bytes [encoding convertfrom ascii $bytes] + binary scan $bytes a* utc + + return +} + + +#----------------------------------------------------------------------------- +# asnGetBitString: Extract a Bit String value (a string of 0/1s) from the +# ASN.1 data. +# +#----------------------------------------------------------------------------- + +proc asn::asnGetBitString {data_var bitstring_var} { + upvar 1 $data_var data $bitstring_var bitstring + + asnGetByte data tag + if {$tag != 0x03} { + return -code error \ + [format "Expected Bit String (0x03), but got %02x" $tag] + } + + asnGetLength data length + # get the number of padding bits used at the end + asnGetByte data padding + incr length -1 + asnGetBytes data $length bytes + binary scan $bytes B* bits + + # cut off the padding bits + set bits [string range $bits 0 end-$padding] + set bitstring $bits +} + +#----------------------------------------------------------------------------- +# asnGetObjectIdentifier: Decode an ASN.1 Object Identifier (OID) into +# a Tcl list of integers. +#----------------------------------------------------------------------------- + +proc asn::asnGetObjectIdentifier {data_var oid_var} { + upvar 1 $data_var data $oid_var oid + + asnGetByte data tag + if {$tag != 0x06} { + return -code error \ + [format "Expected Object Identifier (0x06), but got %02x" $tag] + } + asnGetLength data length + + # the first byte encodes the OID parts in position 0 and 1 + asnGetByte data val + set oid [expr {$val / 40}] + lappend oid [expr {$val % 40}] + incr length -1 + + # the next bytes encode the remaining parts of the OID + set bytes [list] + set incomplete 0 + while {$length} { + asnGetByte data octet + incr length -1 + if {$octet < 128} { + set oidval $octet + set mult 128 + foreach byte $bytes { + if {$byte != {}} { + incr oidval [expr {$mult*$byte}] + set mult [expr {$mult*128}] + } + } + lappend oid $oidval + set bytes [list] + set incomplete 0 + } else { + set byte [expr {$octet-128}] + set bytes [concat [list $byte] $bytes] + set incomplete 1 + } + } + if {$incomplete} { + return -code error "OID Data is incomplete, not enough octets." + } + return +} + +#----------------------------------------------------------------------------- +# asnGetContext: Decode an explicit context tag +# +#----------------------------------------------------------------------------- + +proc ::asn::asnGetContext {data_var contextNumber_var {content_var {}} {encodingType_var {}}} { + upvar 1 $data_var data $contextNumber_var contextNumber + + asnGetByte data tag + asnGetLength data length + + if {($tag & 0xC0) != 0x80} { + return -code error \ + [format "Expected Context, but got %02x" $tag] + } + if {$encodingType_var != {}} { + upvar 1 $encodingType_var encodingType + set encodingType [expr {($tag & 0x20) > 0}] + } + set contextNumber [expr {$tag & 0x1F}] + if {[string length $content_var]} { + upvar 1 $content_var content + asnGetBytes data $length content + } + return +} + + +#----------------------------------------------------------------------------- +# asnGetNumericString: Decode a Numeric String from the data +#----------------------------------------------------------------------------- + +proc ::asn::asnGetNumericString {data_var print_var} { + upvar 1 $data_var data $print_var print + + asnGetByte data tag + if {$tag != 0x12} { + return -code error \ + [format "Expected Numeric String (0x12), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length string + set print [encoding convertfrom ascii $string] + return +} + +#----------------------------------------------------------------------------- +# asnGetPrintableString: Decode a Printable String from the data +#----------------------------------------------------------------------------- + +proc ::asn::asnGetPrintableString {data_var print_var} { + upvar 1 $data_var data $print_var print + + asnGetByte data tag + if {$tag != 0x13} { + return -code error \ + [format "Expected Printable String (0x13), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length string + set print [encoding convertfrom ascii $string] + return +} + +#----------------------------------------------------------------------------- +# asnGetIA5String: Decode a IA5(ASCII) String from the data +#----------------------------------------------------------------------------- + +proc ::asn::asnGetIA5String {data_var print_var} { + upvar 1 $data_var data $print_var print + + asnGetByte data tag + if {$tag != 0x16} { + return -code error \ + [format "Expected IA5 String (0x16), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length string + set print [encoding convertfrom ascii $string] + return +} +#------------------------------------------------------------------------ +# asnGetBMPString: Decode Basic Multiningval (UCS2 string) from data +#------------------------------------------------------------------------ +proc asn::asnGetBMPString {data_var print_var} { + upvar 1 $data_var data $print_var print + asnGetByte data tag + if {$tag != 0x1e} { + return -code error \ + [format "Expected BMP String (0x1e), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length string + if {$::tcl_platform(byteOrder) eq "littleEndian"} { + set str2 "" + foreach {hi lo} [split $string ""] { + append str2 $lo $hi + } + } else { + set str2 $string + } + set print [encoding convertfrom unicode $str2] + return +} +#------------------------------------------------------------------------ +# asnGetUTF8String: Decode UTF8 string from data +#------------------------------------------------------------------------ +proc asn::asnGetUTF8String {data_var print_var} { + upvar 1 $data_var data $print_var print + asnGetByte data tag + if {$tag != 0x0c} { + return -code error \ + [format "Expected UTF8 String (0x0c), but got %02x" $tag] + } + asnGetLength data length + asnGetBytes data $length string + #there should be some error checking to see if input is + #properly-formatted utf8 + set print [encoding convertfrom utf-8 $string] + + return +} +#----------------------------------------------------------------------------- +# asnGetNull: decode a NULL value +#----------------------------------------------------------------------------- + +proc ::asn::asnGetNull {data_var} { + upvar 1 $data_var data + + asnGetByte data tag + if {$tag != 0x05} { + return -code error \ + [format "Expected NULL (0x05), but got %02x" $tag] + } + + asnGetLength data length + asnGetBytes data $length bytes + + # we do not check the null data, all bytes must be 0x00 + + return +} + +#---------------------------------------------------------------------------- +# MultiType string routines +#---------------------------------------------------------------------------- + +namespace eval asn { + variable stringTypes + array set stringTypes { + 12 NumericString + 13 PrintableString + 16 IA5String + 1e BMPString + 0c UTF8String + 14 T61String + 15 VideotexString + 1a VisibleString + 1b GeneralString + 1c UniversalString + } + variable defaultStringType UTF8 +} +#--------------------------------------------------------------------------- +# asnGetString - get readable string automatically detecting its type +#--------------------------------------------------------------------------- +proc ::asn::asnGetString {data_var print_var {type_var {}}} { + variable stringTypes + upvar 1 $data_var data $print_var print + asnPeekByte data tag + set tag [format %02x $tag] + if {![info exists stringTypes($tag)]} { + return -code error "Expected one of string types, but got $tag" + } + asnGet$stringTypes($tag) data print + if {[string length $type_var]} { + upvar $type_var type + set type $stringTypes($tag) + } +} +#--------------------------------------------------------------------- +# defaultStringType - set or query default type for unrestricted strings +#--------------------------------------------------------------------- +proc ::asn::defaultStringType {{type {}}} { + variable defaultStringType + if {![string length $type]} { + return $defaultStringType + } + if {$type ne "BMP" && $type ne "UTF8"} { + return -code error "Invalid default string type. Should be one of BMP, UTF8" + } + set defaultStringType $type + return +} + +#--------------------------------------------------------------------------- +# asnString - encode readable string into most restricted type possible +#--------------------------------------------------------------------------- + +proc ::asn::asnString {string} { + variable nonPrintableChars + variable nonNumericChars + if {[string length $string]!=[string bytelength $string]} { + # There are non-ascii character + variable defaultStringType + return [asn${defaultStringType}String $string] + } elseif {![regexp $nonNumericChars $string]} { + return [asnNumericString $string] + } elseif {![regexp $nonPrintableChars $string]} { + return [asnPrintableString $string] + } else { + return [asnIA5String $string] + } +} + +#----------------------------------------------------------------------------- +package provide asn 0.8.4 + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/asn/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/asn/pkgIndex.tcl new file mode 100644 index 00000000..3cbafd63 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/asn/pkgIndex.tcl @@ -0,0 +1,4 @@ +# Tcl package index file, version 1.1 + +if {![package vsatisfies [package provide Tcl] 8.4]} {return} +package ifneeded asn 0.8.4 [list source [file join $dir asn.tcl]] diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32.tcl new file mode 100644 index 00000000..dd731149 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32.tcl @@ -0,0 +1,182 @@ +# -*- tcl -*- +# This code is hereby put into the public domain. +# ### ### ### ######### ######### ######### +## Overview +# Base32 encoding and decoding of small strings. +# +# Management code for switching between Tcl and C accelerated +# implementations. +# +# RCS: @(#) $Id: base32.tcl,v 1.2 2006/10/13 05:39:49 andreas_kupries Exp $ + +# @mdgen EXCLUDE: base32_c.tcl + +package require Tcl 8.4 + +namespace eval ::base32 {} + +# ### ### ### ######### ######### ######### +## Management of base32 std implementations. + +# ::base32::LoadAccelerator -- +# +# Loads a named implementation, if possible. +# +# Arguments: +# key Name of the implementation to load. +# +# Results: +# A boolean flag. True if the implementation +# was successfully loaded; and False otherwise. + +proc ::base32::LoadAccelerator {key} { + variable accel + set isok 0 + switch -exact -- $key { + critcl { + # Critcl implementation of base32 requires Tcl 8.4. + if {![package vsatisfies [package provide Tcl] 8.4]} {return 0} + if {[catch {package require tcllibc}]} {return 0} + set isok [llength [info commands ::base32::critcl_encode]] + } + tcl { + variable selfdir + if {[catch {source [file join $selfdir base32_tcl.tcl]}]} {return 0} + set isok [llength [info commands ::base32::tcl_encode]] + } + default { + return -code error "invalid accelerator $key:\ + must be one of [join [KnownImplementations] {, }]" + } + } + set accel($key) $isok + return $isok +} + +# ::base32::SwitchTo -- +# +# Activates a loaded named implementation. +# +# Arguments: +# key Name of the implementation to activate. +# +# Results: +# None. + +proc ::base32::SwitchTo {key} { + variable accel + variable loaded + + if {[string equal $key $loaded]} { + # No change, nothing to do. + return + } elseif {![string equal $key ""]} { + # Validate the target implementation of the switch. + + if {![info exists accel($key)]} { + return -code error "Unable to activate unknown implementation \"$key\"" + } elseif {![info exists accel($key)] || !$accel($key)} { + return -code error "Unable to activate missing implementation \"$key\"" + } + } + + # Deactivate the previous implementation, if there was any. + + if {![string equal $loaded ""]} { + foreach c {encode decode} { + rename ::base32::$c ::base32::${loaded}_$c + } + } + + # Activate the new implementation, if there is any. + + if {![string equal $key ""]} { + foreach c {encode decode} { + rename ::base32::${key}_$c ::base32::$c + } + } + + # Remember the active implementation, for deactivation by future + # switches. + + set loaded $key + return +} + +# ::base32::Implementations -- +# +# Determines which implementations are +# present, i.e. loaded. +# +# Arguments: +# None. +# +# Results: +# A list of implementation keys. + +proc ::base32::Implementations {} { + variable accel + set res {} + foreach n [array names accel] { + if {!$accel($n)} continue + lappend res $n + } + return $res +} + +# ::base32::KnownImplementations -- +# +# Determines which implementations are known +# as possible implementations. +# +# Arguments: +# None. +# +# Results: +# A list of implementation keys. In the order +# of preference, most prefered first. + +proc ::base32::KnownImplementations {} { + return {critcl tcl} +} + +proc ::base32::Names {} { + return { + critcl {tcllibc based} + tcl {pure Tcl} + } +} + +# ### ### ### ######### ######### ######### +## Initialization: Data structures. + +namespace eval ::base32 { + variable selfdir [file dirname [info script]] + variable loaded {} + + variable accel + array set accel {tcl 0 critcl 0} +} + +# ### ### ### ######### ######### ######### +## Initialization: Choose an implementation, +## most prefered first. Loads only one of the +## possible implementations. And activates it. + +namespace eval ::base32 { + variable e + foreach e [KnownImplementations] { + if {[LoadAccelerator $e]} { + SwitchTo $e + break + } + } + unset e + + namespace export encode decode +} + +# ### ### ### ######### ######### ######### +## Ready + +package provide base32 0.1 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32_c.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32_c.tcl new file mode 100644 index 00000000..333d73b4 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32_c.tcl @@ -0,0 +1,253 @@ +# base32c.tcl -- +# +# Implementation of a base32 (std) de/encoder for Tcl. +# +# Public domain +# +# RCS: @(#) $Id: base32_c.tcl,v 1.3 2008/01/28 22:58:18 andreas_kupries Exp $ + +package require critcl +package require Tcl 8.4 + +namespace eval ::base32 { + # Supporting code for the main command. + catch { + #critcl::cheaders -g + #critcl::debug memory symbols + } + + # Main commands, encoder & decoder + + critcl::ccommand critcl_encode {dummy interp objc objv} { + /* Syntax -*- c -*- + * critcl_encode string + */ + + unsigned char* buf; + int nbuf; + + unsigned char* out; + unsigned char* at; + int nout; + + /* + * The array used for encoding + */ /* 123456789 123456789 123456789 12 */ + static const char map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +#define USAGEE "bitstring" + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 1, objv, USAGEE); + return TCL_ERROR; + } + + buf = Tcl_GetByteArrayFromObj (objv[1], &nbuf); + nout = ((nbuf+4)/5)*8; + out = (unsigned char*) Tcl_Alloc (nout*sizeof(char)); + + for (at = out; nbuf >= 5; nbuf -= 5, buf += 5) { + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ]; + *(at++) = map [ 0x1f & ((buf[2]<<1) | (buf[3]>>7)) ]; + *(at++) = map [ 0x1f & (buf[3]>>2) ]; + *(at++) = map [ 0x1f & ((buf[3]<<3) | (buf[4]>>5)) ]; + *(at++) = map [ 0x1f & (buf[4]) ]; + } + if (nbuf > 0) { + /* Process partials at end. */ + switch (nbuf) { + case 1: + /* |01234567| 2, padding 6 + * xxxxx + * xxx 00 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & (buf[0]<<2) ]; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + break; + case 2: /* x3/=4 */ + /* |01234567|01234567| 4, padding 4 + * xxxxx + * xxx xx + * xxxxx + * x 0000 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & (buf[1]<<4) ]; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + break; + case 3: + /* |01234567|01234567|01234567| 5, padding 3 + * xxxxx + * xxx xx + * xxxxx + * x xxxx + * xxxx 0 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ]; + *(at++) = map [ 0x1f & (buf[2]<<1) ]; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + break; + case 4: + /* |01234567|01234567|01234567|012334567| 7, padding 1 + * xxxxx + * xxx xx + * xxxxx + * x xxxx + * xxxx + * xxxxx + * xxxx 0 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ]; + *(at++) = map [ 0x1f & ((buf[2]<<1) | (buf[3]>>7)) ]; + *(at++) = map [ 0x1f & (buf[3]>>2) ]; + *(at++) = map [ 0x1f & (buf[3]<<3) ]; + *(at++) = '='; + break; + } + } + + Tcl_SetObjResult (interp, Tcl_NewStringObj ((char*)out, nout)); + Tcl_Free ((char*) out); + return TCL_OK; + } + + + critcl::ccommand critcl_decode {dummy interp objc objv} { + /* Syntax -*- c -*- + * critcl_decode estring + */ + + unsigned char* buf; + int nbuf; + + unsigned char* out; + unsigned char* at; + unsigned char x [8]; + int nout; + + int i, j, a, pad, nx; + + /* + * An array for translating single base-32 characters into a value. + * Disallowed input characters have a value of 64. Upper and lower + * case is the same. Only 128 chars, as everything above char(127) + * is 64. + */ + static const char map [] = { + /* \00 */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* DLE */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* SPC */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* '0' */ 64, 64, 26, 27, 28, 29, 30, 31, 64, 64, 64, 64, 64, 64, 64, 64, + /* '@' */ 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + /* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + /* '`' */ 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + /* 'p' */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64 + }; + +#define USAGED "estring" + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 1, objv, USAGED); + return TCL_ERROR; + } + + buf = (unsigned char*) Tcl_GetStringFromObj (objv[1], &nbuf); + + if (nbuf % 8) { + Tcl_SetObjResult (interp, Tcl_NewStringObj ("Length is not a multiple of 8", -1)); + return TCL_ERROR; + } + + nout = (nbuf/8)*5 *TCL_UTF_MAX; + out = (unsigned char*) Tcl_Alloc (nout*sizeof(char)); + +#define HIGH(x) (((x) & 0x80) != 0) +#define BADC(x) ((x) == 64) +#define BADCHAR(a,j) (HIGH ((a)) || BADC (x [(j)] = map [(a)])) + + for (pad = 0, i=0, at = out; i < nbuf; i += 8, buf += 8){ + for (j=0; j < 8; j++){ + a = buf [j]; + + if (a == '=') { + x[j] = 0; + pad++; + continue; + } else if (pad) { + char msg [120]; + sprintf (msg, + "Invalid character at index %d: \"=\" (padding found in the middle of the input)", + j-1); + Tcl_Free ((char*) out); + Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1)); + return TCL_ERROR; + } + + if (BADCHAR (a,j)) { + char msg [100]; + sprintf (msg,"Invalid character at index %d: \"%c\"",j,a); + Tcl_Free ((char*) out); + Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1)); + return TCL_ERROR; + } + } + + *(at++) = (x[0]<<3) | (x[1]>>2) ; + *(at++) = (x[1]<<6) | (x[2]<<1) | (x[3]>>4); + *(at++) = (x[3]<<4) | (x[4]>>1) ; + *(at++) = (x[4]<<7) | (x[5]<<2) | (x[6]>>3); + *(at++) = (x[6]<<5) | x[7] ; + } + + if (pad) { + if (pad == 1) { + at -= 1; + } else if (pad == 3) { + at -= 2; + } else if (pad == 4) { + at -= 3; + } else if (pad == 6) { + at -= 4; + } else { + char msg [100]; + sprintf (msg,"Invalid padding of length %d",pad); + Tcl_Free ((char*) out); + Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1)); + return TCL_ERROR; + } + } + + Tcl_SetObjResult (interp, Tcl_NewByteArrayObj (out, at-out)); + Tcl_Free ((char*) out); + return TCL_OK; + } +} + +# ### ### ### ######### ######### ######### +## Ready diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32_tcl.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32_tcl.tcl new file mode 100644 index 00000000..a8d50335 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32_tcl.tcl @@ -0,0 +1,73 @@ +# -*- tcl -*- +# This code is hereby put into the public domain. +# ### ### ### ######### ######### ######### +## Overview +# Base32 encoding and decoding of small strings. + +# ### ### ### ######### ######### ######### +## Notes + +# A binary string is split into groups of 5 bits (2^5 == 32), and each +# group is converted into a printable character as is specified in RFC +# 3548. + +# ### ### ### ######### ######### ######### +## Requisites + +package require base32::core +namespace eval ::base32 {} + +# ### ### ### ######### ######### ######### +## API & Implementation + +proc ::base32::tcl_encode {bitstring} { + variable forward + + binary scan $bitstring B* bits + set len [string length $bits] + set rem [expr {$len % 5}] + if {$rem} {append bits =/$rem} + #puts "($bitstring) => <$bits>" + + return [string map $forward $bits] +} + +proc ::base32::tcl_decode {estring} { + variable backward + variable invalid + + if {![core::valid $estring $invalid msg]} { + return -code error $msg + } + #puts "I<$estring>" + #puts "M<[string map $backward $estring]>" + + return [binary format B* [string map $backward [string toupper $estring]]] +} + +# ### ### ### ######### ######### ######### +## Data structures + +namespace eval ::base32 { + # Initialize the maps + variable forward + variable backward + variable invalid + + core::define { + 0 A 9 J 18 S 27 3 + 1 B 10 K 19 T 28 4 + 2 C 11 L 20 U 29 5 + 3 D 12 M 21 V 30 6 + 4 E 13 N 22 W 31 7 + 5 F 14 O 23 X + 6 G 15 P 24 Y + 7 H 16 Q 25 Z + 8 I 17 R 26 2 + } forward backward invalid ; # {} + # puts ///$forward/// + # puts ///$backward/// +} + +# ### ### ### ######### ######### ######### +## Ok diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32core.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32core.tcl new file mode 100644 index 00000000..aaf7fc87 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32core.tcl @@ -0,0 +1,134 @@ +# -*- tcl -*- +# This code is hereby put into the public domain. +# ### ### ### ######### ######### ######### +#= Overview + +# Fundamental handling of base32 conversion tables. Expansion of a +# basic mapping into a full mapping and its inverse mapping. + +# ### ### ### ######### ######### ######### +#= Requisites + +namespace eval ::base32::core {} + +# ### ### ### ######### ######### ######### +#= API & Implementation + +proc ::base32::core::define {map fv bv iv} { + variable bits + upvar 1 $fv forward $bv backward $iv invalid + + # bytes - bits - padding - tail | bits - padding - tail + # 0 - 0 - "" - "xxxxxxxx" | 0 - "" - "" + # 1 - 8 - "======" - "xx======" | 3 - "======" - "x======" + # 2 - 16 - "====" - "xxxx====" | 1 - "====" - "x====" + # 3 - 24 - "===" - "xxxxx===" | 4 - "===" - "x===" + # 4 - 32 - "=" - "xxxxxxx=" | 2 - "=" - "x=" + + array set _ $bits + + set invalid "\[^=" + set forward {} + set btmp {} + + foreach {code char} $map { + set b $_($code) + + append invalid [string tolower $char][string toupper $char] + + # 5 bit remainder + lappend forward $b $char + lappend btmp [list $char $b] + + # 4 bit remainder + if {$code%2} continue + set b [string range $b 0 end-1] + lappend forward ${b}=/4 ${char}=== + lappend btmp [list ${char}=== $b] + + # 3 bit remainder + if {$code%4} continue + set b [string range $b 0 end-1] + lappend forward ${b}=/3 ${char}====== + lappend btmp [list ${char}====== $b] + + # 2 bit remainder + if {$code%8} continue + set b [string range $b 0 end-1] + lappend forward ${b}=/2 ${char}= + lappend btmp [list ${char}= $b] + + # 1 bit remainder + if {$code%16} continue + set b [string range $b 0 end-1] + lappend forward ${b}=/1 ${char}==== + lappend btmp [list ${char}==== $b] + } + + set backward {} + foreach item [lsort -index 0 -decreasing $btmp] { + foreach {c b} $item break + lappend backward $c $b + } + + append invalid "\]" + return +} + +proc ::base32::core::valid {estring pattern mv} { + upvar 1 $mv message + + if {[string length $estring] % 8} { + set message "Length is not a multiple of 8" + return 0 + } elseif {[regexp -indices $pattern $estring where]} { + foreach {s e} $where break + set message "Invalid character at index $s: \"[string index $estring $s]\"" + return 0 + } elseif {[regexp {(=+)$} $estring -> pad]} { + set padlen [string length $pad] + if { + ($padlen != 6) && + ($padlen != 4) && + ($padlen != 3) && + ($padlen != 1) + } { + set message "Invalid padding of length $padlen" + return 0 + } + } + + # Remove the brackets and ^= from the pattern, to construct the + # class of valid characters which must not follow the padding. + + set badp "=\[[string range $pattern 3 end-1]\]" + if {[regexp -indices $badp $estring where]} { + foreach {s e} $where break + set message "Invalid character at index $s: \"[string index $estring $s]\" (padding found in the middle of the input)" + return 0 + } + return 1 +} + +# ### ### ### ######### ######### ######### +## Data structures + +namespace eval ::base32::core { + namespace export define valid + + variable bits { + 0 00000 1 00001 2 00010 3 00011 + 4 00100 5 00101 6 00110 7 00111 + 8 01000 9 01001 10 01010 11 01011 + 12 01100 13 01101 14 01110 15 01111 + 16 10000 17 10001 18 10010 19 10011 + 20 10100 21 10101 22 10110 23 10111 + 24 11000 25 11001 26 11010 27 11011 + 28 11100 29 11101 30 11110 31 11111 + } +} + +# ### ### ### ######### ######### ######### +#= Registration + +package provide base32::core 0.1 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex.tcl new file mode 100644 index 00000000..6611c4c9 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex.tcl @@ -0,0 +1,182 @@ +# -*- tcl -*- +# This code is hereby put into the public domain. +# ### ### ### ######### ######### ######### +## Overview +# Base32 encoding and decoding of small strings. +# +# Management code for switching between Tcl and C accelerated +# implementations. +# +# RCS: @(#) $Id: base32hex.tcl,v 1.3 2008/03/22 23:46:42 andreas_kupries Exp $ + +# @mdgen EXCLUDE: base32hex_c.tcl + +package require Tcl 8.4 + +namespace eval ::base32::hex {} + +# ### ### ### ######### ######### ######### +## Management of base32 std implementations. + +# ::base32::hex::LoadAccelerator -- +# +# Loads a named implementation, if possible. +# +# Arguments: +# key Name of the implementation to load. +# +# Results: +# A boolean flag. True if the implementation +# was successfully loaded; and False otherwise. + +proc ::base32::hex::LoadAccelerator {key} { + variable accel + set isok 0 + switch -exact -- $key { + critcl { + # Critcl implementation of base32 requires Tcl 8.4. + if {![package vsatisfies [package provide Tcl] 8.4]} {return 0} + if {[catch {package require tcllibc}]} {return 0} + set isok [llength [info commands ::base32::hex::critcl_encode]] + } + tcl { + variable selfdir + if {[catch {source [file join $selfdir base32hex_tcl.tcl]}]} {return 0} + set isok [llength [info commands ::base32::hex::tcl_encode]] + } + default { + return -code error "invalid accelerator $key:\ + must be one of [join [KnownImplementations] {, }]" + } + } + set accel($key) $isok + return $isok +} + +# ::base32::hex::SwitchTo -- +# +# Activates a loaded named implementation. +# +# Arguments: +# key Name of the implementation to activate. +# +# Results: +# None. + +proc ::base32::hex::SwitchTo {key} { + variable accel + variable loaded + + if {[string equal $key $loaded]} { + # No change, nothing to do. + return + } elseif {![string equal $key ""]} { + # Validate the target implementation of the switch. + + if {![info exists accel($key)]} { + return -code error "Unable to activate unknown implementation \"$key\"" + } elseif {![info exists accel($key)] || !$accel($key)} { + return -code error "Unable to activate missing implementation \"$key\"" + } + } + + # Deactivate the previous implementation, if there was any. + + if {![string equal $loaded ""]} { + foreach c {encode decode} { + rename ::base32::hex::$c ::base32::hex::${loaded}_$c + } + } + + # Activate the new implementation, if there is any. + + if {![string equal $key ""]} { + foreach c {encode decode} { + rename ::base32::hex::${key}_$c ::base32::hex::$c + } + } + + # Remember the active implementation, for deactivation by future + # switches. + + set loaded $key + return +} + +# ::base32::hex::Implementations -- +# +# Determines which implementations are +# present, i.e. loaded. +# +# Arguments: +# None. +# +# Results: +# A list of implementation keys. + +proc ::base32::hex::Implementations {} { + variable accel + set res {} + foreach n [array names accel] { + if {!$accel($n)} continue + lappend res $n + } + return $res +} + +# ::base32::hex::KnownImplementations -- +# +# Determines which implementations are known +# as possible implementations. +# +# Arguments: +# None. +# +# Results: +# A list of implementation keys. In the order +# of preference, most prefered first. + +proc ::base32::hex::KnownImplementations {} { + return {critcl tcl} +} + +proc ::base32::hex::Names {} { + return { + critcl {tcllibc based} + tcl {pure Tcl} + } +} + +# ### ### ### ######### ######### ######### +## Initialization: Data structures. + +namespace eval ::base32::hex { + variable selfdir [file dirname [info script]] + variable loaded {} + + variable accel + array set accel {tcl 0 critcl 0} +} + +# ### ### ### ######### ######### ######### +## Initialization: Choose an implementation, +## most prefered first. Loads only one of the +## possible implementations. And activates it. + +namespace eval ::base32::hex { + variable e + foreach e [KnownImplementations] { + if {[LoadAccelerator $e]} { + SwitchTo $e + break + } + } + unset e + + namespace export encode decode +} + +# ### ### ### ######### ######### ######### +## Ready + +package provide base32::hex 0.1 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex_c.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex_c.tcl new file mode 100644 index 00000000..5466463c --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex_c.tcl @@ -0,0 +1,253 @@ +# base32hexc.tcl -- +# +# Implementation of a base32 (extended hex) de/encoder for Tcl. +# +# Public domain +# +# RCS: @(#) $Id: base32hex_c.tcl,v 1.3 2008/01/28 22:58:18 andreas_kupries Exp $ + +package require critcl +package require Tcl 8.4 + +namespace eval ::base32::hex { + # Supporting code for the main command. + catch { + #critcl::cheaders -g + #critcl::debug memory symbols + } + + # Main commands, encoder & decoder + + critcl::ccommand critcl_encode {dummy interp objc objv} { + /* Syntax -*- c -*- + * critcl_encode string + */ + + unsigned char* buf; + int nbuf; + + unsigned char* out; + unsigned char* at; + int nout; + + /* + * The array used for encoding + */ /* 123456789 123456789 123456789 12 */ + static const char map[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + +#define USAGEE "bitstring" + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 1, objv, USAGEE); + return TCL_ERROR; + } + + buf = Tcl_GetByteArrayFromObj (objv[1], &nbuf); + nout = ((nbuf+4)/5)*8; + out = (unsigned char*) Tcl_Alloc (nout*sizeof(char)); + + for (at = out; nbuf >= 5; nbuf -= 5, buf += 5) { + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ]; + *(at++) = map [ 0x1f & ((buf[2]<<1) | (buf[3]>>7)) ]; + *(at++) = map [ 0x1f & (buf[3]>>2) ]; + *(at++) = map [ 0x1f & ((buf[3]<<3) | (buf[4]>>5)) ]; + *(at++) = map [ 0x1f & (buf[4]) ]; + } + if (nbuf > 0) { + /* Process partials at end. */ + switch (nbuf) { + case 1: + /* |01234567| 2, padding 6 + * xxxxx + * xxx 00 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & (buf[0]<<2) ]; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + break; + case 2: /* x3/=4 */ + /* |01234567|01234567| 4, padding 4 + * xxxxx + * xxx xx + * xxxxx + * x 0000 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & (buf[1]<<4) ]; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + break; + case 3: + /* |01234567|01234567|01234567| 5, padding 3 + * xxxxx + * xxx xx + * xxxxx + * x xxxx + * xxxx 0 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ]; + *(at++) = map [ 0x1f & (buf[2]<<1) ]; + *(at++) = '='; + *(at++) = '='; + *(at++) = '='; + break; + case 4: + /* |01234567|01234567|01234567|012334567| 7, padding 1 + * xxxxx + * xxx xx + * xxxxx + * x xxxx + * xxxx + * xxxxx + * xxxx 0 + */ + + *(at++) = map [ (buf[0]>>3) ]; + *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ]; + *(at++) = map [ 0x1f & (buf[1]>>1) ]; + *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ]; + *(at++) = map [ 0x1f & ((buf[2]<<1) | (buf[3]>>7)) ]; + *(at++) = map [ 0x1f & (buf[3]>>2) ]; + *(at++) = map [ 0x1f & (buf[3]<<3) ]; + *(at++) = '='; + break; + } + } + + Tcl_SetObjResult (interp, Tcl_NewStringObj ((char*)out, nout)); + Tcl_Free ((char*) out); + return TCL_OK; + } + + + critcl::ccommand critcl_decode {dummy interp objc objv} { + /* Syntax -*- c -*- + * critcl_decode estring + */ + + unsigned char* buf; + int nbuf; + + unsigned char* out; + unsigned char* at; + unsigned char x [8]; + int nout; + + int i, j, a, pad, nx; + + /* + * An array for translating single base-32 characters into a value. + * Disallowed input characters have a value of 64. Upper and lower + * case is the same. Only 128 chars, as everything above char(127) + * is 64. + */ + static const char map [] = { + /* \00 */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* DLE */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* SPC */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* '0' */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 64, 64, 64, 64, 64, 64, + /* '@' */ 64, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + /* 'P' */ 25, 26, 27, 28, 29, 30, 31, 64, 64, 64, 64, 64, 64, 64, 64, 64, + /* '`' */ 64, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + /* 'p' */ 25, 26, 27, 28, 29, 30, 31, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + +#define USAGED "estring" + + if (objc != 2) { + Tcl_WrongNumArgs (interp, 1, objv, USAGED); + return TCL_ERROR; + } + + buf = (unsigned char*) Tcl_GetStringFromObj (objv[1], &nbuf); + + if (nbuf % 8) { + Tcl_SetObjResult (interp, Tcl_NewStringObj ("Length is not a multiple of 8", -1)); + return TCL_ERROR; + } + + nout = (nbuf/8)*5 *TCL_UTF_MAX; + out = (unsigned char*) Tcl_Alloc (nout*sizeof(char)); + +#define HIGH(x) (((x) & 0x80) != 0) +#define BADC(x) ((x) == 64) +#define BADCHAR(a,j) (HIGH ((a)) || BADC (x [(j)] = map [(a)])) + + for (pad = 0, i=0, at = out; i < nbuf; i += 8, buf += 8){ + for (j=0; j < 8; j++){ + a = buf [j]; + + if (a == '=') { + x[j] = 0; + pad++; + continue; + } else if (pad) { + char msg [120]; + sprintf (msg, + "Invalid character at index %d: \"=\" (padding found in the middle of the input)", + j-1); + Tcl_Free ((char*) out); + Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1)); + return TCL_ERROR; + } + + if (BADCHAR (a,j)) { + char msg [100]; + sprintf (msg,"Invalid character at index %d: \"%c\"",j,a); + Tcl_Free ((char*) out); + Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1)); + return TCL_ERROR; + } + } + + *(at++) = (x[0]<<3) | (x[1]>>2) ; + *(at++) = (x[1]<<6) | (x[2]<<1) | (x[3]>>4); + *(at++) = (x[3]<<4) | (x[4]>>1) ; + *(at++) = (x[4]<<7) | (x[5]<<2) | (x[6]>>3); + *(at++) = (x[6]<<5) | x[7] ; + } + + if (pad) { + if (pad == 1) { + at -= 1; + } else if (pad == 3) { + at -= 2; + } else if (pad == 4) { + at -= 3; + } else if (pad == 6) { + at -= 4; + } else { + char msg [100]; + sprintf (msg,"Invalid padding of length %d",pad); + Tcl_Free ((char*) out); + Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1)); + return TCL_ERROR; + } + } + + Tcl_SetObjResult (interp, Tcl_NewByteArrayObj (out, at-out)); + Tcl_Free ((char*) out); + return TCL_OK; + } +} + +# ### ### ### ######### ######### ######### +## Ready diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex_tcl.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex_tcl.tcl new file mode 100644 index 00000000..f406bc6d --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/base32hex_tcl.tcl @@ -0,0 +1,79 @@ +# -*- tcl -*- +# This code is hereby put into the public domain. +# ### ### ### ######### ######### ######### +## Overview +# Base32 encoding and decoding of small strings. + +# ### ### ### ######### ######### ######### +## Notes + +# A binary string is split into groups of 5 bits (2^5 == 32), and each +# group is converted into a printable character as is specified in RFC +# 3548 for the extended hex encoding. + +# ### ### ### ######### ######### ######### +## Requisites + +package require base32::core +namespace eval ::base32::hex {} + +# ### ### ### ######### ######### ######### +## API & Implementation + +proc ::base32::hex::tcl_encode {bitstring} { + variable forward + + binary scan $bitstring B* bits + set len [string length $bits] + set rem [expr {$len % 5}] + if {$rem} {append bits =/$rem} + #puts "($bitstring) => <$bits>" + + return [string map $forward $bits] +} + +proc ::base32::hex::tcl_decode {estring} { + variable backward + variable invalid + + if {![core::valid $estring $invalid msg]} { + return -code error $msg + } + #puts "I<$estring>" + #puts "M<[string map $backward $estring]>" + + return [binary format B* [string map $backward [string toupper $estring]]] +} + +# ### ### ### ######### ######### ######### +## Data structures + +namespace eval ::base32::hex { + namespace eval core { + namespace import ::base32::core::define + namespace import ::base32::core::valid + } + + namespace export encode decode + # Initialize the maps + variable forward + variable backward + variable invalid + + core::define { + 0 0 9 9 18 I 27 R + 1 1 10 A 19 J 28 S + 2 2 11 B 20 K 29 T + 3 3 12 C 21 L 30 U + 4 4 13 D 22 M 31 V + 5 5 14 E 23 N + 6 6 15 F 24 O + 7 7 16 G 25 P + 8 8 17 H 26 Q + } forward backward invalid ; # {} + # puts ///$forward/// + # puts ///$backward/// +} + +# ### ### ### ######### ######### ######### +## Ok diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/pkgIndex.tcl new file mode 100644 index 00000000..3bccaa7e --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base32/pkgIndex.tcl @@ -0,0 +1,4 @@ +if {![package vsatisfies [package provide Tcl] 8.4]} return +package ifneeded base32 0.1 [list source [file join $dir base32.tcl]] +package ifneeded base32::hex 0.1 [list source [file join $dir base32hex.tcl]] +package ifneeded base32::core 0.1 [list source [file join $dir base32core.tcl]] diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/ascii85.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/ascii85.tcl new file mode 100644 index 00000000..e05e3430 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/ascii85.tcl @@ -0,0 +1,271 @@ +# ascii85.tcl -- +# +# Encode/Decode ascii85 for a string +# +# Copyright (c) Emiliano Gavilan +# 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.4 + +namespace eval ascii85 { + namespace export encode encodefile decode + # default values for encode options + variable options + array set options [list -wrapchar \n -maxlen 76] +} + +# ::ascii85::encode -- +# +# Ascii85 encode a given string. +# +# Arguments: +# args ?-maxlen maxlen? ?-wrapchar wrapchar? string +# +# If maxlen is 0, the output is not wrapped. +# +# Results: +# A Ascii85 encoded version of $string, wrapped at $maxlen characters +# by $wrapchar. + +proc ascii85::encode {args} { + variable options + + set alen [llength $args] + if {$alen != 1 && $alen != 3 && $alen != 5} { + return -code error "wrong # args:\ + should be \"[lindex [info level 0] 0]\ + ?-maxlen maxlen?\ + ?-wrapchar wrapchar? string\"" + } + + set data [lindex $args end] + array set opts [array get options] + array set opts [lrange $args 0 end-1] + foreach key [array names opts] { + if {[lsearch -exact [array names options] $key] == -1} { + return -code error "unknown option \"$key\":\ + must be -maxlen or -wrapchar" + } + } + + if {![string is integer -strict $opts(-maxlen)] + || $opts(-maxlen) < 0} { + return -code error "expected positive integer but got\ + \"$opts(-maxlen)\"" + } + + # perform this check early + if {[string length $data] == 0} { + return "" + } + + # shorten the names + set ml $opts(-maxlen) + set wc $opts(-wrapchar) + + # if maxlen is zero, don't wrap the output + if {$ml == 0} { + set wc "" + } + + set encoded {} + + binary scan $data c* X + set len [llength $X] + set rest [expr {$len % 4}] + set lastidx [expr {$len - $rest - 1}] + + foreach {b1 b2 b3 b4} [lrange $X 0 $lastidx] { + # calculate the 32 bit value + # this is an inlined version of the [encode4bytes] proc + # included here for performance reasons + set val [expr { + ( (($b1 & 0xff) << 24) + |(($b2 & 0xff) << 16) + |(($b3 & 0xff) << 8) + | ($b4 & 0xff) + ) & 0xffffffff }] + + if {$val == 0} { + # four \0 bytes encodes as "z" instead of "!!!!!" + append current "z" + } else { + # no magic numbers here. + # 52200625 -> 85 ** 4 + # 614125 -> 85 ** 3 + # 7225 -> 85 ** 2 + append current [binary format ccccc \ + [expr { ( $val / 52200625) + 33 }] \ + [expr { (($val % 52200625) / 614125) + 33 }] \ + [expr { (($val % 614125) / 7225) + 33 }] \ + [expr { (($val % 7225) / 85) + 33 }] \ + [expr { ( $val % 85) + 33 }]] + } + + if {[string length $current] >= $ml} { + append encoded [string range $current 0 [expr {$ml - 1}]] $wc + set current [string range $current $ml end] + } + } + + if { $rest } { + # there are remaining bytes. + # pad with \0 and encode not using the "z" convention. + # finally, add ($rest + 1) chars. + set val 0 + foreach {b1 b2 b3 b4} [pad [lrange $X [incr lastidx] end] 4 0] break + append current [string range [encode4bytes $b1 $b2 $b3 $b4] 0 $rest] + } + append encoded [regsub -all -- ".{$ml}" $current "&$wc"] + + return $encoded +} + +proc ascii85::encode4bytes {b1 b2 b3 b4} { + set val [expr { + ( (($b1 & 0xff) << 24) + |(($b2 & 0xff) << 16) + |(($b3 & 0xff) << 8) + | ($b4 & 0xff) + ) & 0xffffffff }] + return [binary format ccccc \ + [expr { ( $val / 52200625) + 33 }] \ + [expr { (($val % 52200625) / 614125) + 33 }] \ + [expr { (($val % 614125) / 7225) + 33 }] \ + [expr { (($val % 7225) / 85) + 33 }] \ + [expr { ( $val % 85) + 33 }]] +} + +# ::ascii85::encodefile -- +# +# Ascii85 encode the contents of a file using default values +# for maxlen and wrapchar parameters. +# +# Arguments: +# fname The name of the file to encode. +# +# Results: +# An Ascii85 encoded version of the contents of the file. +# This is a convenience command + +proc ascii85::encodefile {fname} { + set fd [open $fname] + fconfigure $fd -encoding binary -translation binary + return [encode [read $fd]][close $fd] +} + +# ::ascii85::decode -- +# +# Ascii85 decode a given string. +# +# Arguments: +# string The string to decode. +# Leading spaces and tabs are removed, along with trailing newlines +# +# Results: +# The decoded value. + +proc ascii85::decode {data} { + # get rid of leading spaces/tabs and trailing newlines + set data [string map [list \n {} \t {} { } {}] $data] + set len [string length $data] + + # perform this ckeck early + if {! $len} { + return "" + } + + set decoded {} + set count 0 + set group [list] + binary scan $data c* X + + foreach char $X { + # we must check that every char is in the allowed range + if {$char < 33 || $char > 117 } { + # "z" is an exception + if {$char == 122} { + if {$count == 0} { + # if a "z" char appears at the beggining of a group, + # it decodes as four null bytes + append decoded \x00\x00\x00\x00 + continue + } else { + # if not, is an error + return -code error \ + "error decoding data: \"z\" char misplaced" + } + } + # char is not in range and not a "z" at the beggining of a group + return -code error \ + "error decoding data: chars outside the allowed range" + } + + lappend group $char + incr count + if {$count == 5} { + # this is an inlined version of the [decode5chars] proc + # included here for performance reasons + set val [expr { + ([lindex $group 0] - 33) * wide(52200625) + + ([lindex $group 1] - 33) * 614125 + + ([lindex $group 2] - 33) * 7225 + + ([lindex $group 3] - 33) * 85 + + ([lindex $group 4] - 33) }] + if {$val > 0xffffffff} { + return -code error "error decoding data: decoded group overflow" + } else { + append decoded [binary format I $val] + incr count -5 + set group [list] + } + } + } + + set len [llength $group] + switch -- $len { + 0 { + # all input has been consumed + # do nothing + } + 1 { + # a single char is a condition error, there should be at least 2 + return -code error \ + "error decoding data: trailing char" + } + default { + # pad with "u"s, decode and add ($len - 1) bytes + append decoded [string range \ + [decode5chars [pad $group 5 122]] \ + 0 \ + [expr {$len - 2}]] + } + } + + return $decoded +} + +proc ascii85::decode5chars {group} { + set val [expr { + ([lindex $group 0] - 33) * wide(52200625) + + ([lindex $group 1] - 33) * 614125 + + ([lindex $group 2] - 33) * 7225 + + ([lindex $group 3] - 33) * 85 + + ([lindex $group 4] - 33) }] + if {$val > 0xffffffff} { + return -code error "error decoding data: decoded group overflow" + } + + return [binary format I $val] +} + +proc ascii85::pad {chars len padchar} { + while {[llength $chars] < $len} { + lappend chars $padchar + } + + return $chars +} + +package provide ascii85 1.0 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/base64.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/base64.tcl new file mode 100644 index 00000000..fa52c1c3 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/base64.tcl @@ -0,0 +1,410 @@ +# base64.tcl -- +# +# Encode/Decode base64 for a string +# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems +# The decoder was done for exmh by Chris Garrigues +# +# 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. + +# Version 1.0 implemented Base64_Encode, Base64_Decode +# Version 2.0 uses the base64 namespace +# Version 2.1 fixes various decode bugs and adds options to encode +# Version 2.2 is much faster, Tcl8.0 compatible +# Version 2.2.1 bugfixes +# Version 2.2.2 bugfixes +# Version 2.3 bugfixes and extended to support Trf +# Version 2.4.x bugfixes + +# @mdgen EXCLUDE: base64c.tcl + +package require Tcl 8.2 +namespace eval ::base64 { + namespace export encode decode +} + +package provide base64 2.5 + +if {[package vsatisfies [package require Tcl] 8.6]} { + proc ::base64::encode {args} { + binary encode base64 -maxlen 76 {*}$args + } + + proc ::base64::decode {string} { + # Tcllib is strict with respect to end of input, yet lax for + # invalid characters outside of that. + regsub -all -- {[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/]} $string {} string + binary decode base64 -strict $string + } + + return +} + +if {![catch {package require Trf 2.0}]} { + # Trf is available, so implement the functionality provided here + # in terms of calls to Trf for speed. + + # ::base64::encode -- + # + # Base64 encode a given string. + # + # Arguments: + # args ?-maxlen maxlen? ?-wrapchar wrapchar? string + # + # If maxlen is 0, the output is not wrapped. + # + # Results: + # A Base64 encoded version of $string, wrapped at $maxlen characters + # by $wrapchar. + + proc ::base64::encode {args} { + # Set the default wrapchar and maximum line length to match + # the settings for MIME encoding (RFC 3548, RFC 2045). These + # are the settings used by Trf as well. Various RFCs allow for + # different wrapping characters and wraplengths, so these may + # be overridden by command line options. + set wrapchar "\n" + set maxlen 76 + + if { [llength $args] == 0 } { + error "wrong # args: should be \"[lindex [info level 0] 0]\ + ?-maxlen maxlen? ?-wrapchar wrapchar? string\"" + } + + set optionStrings [list "-maxlen" "-wrapchar"] + for {set i 0} {$i < [llength $args] - 1} {incr i} { + set arg [lindex $args $i] + set index [lsearch -glob $optionStrings "${arg}*"] + if { $index == -1 } { + error "unknown option \"$arg\": must be -maxlen or -wrapchar" + } + incr i + if { $i >= [llength $args] - 1 } { + error "value for \"$arg\" missing" + } + set val [lindex $args $i] + + # The name of the variable to assign the value to is extracted + # from the list of known options, all of which have an + # associated variable of the same name as the option without + # a leading "-". The [string range] command is used to strip + # of the leading "-" from the name of the option. + # + # FRINK: nocheck + set [string range [lindex $optionStrings $index] 1 end] $val + } + + # [string is] requires Tcl8.2; this works with 8.0 too + if {[catch {expr {$maxlen % 2}}]} { + return -code error "expected integer but got \"$maxlen\"" + } elseif {$maxlen < 0} { + return -code error "expected positive integer but got \"$maxlen\"" + } + + set string [lindex $args end] + set result [::base64 -mode encode -- $string] + + # Trf's encoder implicitly uses the settings -maxlen 76, + # -wrapchar \n for its output. We may have to reflow this for + # the settings chosen by the user. A second difference is that + # Trf closes the output with the wrap char sequence, + # always. The code here doesn't. Therefore 'trimright' is + # needed in the fast cases. + + if {($maxlen == 76) && [string equal $wrapchar \n]} { + # Both maxlen and wrapchar are identical to Trf's + # settings. This is the super-fast case, because nearly + # nothing has to be done. Only thing to do is strip a + # terminating wrapchar. + set result [string trimright $result] + } elseif {$maxlen == 76} { + # wrapchar has to be different here, length is the + # same. We can use 'string map' to transform the wrap + # information. + set result [string map [list \n $wrapchar] \ + [string trimright $result]] + } elseif {$maxlen == 0} { + # Have to reflow the output to no wrapping. Another fast + # case using only 'string map'. 'trimright' is not needed + # here. + + set result [string map [list \n ""] $result] + } else { + # Have to reflow the output from 76 to the chosen maxlen, + # and possibly change the wrap sequence as well. + + # Note: After getting rid of the old wrap sequence we + # extract the relevant segments from the string without + # modifying the string. Modification, i.e. removal of the + # processed part, means 'shifting down characters in + # memory', making the algorithm O(n^2). By avoiding the + # modification we stay in O(n). + + set result [string map [list \n ""] $result] + set l [expr {[string length $result]-$maxlen}] + for {set off 0} {$off < $l} {incr off $maxlen} { + append res [string range $result $off [expr {$off+$maxlen-1}]] $wrapchar + } + append res [string range $result $off end] + set result $res + } + + return $result + } + + # ::base64::decode -- + # + # Base64 decode a given string. + # + # Arguments: + # string The string to decode. Characters not in the base64 + # alphabet are ignored (e.g., newlines) + # + # Results: + # The decoded value. + + proc ::base64::decode {string} { + regsub -all {\s} $string {} string + ::base64 -mode decode -- $string + } + +} else { + # Without Trf use a pure tcl implementation + + namespace eval base64 { + variable base64 {} + variable base64_en {} + + # We create the auxiliary array base64_tmp, it will be unset later. + variable base64_tmp + variable i + + set i 0 + foreach char {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 \ + 0 1 2 3 4 5 6 7 8 9 + /} { + set base64_tmp($char) $i + lappend base64_en $char + incr i + } + + # + # Create base64 as list: to code for instance C<->3, specify + # that [lindex $base64 67] be 3 (C is 67 in ascii); non-coded + # ascii chars get a {}. we later use the fact that lindex on a + # non-existing index returns {}, and that [expr {} < 0] is true + # + + # the last ascii char is 'z' + variable char + variable len + variable val + + scan z %c len + for {set i 0} {$i <= $len} {incr i} { + set char [format %c $i] + set val {} + if {[info exists base64_tmp($char)]} { + set val $base64_tmp($char) + } else { + set val {} + } + lappend base64 $val + } + + # code the character "=" as -1; used to signal end of message + scan = %c i + set base64 [lreplace $base64 $i $i -1] + + # remove unneeded variables + unset base64_tmp i char len val + + namespace export encode decode + } + + # ::base64::encode -- + # + # Base64 encode a given string. + # + # Arguments: + # args ?-maxlen maxlen? ?-wrapchar wrapchar? string + # + # If maxlen is 0, the output is not wrapped. + # + # Results: + # A Base64 encoded version of $string, wrapped at $maxlen characters + # by $wrapchar. + + proc ::base64::encode {args} { + set base64_en $::base64::base64_en + + # Set the default wrapchar and maximum line length to match + # the settings for MIME encoding (RFC 3548, RFC 2045). These + # are the settings used by Trf as well. Various RFCs allow for + # different wrapping characters and wraplengths, so these may + # be overridden by command line options. + set wrapchar "\n" + set maxlen 76 + + if { [llength $args] == 0 } { + error "wrong # args: should be \"[lindex [info level 0] 0]\ + ?-maxlen maxlen? ?-wrapchar wrapchar? string\"" + } + + set optionStrings [list "-maxlen" "-wrapchar"] + for {set i 0} {$i < [llength $args] - 1} {incr i} { + set arg [lindex $args $i] + set index [lsearch -glob $optionStrings "${arg}*"] + if { $index == -1 } { + error "unknown option \"$arg\": must be -maxlen or -wrapchar" + } + incr i + if { $i >= [llength $args] - 1 } { + error "value for \"$arg\" missing" + } + set val [lindex $args $i] + + # The name of the variable to assign the value to is extracted + # from the list of known options, all of which have an + # associated variable of the same name as the option without + # a leading "-". The [string range] command is used to strip + # of the leading "-" from the name of the option. + # + # FRINK: nocheck + set [string range [lindex $optionStrings $index] 1 end] $val + } + + # [string is] requires Tcl8.2; this works with 8.0 too + if {[catch {expr {$maxlen % 2}}]} { + return -code error "expected integer but got \"$maxlen\"" + } elseif {$maxlen < 0} { + return -code error "expected positive integer but got \"$maxlen\"" + } + + set string [lindex $args end] + + set result {} + set state 0 + set length 0 + + + # Process the input bytes 3-by-3 + + binary scan $string c* X + + foreach {x y z} $X { + ADD [lindex $base64_en [expr {($x >>2) & 0x3F}]] + if {$y != {}} { + ADD [lindex $base64_en [expr {(($x << 4) & 0x30) | (($y >> 4) & 0xF)}]] + if {$z != {}} { + ADD [lindex $base64_en [expr {(($y << 2) & 0x3C) | (($z >> 6) & 0x3)}]] + ADD [lindex $base64_en [expr {($z & 0x3F)}]] + } else { + set state 2 + break + } + } else { + set state 1 + break + } + } + if {$state == 1} { + ADD [lindex $base64_en [expr {(($x << 4) & 0x30)}]] + ADD = + ADD = + } elseif {$state == 2} { + ADD [lindex $base64_en [expr {(($y << 2) & 0x3C)}]] + ADD = + } + return $result + } + + proc ::base64::ADD {x} { + # The line length check is always done before appending so + # that we don't get an extra newline if the output is a + # multiple of $maxlen chars long. + + upvar 1 maxlen maxlen length length result result wrapchar wrapchar + if {$maxlen && $length >= $maxlen} { + append result $wrapchar + set length 0 + } + append result $x + incr length + return + } + + # ::base64::decode -- + # + # Base64 decode a given string. + # + # Arguments: + # string The string to decode. Characters not in the base64 + # alphabet are ignored (e.g., newlines) + # + # Results: + # The decoded value. + + proc ::base64::decode {string} { + if {[string length $string] == 0} {return ""} + + set base64 $::base64::base64 + set output "" ; # Fix for [Bug 821126] + set nums {} + + binary scan $string c* X + lappend X 61 ;# force a terminator + foreach x $X { + set bits [lindex $base64 $x] + if {$bits >= 0} { + if {[llength [lappend nums $bits]] == 4} { + foreach {v w z y} $nums break + set a [expr {($v << 2) | ($w >> 4)}] + set b [expr {(($w & 0xF) << 4) | ($z >> 2)}] + set c [expr {(($z & 0x3) << 6) | $y}] + append output [binary format ccc $a $b $c] + set nums {} + } + } elseif {$bits == -1} { + # = indicates end of data. Output whatever chars are + # left, if any. + if {![llength $nums]} break + # The encoding algorithm dictates that we can only + # have 1 or 2 padding characters. If x=={}, we must + # (*) have 12 bits of input (enough for 1 8-bit + # output). If x!={}, we have 18 bits of input (enough + # for 2 8-bit outputs). + # + # (*) If we don't then the input is broken (bug 2976290). + + foreach {v w z} $nums break + + # Bug 2976290 + if {$w == {}} { + return -code error "Not enough data to process padding" + } + + set a [expr {($v << 2) | (($w & 0x30) >> 4)}] + if {$z == {}} { + append output [binary format c $a ] + } else { + set b [expr {(($w & 0xF) << 4) | (($z & 0x3C) >> 2)}] + append output [binary format cc $a $b] + } + break + } else { + # RFC 2045 says that line breaks and other characters not part + # of the Base64 alphabet must be ignored, and that the decoder + # can optionally emit a warning or reject the message. We opt + # not to do so, but to just ignore the character. + continue + } + } + return $output + } +} + +# # ## ### ##### ######## ############# ##################### +return + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/base64c.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/base64c.tcl new file mode 100644 index 00000000..29e501df --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/base64c.tcl @@ -0,0 +1,19 @@ +# base64c - Copyright (C) 2003 Pat Thoyts +# +# This package is a place-holder for the critcl enhanced code present in +# the tcllib base64 module. +# +# Normally this code will become part of the tcllibc library. +# + +# @sak notprovided base64c +package require critcl +package provide base64c 0.1.0 + +namespace eval ::base64c { + variable base64c_rcsid {$Id: base64c.tcl,v 1.5 2008/03/25 07:15:35 andreas_kupries Exp $} + + critcl::ccode { + /* no code required in this file */ + } +} diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/pkgIndex.tcl new file mode 100644 index 00000000..c8528f59 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/pkgIndex.tcl @@ -0,0 +1,5 @@ +if {![package vsatisfies [package provide Tcl] 8.2]} {return} +package ifneeded base64 2.5 [list source [file join $dir base64.tcl]] +package ifneeded uuencode 1.1.5 [list source [file join $dir uuencode.tcl]] +package ifneeded yencode 1.1.3 [list source [file join $dir yencode.tcl]] +package ifneeded ascii85 1.0 [list source [file join $dir ascii85.tcl]] diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/uuencode.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/uuencode.tcl new file mode 100644 index 00000000..5e26422d --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/uuencode.tcl @@ -0,0 +1,335 @@ +# uuencode - Copyright (C) 2002 Pat Thoyts +# +# Provide a Tcl only implementation of uuencode and uudecode. +# +# ------------------------------------------------------------------------- +# 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; # tcl minimum version + +# Try and get some compiled helper package. +if {[catch {package require tcllibc}]} { + catch {package require Trf} +} + +namespace eval ::uuencode { + namespace export encode decode uuencode uudecode +} + +proc ::uuencode::Enc {c} { + return [format %c [expr {($c != 0) ? (($c & 0x3f) + 0x20) : 0x60}]] +} + +proc ::uuencode::Encode {s} { + set r {} + binary scan $s c* d + foreach {c1 c2 c3} $d { + if {$c1 == {}} {set c1 0} + if {$c2 == {}} {set c2 0} + if {$c3 == {}} {set c3 0} + append r [Enc [expr {$c1 >> 2}]] + append r [Enc [expr {(($c1 << 4) & 060) | (($c2 >> 4) & 017)}]] + append r [Enc [expr {(($c2 << 2) & 074) | (($c3 >> 6) & 003)}]] + append r [Enc [expr {($c3 & 077)}]] + } + return $r +} + + +proc ::uuencode::Decode {s} { + if {[string length $s] == 0} {return ""} + set r {} + binary scan [pad $s] c* d + + foreach {c0 c1 c2 c3} $d { + append r [format %c [expr {((($c0-0x20)&0x3F) << 2) & 0xFF + | ((($c1-0x20)&0x3F) >> 4) & 0xFF}]] + append r [format %c [expr {((($c1-0x20)&0x3F) << 4) & 0xFF + | ((($c2-0x20)&0x3F) >> 2) & 0xFF}]] + append r [format %c [expr {((($c2-0x20)&0x3F) << 6) & 0xFF + | (($c3-0x20)&0x3F) & 0xFF}]] + } + return $r +} + +# ------------------------------------------------------------------------- +# C coded version of the Encode/Decode functions for base64c package. +# ------------------------------------------------------------------------- +if {[package provide critcl] != {}} { + namespace eval ::uuencode { + critcl::ccode { + #include + static unsigned char Enc(unsigned char c) { + return (c != 0) ? ((c & 0x3f) + 0x20) : 0x60; + } + } + critcl::ccommand CEncode {dummy interp objc objv} { + Tcl_Obj *inputPtr, *resultPtr; + int len, rlen, xtra; + unsigned char *input, *p, *r; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "data"); + return TCL_ERROR; + } + + inputPtr = objv[1]; + input = Tcl_GetByteArrayFromObj(inputPtr, &len); + if ((xtra = (3 - (len % 3))) != 3) { + if (Tcl_IsShared(inputPtr)) + inputPtr = Tcl_DuplicateObj(inputPtr); + input = Tcl_SetByteArrayLength(inputPtr, len + xtra); + memset(input + len, 0, xtra); + len += xtra; + } + + rlen = (len / 3) * 4; + resultPtr = Tcl_NewObj(); + r = Tcl_SetByteArrayLength(resultPtr, rlen); + memset(r, 0, rlen); + + for (p = input; p < input + len; p += 3) { + char a, b, c; + a = *p; b = *(p+1), c = *(p+2); + *r++ = Enc(a >> 2); + *r++ = Enc(((a << 4) & 060) | ((b >> 4) & 017)); + *r++ = Enc(((b << 2) & 074) | ((c >> 6) & 003)); + *r++ = Enc(c & 077); + } + Tcl_SetObjResult(interp, resultPtr); + return TCL_OK; + } + + critcl::ccommand CDecode {dummy interp objc objv} { + Tcl_Obj *inputPtr, *resultPtr; + int len, rlen, xtra; + unsigned char *input, *p, *r; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "data"); + return TCL_ERROR; + } + + /* if input is not mod 4, extend it with nuls */ + inputPtr = objv[1]; + input = Tcl_GetByteArrayFromObj(inputPtr, &len); + if ((xtra = (4 - (len % 4))) != 4) { + if (Tcl_IsShared(inputPtr)) + inputPtr = Tcl_DuplicateObj(inputPtr); + input = Tcl_SetByteArrayLength(inputPtr, len + xtra); + memset(input + len, 0, xtra); + len += xtra; + } + + /* output will be 1/3 smaller than input and a multiple of 3 */ + rlen = (len / 4) * 3; + resultPtr = Tcl_NewObj(); + r = Tcl_SetByteArrayLength(resultPtr, rlen); + memset(r, 0, rlen); + + for (p = input; p < input + len; p += 4) { + char a, b, c, d; + a = *p; b = *(p+1), c = *(p+2), d = *(p+3); + *r++ = (((a - 0x20) & 0x3f) << 2) | (((b - 0x20) & 0x3f) >> 4); + *r++ = (((b - 0x20) & 0x3f) << 4) | (((c - 0x20) & 0x3f) >> 2); + *r++ = (((c - 0x20) & 0x3f) << 6) | (((d - 0x20) & 0x3f) ); + } + Tcl_SetObjResult(interp, resultPtr); + return TCL_OK; + } + } +} + +# ------------------------------------------------------------------------- + +# Description: +# Permit more tolerant decoding of invalid input strings by padding to +# a multiple of 4 bytes with nulls. +# Result: +# Returns the input string - possibly padded with uuencoded null chars. +# +proc ::uuencode::pad {s} { + if {[set mod [expr {[string length $s] % 4}]] != 0} { + append s [string repeat "`" [expr {4 - $mod}]] + } + return $s +} + +# ------------------------------------------------------------------------- + +# If the Trf package is available then we shall use this by default but the +# Tcllib implementations are always visible if needed (ie: for testing) +if {[info commands ::uuencode::CDecode] != {}} { + # tcllib critcl package + interp alias {} ::uuencode::encode {} ::uuencode::CEncode + interp alias {} ::uuencode::decode {} ::uuencode::CDecode +} elseif {[package provide Trf] != {}} { + proc ::uuencode::encode {s} { + return [::uuencode -mode encode -- $s] + } + proc ::uuencode::decode {s} { + return [::uuencode -mode decode -- [pad $s]] + } +} else { + # pure-tcl then + interp alias {} ::uuencode::encode {} ::uuencode::Encode + interp alias {} ::uuencode::decode {} ::uuencode::Decode +} + +# ------------------------------------------------------------------------- + +proc ::uuencode::uuencode {args} { + array set opts {mode 0644 filename {} name {}} + set wrongargs "wrong \# args: should be\ + \"uuencode ?-name string? ?-mode octal?\ + (-file filename | ?--? string)\"" + while {[string match -* [lindex $args 0]]} { + switch -glob -- [lindex $args 0] { + -f* { + if {[llength $args] < 2} { + return -code error $wrongargs + } + set opts(filename) [lindex $args 1] + set args [lreplace $args 0 0] + } + -m* { + if {[llength $args] < 2} { + return -code error $wrongargs + } + set opts(mode) [lindex $args 1] + set args [lreplace $args 0 0] + } + -n* { + if {[llength $args] < 2} { + return -code error $wrongargs + } + set opts(name) [lindex $args 1] + set args [lreplace $args 0 0] + } + -- { + set args [lreplace $args 0 0] + break + } + default { + return -code error "bad option [lindex $args 0]:\ + must be -file, -mode, or -name" + } + } + set args [lreplace $args 0 0] + } + + if {$opts(name) == {}} { + set opts(name) $opts(filename) + } + if {$opts(name) == {}} { + set opts(name) "data.dat" + } + + if {$opts(filename) != {}} { + set f [open $opts(filename) r] + fconfigure $f -translation binary + set data [read $f] + close $f + } else { + if {[llength $args] != 1} { + return -code error $wrongargs + } + set data [lindex $args 0] + } + + set r {} + append r [format "begin %o %s" $opts(mode) $opts(name)] "\n" + for {set n 0} {$n < [string length $data]} {incr n 45} { + set s [string range $data $n [expr {$n + 44}]] + append r [Enc [string length $s]] + append r [encode $s] "\n" + } + append r "`\nend" + return $r +} + +# ------------------------------------------------------------------------- +# Description: +# Perform uudecoding of a file or data. A file may contain more than one +# encoded data section so the result is a list where each element is a +# three element list of the provided filename, the suggested mode and the +# data itself. +# +proc ::uuencode::uudecode {args} { + array set opts {mode 0644 filename {}} + set wrongargs "wrong \# args: should be \"uudecode (-file filename | ?--? string)\"" + while {[string match -* [lindex $args 0]]} { + switch -glob -- [lindex $args 0] { + -f* { + if {[llength $args] < 2} { + return -code error $wrongargs + } + set opts(filename) [lindex $args 1] + set args [lreplace $args 0 0] + } + -- { + set args [lreplace $args 0 0] + break + } + default { + return -code error "bad option [lindex $args 0]:\ + must be -file" + } + } + set args [lreplace $args 0 0] + } + + if {$opts(filename) != {}} { + set f [open $opts(filename) r] + set data [read $f] + close $f + } else { + if {[llength $args] != 1} { + return -code error $wrongargs + } + set data [lindex $args 0] + } + + set state false + set result {} + + foreach {line} [split $data "\n"] { + switch -exact -- $state { + false { + if {[regexp {^begin ([0-7]+) ([^\s]*)} $line \ + -> opts(mode) opts(name)]} { + set state true + set r {} + } + } + + true { + if {[string match "end" $line]} { + set state false + lappend result [list $opts(name) $opts(mode) $r] + } else { + scan $line %c c + set n [expr {($c - 0x21)}] + append r [string range \ + [decode [string range $line 1 end]] 0 $n] + } + } + } + } + + return $result +} + +# ------------------------------------------------------------------------- + +package provide uuencode 1.1.5 + +# ------------------------------------------------------------------------- +# +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/yencode.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/yencode.tcl new file mode 100644 index 00000000..0d4554c0 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/base64/yencode.tcl @@ -0,0 +1,307 @@ +# yencode.tcl - Copyright (C) 2002 Pat Thoyts +# +# Provide a Tcl only implementation of yEnc encoding algorithm +# +# ------------------------------------------------------------------------- +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# ------------------------------------------------------------------------- + +# FUTURE: Rework to allow switching between the tcl/critcl implementations. + +package require Tcl 8.2; # tcl minimum version +catch {package require crc32}; # tcllib 1.1 +catch {package require tcllibc}; # critcl enhancements for tcllib + +namespace eval ::yencode { + namespace export encode decode yencode ydecode +} + +# ------------------------------------------------------------------------- + +proc ::yencode::Encode {s} { + set r {} + binary scan $s c* d + foreach {c} $d { + set v [expr {($c + 42) % 256}] + if {$v == 0x00 || $v == 0x09 || $v == 0x0A + || $v == 0x0D || $v == 0x3D} { + append r "=" + set v [expr {($v + 64) % 256}] + } + append r [format %c $v] + } + return $r +} + +proc ::yencode::Decode {s} { + if {[string length $s] == 0} {return ""} + set r {} + set esc 0 + binary scan $s c* d + foreach c $d { + if {$c == 61 && $esc == 0} { + set esc 1 + continue + } + set v [expr {($c - 42) % 256}] + if {$esc} { + set v [expr {($v - 64) % 256}] + set esc 0 + } + append r [format %c $v] + } + return $r +} + +# ------------------------------------------------------------------------- +# C coded versions for critcl built base64c package +# ------------------------------------------------------------------------- + +if {[package provide critcl] != {}} { + namespace eval ::yencode { + critcl::ccode { + #include + } + critcl::ccommand CEncode {dummy interp objc objv} { + Tcl_Obj *inputPtr, *resultPtr; + int len, rlen, xtra; + unsigned char *input, *p, *r, v; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "data"); + return TCL_ERROR; + } + + /* fetch the input data */ + inputPtr = objv[1]; + input = Tcl_GetByteArrayFromObj(inputPtr, &len); + + /* calculate the length of the encoded result */ + rlen = len; + for (p = input; p < input + len; p++) { + v = (*p + 42) % 256; + if (v == 0 || v == 9 || v == 0x0A || v == 0x0D || v == 0x3D) + rlen++; + } + + /* allocate the output buffer */ + resultPtr = Tcl_NewObj(); + r = Tcl_SetByteArrayLength(resultPtr, rlen); + + /* encode the input */ + for (p = input; p < input + len; p++) { + v = (*p + 42) % 256; + if (v == 0 || v == 9 || v == 0x0A || v == 0x0D || v == 0x3D) { + *r++ = '='; + v = (v + 64) % 256; + } + *r++ = v; + } + Tcl_SetObjResult(interp, resultPtr); + return TCL_OK; + } + + critcl::ccommand CDecode {dummy interp objc objv} { + Tcl_Obj *inputPtr, *resultPtr; + int len, rlen, esc; + unsigned char *input, *p, *r, v; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "data"); + return TCL_ERROR; + } + + /* fetch the input data */ + inputPtr = objv[1]; + input = Tcl_GetByteArrayFromObj(inputPtr, &len); + + /* allocate the output buffer */ + resultPtr = Tcl_NewObj(); + r = Tcl_SetByteArrayLength(resultPtr, len); + + /* encode the input */ + for (p = input, esc = 0, rlen = 0; p < input + len; p++) { + if (*p == 61 && esc == 0) { + esc = 1; + continue; + } + v = (*p - 42) % 256; + if (esc) { + v = (v - 64) % 256; + esc = 0; + } + *r++ = v; + rlen++; + } + Tcl_SetByteArrayLength(resultPtr, rlen); + Tcl_SetObjResult(interp, resultPtr); + return TCL_OK; + } + } +} + +if {[info commands ::yencode::CEncode] != {}} { + interp alias {} ::yencode::encode {} ::yencode::CEncode + interp alias {} ::yencode::decode {} ::yencode::CDecode +} else { + interp alias {} ::yencode::encode {} ::yencode::Encode + interp alias {} ::yencode::decode {} ::yencode::Decode +} + +# ------------------------------------------------------------------------- +# Description: +# Pop the nth element off a list. Used in options processing. +# +proc ::yencode::Pop {varname {nth 0}} { + upvar $varname args + set r [lindex $args $nth] + set args [lreplace $args $nth $nth] + return $r +} + +# ------------------------------------------------------------------------- + +proc ::yencode::yencode {args} { + array set opts {mode 0644 filename {} name {} line 128 crc32 1} + while {[string match -* [lindex $args 0]]} { + switch -glob -- [lindex $args 0] { + -f* { set opts(filename) [Pop args 1] } + -m* { set opts(mode) [Pop args 1] } + -n* { set opts(name) [Pop args 1] } + -l* { set opts(line) [Pop args 1] } + -c* { set opts(crc32) [Pop args 1] } + -- { Pop args ; break } + default { + set options [join [lsort [array names opts]] ", -"] + return -code error "bad option [lindex $args 0]:\ + must be -$options" + } + } + Pop args + } + + if {$opts(name) == {}} { + set opts(name) $opts(filename) + } + if {$opts(name) == {}} { + set opts(name) "data.dat" + } + if {! [string is boolean $opts(crc32)]} { + return -code error "bad option -crc32: argument must be true or false" + } + + if {$opts(filename) != {}} { + set f [open $opts(filename) r] + fconfigure $f -translation binary + set data [read $f] + close $f + } else { + if {[llength $args] != 1} { + return -code error "wrong \# args: should be\ + \"yencode ?options? -file name | data\"" + } + set data [lindex $args 0] + } + + set opts(size) [string length $data] + + set r {} + append r [format "=ybegin line=%d size=%d name=%s" \ + $opts(line) $opts(size) $opts(name)] "\n" + + set ndx 0 + while {$ndx < $opts(size)} { + set pln [string range $data $ndx [expr {$ndx + $opts(line) - 1}]] + set enc [encode $pln] + incr ndx [string length $pln] + append r $enc "\r\n" + } + + append r [format "=yend size=%d" $ndx] + if {$opts(crc32)} { + append r " crc32=" [crc::crc32 -format %x $data] + } + return $r +} + +# ------------------------------------------------------------------------- +# Description: +# Perform ydecoding of a file or data. A file may contain more than one +# encoded data section so the result is a list where each element is a +# three element list of the provided filename, the file size and the +# data itself. +# +proc ::yencode::ydecode {args} { + array set opts {mode 0644 filename {} name default.bin} + while {[string match -* [lindex $args 0]]} { + switch -glob -- [lindex $args 0] { + -f* { set opts(filename) [Pop args 1] } + -- { Pop args ; break; } + default { + set options [join [lsort [array names opts]] ", -"] + return -code error "bad option [lindex $args 0]:\ + must be -$opts" + } + } + Pop args + } + + if {$opts(filename) != {}} { + set f [open $opts(filename) r] + set data [read $f] + close $f + } else { + if {[llength $args] != 1} { + return -code error "wrong \# args: should be\ + \"ydecode ?options? -file name | data\"" + } + set data [lindex $args 0] + } + + set state false + set result {} + + foreach {line} [split $data "\n"] { + set line [string trimright $line "\r\n"] + switch -exact -- $state { + false { + if {[string match "=ybegin*" $line]} { + regexp {line=(\d+)} $line -> opts(line) + regexp {size=(\d+)} $line -> opts(size) + regexp {name=(\d+)} $line -> opts(name) + + if {$opts(name) == {}} { + set opts(name) default.bin + } + + set state true + set r {} + } + } + + true { + if {[string match "=yend*" $line]} { + set state false + lappend result [list $opts(name) $opts(size) $r] + } else { + append r [decode $line] + } + } + } + } + + return $result +} + +# ------------------------------------------------------------------------- + +package provide yencode 1.1.3 + +# ------------------------------------------------------------------------- +# +# Local variables: +# mode: tcl +# indent-tabs-mode: nil +# End: + diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bee/bee.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bee/bee.tcl new file mode 100644 index 00000000..6eb53c06 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bee/bee.tcl @@ -0,0 +1,990 @@ +# bee.tcl -- +# +# BitTorrent Bee de- and encoder. +# +# Copyright (c) 2004 by Andreas Kupries +# See the file license.terms. + +package require Tcl 8.4 + +namespace eval ::bee { + # Encoder commands + namespace export \ + encodeString encodeNumber \ + encodeListArgs encodeList \ + encodeDictArgs encodeDict + + # Decoder commands. + namespace export \ + decode \ + decodeChannel \ + decodeCancel \ + decodePush + + # Channel decoders, reference to state information, keyed by + # channel handle. + + variable bee + array set bee {} + + # Counter for generation of names for the state variables. + + variable count 0 + + # State information for the channel decoders. + + # stateN, with N an integer number counting from 0 on up. + # ...(chan) Handle of channel the decoder is for. + # ...(cmd) Command prefix, completion callback + # ...(exact) Boolean flag, set for exact processing. + # ...(read) Buffer for new characters to process. + # ...(type) Type of current value (integer, string, list, dict) + # ...(value) Buffer for assembling the current value. + # ...(pend) Stack of pending 'value' buffers, for nested + # containers. + # ...(state) Current state of the decoding state machine. + + # States of the finite automaton ... + # intro - One char, type of value, or 'e' as stop of container. + # signum - sign or digit, for integer. + # idigit - digit, for integer, or 'e' as stop + # ldigit - digit, for length of string, or : + # data - string data, 'get' characters. + # Containers via 'pend'. + + #Debugging help, nesting level + #variable X 0 +} + + +# ::bee::encodeString -- +# +# Encode a string to bee-format. +# +# Arguments: +# string The string to encode. +# +# Results: +# The bee-encoded form of the string. + +proc ::bee::encodeString {string} { + return "[string length $string]:$string" +} + + +# ::bee::encodeNumber -- +# +# Encode an integer number to bee-format. +# +# Arguments: +# num The integer number to encode. +# +# Results: +# The bee-encoded form of the integer number. + +proc ::bee::encodeNumber {num} { + if {![string is integer -strict $num]} { + return -code error "Expected integer number, got \"$num\"" + } + + # The reformatting deals with hex, octal and other tcl + # representation of the value. In other words we normalize the + # string representation of the input value. + + set num [format %d $num] + return "i${num}e" +} + + +# ::bee::encodeList -- +# +# Encode a list of bee-coded values to bee-format. +# +# Arguments: +# list The list to encode. +# +# Results: +# The bee-encoded form of the list. + +proc ::bee::encodeList {list} { + return "l[join $list ""]e" +} + + +# ::bee::encodeListArgs -- +# +# Encode a variable list of bee-coded values to bee-format. +# +# Arguments: +# args The values to encode. +# +# Results: +# The bee-encoded form of the list of values. + +proc ::bee::encodeListArgs {args} { + return [encodeList $args] +} + + +# ::bee::encodeDict -- +# +# Encode a dictionary of keys and bee-coded values to bee-format. +# +# Arguments: +# dict The dictionary to encode. +# +# Results: +# The bee-encoded form of the dictionary. + +proc ::bee::encodeDict {dict} { + if {([llength $dict] % 2) == 1} { + return -code error "Expected even number of elements, got \"[llength $dict]\"" + } + set temp [list] + foreach {k v} $dict { + lappend temp [list $k $v] + } + set res "d" + foreach item [lsort -index 0 $temp] { + foreach {k v} $item break + append res [encodeString $k]$v + } + append res "e" + return $res +} + + +# ::bee::encodeDictArgs -- +# +# Encode a variable dictionary of keys and bee-coded values to bee-format. +# +# Arguments: +# args The keys and values to encode. +# +# Results: +# The bee-encoded form of the dictionary. + +proc ::bee::encodeDictArgs {args} { + return [encodeDict $args] +} + + +# ::bee::decode -- +# +# Decode a bee-encoded value and returns the embedded tcl +# value. For containers this recurses into the contained value. +# +# Arguments: +# value The string containing the bee-encoded value to decode. +# evar Optional. If set the name of the variable to store the +# index of the first character after the decoded value to. +# start Optional. If set the index of the first character of the +# value to decode. Defaults to 0, i.e. the beginning of the +# string. +# +# Results: +# The tcl value embedded in the encoded string. + +proc ::bee::decode {value {evar {}} {start 0}} { + #variable X + #puts -nonewline "[string repeat " " $X]decode @$start" ; flush stdout + + if {$evar ne ""} {upvar 1 $evar end} else {set end _} + + if {[string length $value] < ($start+2)} { + # This checked that the 'start' index is still in the string, + # and the end of the value most likely as well. Note that each + # encoded value consists of at least two characters (the + # bracketing characters for integer, list, and dict, and for + # string at least one digit length and the colon). + + #puts \t[string length $value]\ <\ ($start+2) + return -code error "String not large enough for value" + } + + set type [string index $value $start] + + #puts -nonewline " $type=" ; flush stdout + + if {$type eq "i"} { + # Extract integer + #puts -nonewline integer ; flush stdout + + incr start ; # Skip over intro 'i'. + set end [string first e $value $start] + if {$end < 0} { + return -code error "End of integer number not found" + } + incr end -1 ; # Get last character before closing 'e'. + set num [string range $value $start $end] + if { + [regexp {^-0+$} $num] || + ![string is integer -strict $num] || + (([string length $num] > 1) && [string match 0* $num]) + } { + return -code error "Expected integer number, got \"$num\"" + } + incr end 2 ; # Step after closing 'e' to the beginning of + # ........ ; # the next bee-value behind the current one. + + #puts " ($num) @$end" + return $num + + } elseif {($type eq "l") || ($type eq "d")} { + #puts -nonewline $type\n ; flush stdout + + # Extract list or dictionary, recursively each contained + # element. From the perspective of the decoder this is the + # same, the tcl representation of both is a list, and for a + # dictionary keys and values are also already in the correct + # order. + + set result [list] + incr start ; # Step over intro 'e' to beginning of the first + # ........ ; # contained value, or behind the container (if + # ........ ; # empty). + + set end $start + #incr X + while {[string index $value $start] ne "e"} { + lappend result [decode $value end $start] + set start $end + } + #incr X -1 + incr end + + #puts "[string repeat " " $X]($result) @$end" + + if {$type eq "d" && ([llength $result] % 2 == 1)} { + return -code error "Dictionary has to be of even length" + } + return $result + + } elseif {[string match {[0-9]} $type]} { + #puts -nonewline string ; flush stdout + + # Extract string. First the length, bounded by a colon, then + # the appropriate number of characters. + + set end [string first : $value $start] + if {$end < 0} { + return -code error "End of string length not found" + } + incr end -1 + set length [string range $value $start $end] + incr end 2 ;# Skip to beginning of the string after the colon + + if {![string is integer -strict $length]} { + return -code error "Expected integer number for string length, got \"$length\"" + } elseif {$length < 0} { + # This cannot happen. To happen "-" has to be first character, + # and this is caught as unknown bee-type. + return -code error "Illegal negative string length" + } elseif {($end + $length) > [string length $value]} { + return -code error "String not large enough for value" + } + + #puts -nonewline \[$length\] ; flush stdout + if {$length > 0} { + set start $end + incr end $length + incr end -1 + set result [string range $value $start $end] + incr end + } else { + set result "" + } + + #puts " ($result) @$end" + return $result + + } else { + return -code error "Unknown bee-type \"$type\"" + } +} + +# ::bee::decodeIndices -- +# +# Similar to 'decode', but does not return the decoded tcl values, +# but a structure containing the start- and end-indices for all +# values in the structure. +# +# Arguments: +# value The string containing the bee-encoded value to decode. +# evar Optional. If set the name of the variable to store the +# index of the first character after the decoded value to. +# start Optional. If set the index of the first character of the +# value to decode. Defaults to 0, i.e. the beginning of the +# string. +# +# Results: +# The structure of the value, with indices and types for all +# contained elements. + +proc ::bee::decodeIndices {value {evar {}} {start 0}} { + #variable X + #puts -nonewline "[string repeat " " $X]decode @$start" ; flush stdout + + if {$evar ne ""} {upvar 1 $evar end} else {set end _} + + if {[string length $value] < ($start+2)} { + # This checked that the 'start' index is still in the string, + # and the end of the value most likely as well. Note that each + # encoded value consists of at least two characters (the + # bracketing characters for integer, list, and dict, and for + # string at least one digit length and the colon). + + #puts \t[string length $value]\ <\ ($start+2) + return -code error "String not large enough for value" + } + + set type [string index $value $start] + + #puts -nonewline " $type=" ; flush stdout + + if {$type eq "i"} { + # Extract integer + #puts -nonewline integer ; flush stdout + + set begin $start + + incr start ; # Skip over intro 'i'. + set end [string first e $value $start] + if {$end < 0} { + return -code error "End of integer number not found" + } + incr end -1 ; # Get last character before closing 'e'. + set num [string range $value $start $end] + if { + [regexp {^-0+$} $num] || + ![string is integer -strict $num] || + (([string length $num] > 1) && [string match 0* $num]) + } { + return -code error "Expected integer number, got \"$num\"" + } + incr end + set stop $end + incr end 1 ; # Step after closing 'e' to the beginning of + # ........ ; # the next bee-value behind the current one. + + #puts " ($num) @$end" + return [list integer $begin $stop] + + } elseif {$type eq "l"} { + #puts -nonewline $type\n ; flush stdout + + # Extract list, recursively each contained element. + + set result [list] + + lappend result list $start @ + + incr start ; # Step over intro 'e' to beginning of the first + # ........ ; # contained value, or behind the container (if + # ........ ; # empty). + + set end $start + #incr X + + set contained [list] + while {[string index $value $start] ne "e"} { + lappend contained [decodeIndices $value end $start] + set start $end + } + lappend result $contained + #incr X -1 + set stop $end + incr end + + #puts "[string repeat " " $X]($result) @$end" + + return [lreplace $result 2 2 $stop] + + } elseif {($type eq "l") || ($type eq "d")} { + #puts -nonewline $type\n ; flush stdout + + # Extract dictionary, recursively each contained element. + + set result [list] + + lappend result dict $start @ + + incr start ; # Step over intro 'e' to beginning of the first + # ........ ; # contained value, or behind the container (if + # ........ ; # empty). + + set end $start + set atkey 1 + #incr X + + set contained [list] + set val [list] + while {[string index $value $start] ne "e"} { + if {$atkey} { + lappend contained [decode $value {} $start] + lappend val [decodeIndices $value end $start] + set atkey 0 + } else { + lappend val [decodeIndices $value end $start] + lappend contained $val + set val [list] + set atkey 1 + } + set start $end + } + lappend result $contained + #incr X -1 + set stop $end + incr end + + #puts "[string repeat " " $X]($result) @$end" + + if {[llength $result] % 2 == 1} { + return -code error "Dictionary has to be of even length" + } + return [lreplace $result 2 2 $stop] + + } elseif {[string match {[0-9]} $type]} { + #puts -nonewline string ; flush stdout + + # Extract string. First the length, bounded by a colon, then + # the appropriate number of characters. + + set end [string first : $value $start] + if {$end < 0} { + return -code error "End of string length not found" + } + incr end -1 + set length [string range $value $start $end] + incr end 2 ;# Skip to beginning of the string after the colon + + if {![string is integer -strict $length]} { + return -code error "Expected integer number for string length, got \"$length\"" + } elseif {$length < 0} { + # This cannot happen. To happen "-" has to be first character, + # and this is caught as unknown bee-type. + return -code error "Illegal negative string length" + } elseif {($end + $length) > [string length $value]} { + return -code error "String not large enough for value" + } + + #puts -nonewline \[$length\] ; flush stdout + incr end -1 + if {$length > 0} { + incr end $length + set stop $end + } else { + set stop $end + } + incr end + + #puts " ($result) @$end" + return [list string $start $stop] + + } else { + return -code error "Unknown bee-type \"$type\"" + } +} + + +# ::bee::decodeChannel -- +# +# Attach decoder for a bee-value to a channel. See the +# documentation for details. +# +# Arguments: +# chan Channel to attach to. +# -command cmdprefix Completion callback. Required. +# -exact Keep running after completion. +# -prefix data Seed for decode buffer. +# +# Results: +# A token to use when referring to the decoder. +# For example when canceling it. + +proc ::bee::decodeChannel {chan args} { + variable bee + if {[info exists bee($chan)]} { + return -code error "bee-Decoder already active for channel" + } + + # Create state and token. + + variable count + variable [set st state$count] + array set $st {} + set bee($chan) $st + upvar 0 $st state + incr count + + # Initialize the decoder state, process the options. When + # encountering errors here destroy the half-baked state before + # throwing the message. + + set state(chan) $chan + array set state { + exact 0 + type ? + read {} + value {} + pend {} + state intro + get 1 + } + + while {[llength $args]} { + set option [lindex $args 0] + set args [lrange $args 1 end] + if {$option eq "-command"} { + if {![llength $args]} { + unset bee($chan) + unset state + return -code error "Missing value for option -command." + } + set state(cmd) [lindex $args 0] + set args [lrange $args 1 end] + + } elseif {$option eq "-prefix"} { + if {![llength $args]} { + unset bee($chan) + unset state + return -code error "Missing value for option -prefix." + } + set state(read) [lindex $args 0] + set args [lrange $args 1 end] + + } elseif {$option eq "-exact"} { + set state(exact) 1 + } else { + unset bee($chan) + unset state + return -code error "Illegal option \"$option\",\ + expected \"-command\", \"-prefix\", or \"-keep\"" + } + } + + if {![info exists state(cmd)]} { + unset bee($chan) + unset state + return -code error "Missing required completion callback." + } + + # Set up the processing of incoming data. + + fileevent $chan readable [list ::bee::Process $chan $bee($chan)] + + # Return the name of the state array as token. + return $bee($chan) +} + +# ::bee::Parse -- +# +# Internal helper. Fileevent handler for a decoder. +# Parses input and handles both error and eof conditions. +# +# Arguments: +# token The decoder to run on its input. +# +# Results: +# None. + +proc ::bee::Process {chan token} { + if {[catch {Parse $token} msg]} { + # Something failed. Destroy and report. + Command $token error $msg + return + } + + if {[eof $chan]} { + # Having data waiting, either in the input queue, or in the + # output stack (of nested containers) is a failure. Report + # this instead of the eof. + + variable $token + upvar 0 $token state + + if { + [string length $state(read)] || + [llength $state(pend)] || + [string length $state(value)] || + ($state(state) ne "intro") + } { + Command $token error "Incomplete value at end of channel" + } else { + Command $token eof + } + } + return +} + +# ::bee::Parse -- +# +# Internal helper. Reading from the channel and parsing the input. +# Uses a hardwired state machine. +# +# Arguments: +# token The decoder to run on its input. +# +# Results: +# None. + +proc ::bee::Parse {token} { + variable $token + upvar 0 $token state + upvar 0 state(state) current + upvar 0 state(read) input + upvar 0 state(type) type + upvar 0 state(value) value + upvar 0 state(pend) pend + upvar 0 state(exact) exact + upvar 0 state(get) get + set chan $state(chan) + + #puts Parse/$current + + if {!$exact} { + # Add all waiting characters to the buffer so that we can process as + # much as is possible in one go. + append input [read $chan] + } else { + # Exact reading. Usually one character, but when in the data + # section for a string value we know for how many characters + # we are looking for. + + append input [read $chan $get] + } + + # We got nothing, do nothing. + if {![string length $input]} return + + + if {$current eq "data"} { + # String data, this can be done faster, as we read longer + # sequences of characters for this. + set l [string length $input] + if {$l < $get} { + # Not enough, wait for more. + append value $input + incr get -$l + return + } elseif {$l == $get} { + # Got all, exactly. Prepare state machine for next value. + + if {[Complete $token $value$input]} return + + set current intro + set get 1 + set value "" + set input "" + + return + } else { + # Got more than required (only for !exact). + + incr get -1 + if {[Complete $token $value[string range $input 0 $get]]} {return} + + incr get + set input [string range $input $get end] + set get 1 + set value "" + set current intro + # This now falls into the loop below. + } + } + + set where 0 + set n [string length $input] + + #puts Parse/$n + + while {$where < $n} { + # Hardwired state machine. Get current character. + set ch [string index $input $where] + + #puts Parse/@$where/$current/$ch/ + if {$current eq "intro"} { + # First character of a value. + + if {$ch eq "i"} { + # Begin reading integer. + set type integer + set current signum + } elseif {$ch eq "l"} { + # Begin a list. + set type list + lappend pend list {} + #set current intro + + } elseif {$ch eq "d"} { + # Begin a dictionary. + set type dict + lappend pend dict {} + #set current intro + + } elseif {$ch eq "e"} { + # Close a container. Throw an error if there is no + # container to close. + + if {![llength $pend]} { + return -code error "End of container outside of container." + } + + set v [lindex $pend end] + set t [lindex $pend end-1] + set pend [lrange $pend 0 end-2] + + if {$t eq "dict" && ([llength $v] % 2 == 1)} { + return -code error "Dictionary has to be of even length" + } + + if {[Complete $token $v]} {return} + set current intro + + } elseif {[string match {[0-9]} $ch]} { + # Begin reading a string, length section first. + set type string + set current ldigit + set value $ch + + } else { + # Unknown type. Throw error. + return -code error "Unknown bee-type \"$ch\"" + } + + # To next character. + incr where + } elseif {$current eq "signum"} { + # Integer number, a minus sign, or a digit. + if {[string match {[-0-9]} $ch]} { + append value $ch + set current idigit + } else { + return -code error "Syntax error in integer,\ + expected sign or digit, got \"$ch\"" + } + incr where + + } elseif {$current eq "idigit"} { + # Integer number, digit or closing 'e'. + + if {[string match {[-0-9]} $ch]} { + append value $ch + } elseif {$ch eq "e"} { + # Integer closes. Validate and report. + #puts validate + if { + [regexp {^-0+$} $value] || + ![string is integer -strict $value] || + (([string length $value] > 1) && [string match 0* $value]) + } { + return -code error "Expected integer number, got \"$value\"" + } + + if {[Complete $token $value]} {return} + set value "" + set current intro + } else { + return -code error "Syntax error in integer,\ + expected digit, or 'e', got \"$ch\"" + } + incr where + + } elseif {$current eq "ldigit"} { + # String, length section, digit, or : + + if {[string match {[-0-9]} $ch]} { + append value $ch + + } elseif {$ch eq ":"} { + # Length section closes, validate, + # then perform data processing. + + set num $value + if { + [regexp {^-0+$} $num] || + ![string is integer -strict $num] || + (([string length $num] > 1) && [string match 0* $num]) + } { + return -code error "Expected integer number as string length, got \"$num\"" + } + + set value "" + + # We may have already part of the data in + # memory. Process that piece before looking for more. + + incr where + set have [expr {$n - $where}] + if {$num < $have} { + # More than enough in the buffer. + + set end $where + incr end $num + incr end -1 + + if {[Complete $token [string range $input $where $end]]} {return} + + set where $end ;# Further processing behind the string. + set current intro + + } elseif {$num == $have} { + # Just enough. + + if {[Complete $token [string range $input $where end]]} {return} + + set where $n + set current intro + } else { + # Not enough. Initialize value with the data we + # have (after the colon) and stop processing for + # now. + + set value [string range $input $where end] + set current data + set get $num + set input "" + return + } + } else { + return -code error "Syntax error in string length,\ + expected digit, or ':', got \"$ch\"" + } + incr where + } else { + # unknown state = internal error + return -code error "Unknown decoder state \"$current\", internal error" + } + } + + set input "" + return +} + +# ::bee::Command -- +# +# Internal helper. Runs the decoder command callback. +# +# Arguments: +# token The decoder invoking its callback +# how Which method to invoke (value, error, eof) +# args Arguments for the method. +# +# Results: +# A boolean flag. Set if further processing has to stop. + +proc ::bee::Command {token how args} { + variable $token + upvar 0 $token state + + #puts Report/$token/$how/$args/ + + set cmd $state(cmd) + set chan $state(chan) + + # We catch the fileevents because they will fail when this is + # called from the 'Close'. The channel will already be gone in + # that case. + + set stop 0 + if {($how eq "error") || ($how eq "eof")} { + variable bee + + set stop 1 + fileevent $chan readable {} + unset bee($chan) + unset state + + if {$how eq "eof"} { + #puts \tclosing/$chan + close $chan + } + } + + lappend cmd $how $token + foreach a $args {lappend cmd $a} + uplevel #0 $cmd + + if {![info exists state]} { + # The decoder token was killed by the callback, stop + # processing. + set stop 1 + } + + #puts /$stop/[file channels] + return $stop +} + +# ::bee::Complete -- +# +# Internal helper. Reports a completed value. +# +# Arguments: +# token The decoder reporting the value. +# value The value to report. +# +# Results: +# A boolean flag. Set if further processing has to stop. + +proc ::bee::Complete {token value} { + variable $token + upvar 0 $token state + upvar 0 state(pend) pend + + if {[llength $pend]} { + # The value is part of a container. Add the value to its end + # and keep processing. + + set pend [lreplace $pend end end \ + [linsert [lindex $pend end] end \ + $value]] + + # Don't stop. + return 0 + } + + # The value is at the top, report it. The callback determines if + # we keep processing. + + return [Command $token value $value] +} + +# ::bee::decodeCancel -- +# +# Destroys the decoder referenced by the token. +# +# Arguments: +# token The decoder to destroy. +# +# Results: +# None. + +proc ::bee::decodeCancel {token} { + variable bee + variable $token + upvar 0 $token state + unset bee($state(chan)) + unset state + return +} + +# ::bee::decodePush -- +# +# Push data into the decoder input buffer. +# +# Arguments: +# token The decoder to extend. +# string The characters to add. +# +# Results: +# None. + +proc ::bee::decodePush {token string} { + variable $token + upvar 0 $token state + append state(read) $string + return +} + + +package provide bee 0.1 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bee/pkgIndex.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bee/pkgIndex.tcl new file mode 100644 index 00000000..e95dedfc --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bee/pkgIndex.tcl @@ -0,0 +1,4 @@ +# Tcl package index file, version 1.1 + +if {![package vsatisfies [package provide Tcl] 8.4]} {return} +package ifneeded bee 0.1 [list source [file join $dir bee.tcl]] diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench.tcl new file mode 100644 index 00000000..461afbcf --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench.tcl @@ -0,0 +1,553 @@ +# bench.tcl -- +# +# Management of benchmarks. +# +# Copyright (c) 2005-2008 by Andreas Kupries +# library derived from runbench.tcl application (C) Jeff Hobbs. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: bench.tcl,v 1.14 2008/10/08 03:30:48 andreas_kupries Exp $ + +# ### ### ### ######### ######### ######### ########################### +## Requisites - Packages and namespace for the commands and data. + +package require Tcl 8.2 +package require logger +package require csv +package require struct::matrix +package require report + +namespace eval ::bench {} +namespace eval ::bench::out {} + +# @mdgen OWNER: libbench.tcl + +# ### ### ### ######### ######### ######### ########################### +## Public API - Benchmark execution + +# ::bench::run -- +# +# Run a series of benchmarks. +# +# Arguments: +# ... +# +# Results: +# Dictionary. + +proc ::bench::run {args} { + log::debug [linsert $args 0 ::bench::run] + + # -errors 0|1 default 1, propagate errors in benchmarks + # -threads default 0, no threads, #threads to use + # -match only run tests matching this pattern + # -rmatch only run tests matching this pattern + # -iters default 1000, max#iterations for any benchmark + # -pkgdir Defaults to nothing, regular bench invokation. + + # interps - dict (path -> version) + # files - list (of files) + + # Process arguments ...................................... + # Defaults first, then overides by the user + + set errors 1 ; # Propagate errors + set threads 0 ; # Do not use threads + set match {} ; # Do not exclude benchmarks based on glob pattern + set rmatch {} ; # Do not exclude benchmarks based on regex pattern + set iters 1000 ; # Limit #iterations for any benchmark + set pkgdirs {} ; # List of dirs to put in front of auto_path in the + # bench interpreters. Default: nothing. + + while {[string match "-*" [set opt [lindex $args 0]]]} { + set val [lindex $args 1] + switch -exact -- $opt { + -errors { + if {![string is boolean -strict $val]} { + return -code error "Expected boolean, got \"$val\"" + } + set errors $val + } + -threads { + if {![string is int -strict $val] || ($val < 0)} { + return -code error "Expected int >= 0, got \"$val\"" + } + set threads [lindex $args 1] + } + -match { + set match [lindex $args 1] + } + -rmatch { + set rmatch [lindex $args 1] + } + -iters { + if {![string is int -strict $val] || ($val <= 0)} { + return -code error "Expected int > 0, got \"$val\"" + } + set iters [lindex $args 1] + } + -pkgdir { + CheckPkgDirArg $val + lappend pkgdirs $val + } + default { + return -code error "Unknown option \"$opt\", should -errors, -threads, -match, -rmatch, or -iters" + } + } + set args [lrange $args 2 end] + } + if {[llength $args] != 2} { + return -code error "wrong\#args, should be: ?options? interp files" + } + foreach {interps files} $args break + + # Run the benchmarks ..................................... + + array set DATA {} + + if {![llength $pkgdirs]} { + # No user specified package directories => Simple run. + foreach {ip ver} $interps { + Invoke $ip $ver {} ;# DATA etc passed via upvar. + } + } else { + # User specified package directories. + foreach {ip ver} $interps { + foreach pkgdir $pkgdirs { + Invoke $ip $ver $pkgdir ;# DATA etc passed via upvar. + } + } + } + + # Benchmark data ... Structure, dict (key -> value) + # + # Key || Value + # ============ ++ ========================================= + # interp IP -> Version. Shell IP was used to run benchmarks. IP is + # the path to the shell. + # + # desc DESC -> "". DESC is description of an executed benchmark. + # + # usec DESC IP -> Result. Result of benchmark DESC when run by the + # shell IP. Usually time in microseconds, but can be + # a special code as well (ERR, BAD_RES). + # ============ ++ ========================================= + + return [array get DATA] +} + +# ::bench::locate -- +# +# Locate interpreters on the pathlist, based on a pattern. +# +# Arguments: +# ... +# +# Results: +# List of paths. + +proc ::bench::locate {pattern paths} { + # Cache of executables already found. + array set var {} + set res {} + + foreach path $paths { + foreach ip [glob -nocomplain [file join $path $pattern]] { + if {[package vsatisfies [package provide Tcl] 8.4]} { + set ip [file normalize $ip] + } + + # Follow soft-links to the actual executable. + while {[string equal link [file type $ip]]} { + set link [file readlink $ip] + if {[string match relative [file pathtype $link]]} { + set ip [file join [file dirname $ip] $link] + } else { + set ip $link + } + } + + if { + [file executable $ip] && ![info exists var($ip)] + } { + if {[catch {exec $ip << "exit"} dummy]} { + log::debug "$ip: $dummy" + continue + } + set var($ip) . + lappend res $ip + } + } + } + + return $res +} + +# ::bench::versions -- +# +# Take list of interpreters, find their versions. +# Removes all interps for which it cannot do so. +# +# Arguments: +# List of interpreters (paths) +# +# Results: +# dictionary: interpreter -> version. + +proc ::bench::versions {interps} { + set res {} + foreach ip $interps { + if {[catch { + exec $ip << {puts [info patchlevel] ; exit} + } patchlevel]} { + log::debug "$ip: $patchlevel" + continue + } + + lappend res [list $patchlevel $ip] + } + + # -uniq 8.4-ism, replaced with use of array. + array set tmp {} + set resx {} + foreach item [lsort -dictionary -decreasing -index 0 $res] { + foreach {p ip} $item break + if {[info exists tmp($p)]} continue + set tmp($p) . + lappend resx $ip $p + } + + return $resx +} + +# ::bench::merge -- +# +# Take the data of several benchmark runs and merge them into +# one data set. +# +# Arguments: +# One or more data sets to merge +# +# Results: +# The merged data set. + +proc ::bench::merge {args} { + if {[llength $args] == 1} { + return [lindex $args 0] + } + + array set DATA {} + foreach data $args { + array set DATA $data + } + return [array get DATA] +} + +# ::bench::norm -- +# +# Normalize the time data in the dataset, using one of the +# columns as reference. +# +# Arguments: +# Data to normalize +# Index of reference column +# +# Results: +# The normalized data set. + +proc ::bench::norm {data col} { + + if {![string is integer -strict $col]} { + return -code error "Ref.column: Expected integer, but got \"$col\"" + } + if {$col < 1} { + return -code error "Ref.column out of bounds" + } + + array set DATA $data + set ipkeys [array names DATA interp*] + + if {$col > [llength $ipkeys]} { + return -code error "Ref.column out of bounds" + } + incr col -1 + set refip [lindex [lindex [lsort -dict $ipkeys] $col] 1] + + foreach key [array names DATA] { + if {[string match "desc*" $key]} continue + if {[string match "interp*" $key]} continue + + foreach {_ desc ip} $key break + if {[string equal $ip $refip]} continue + + set v $DATA($key) + if {![string is double -strict $v]} continue + + if {![info exists DATA([list usec $desc $refip])]} { + # We cannot normalize, we do not keep the time value. + # The row will be shown, empty. + set DATA($key) "" + continue + } + set vref $DATA([list usec $desc $refip]) + + if {![string is double -strict $vref]} continue + + set DATA($key) [expr {$v/double($vref)}] + } + + foreach key [array names DATA [list * $refip]] { + if {![string is double -strict $DATA($key)]} continue + set DATA($key) 1 + } + + return [array get DATA] +} + +# ::bench::edit -- +# +# Change the 'path' of an interp to a user-defined value. +# +# Arguments: +# Data to edit +# Index of column to change +# The value replacing the current path +# +# Results: +# The changed data set. + +proc ::bench::edit {data col new} { + + if {![string is integer -strict $col]} { + return -code error "Ref.column: Expected integer, but got \"$col\"" + } + if {$col < 1} { + return -code error "Ref.column out of bounds" + } + + array set DATA $data + set ipkeys [array names DATA interp*] + + if {$col > [llength $ipkeys]} { + return -code error "Ref.column out of bounds" + } + incr col -1 + set refip [lindex [lindex [lsort -dict $ipkeys] $col] 1] + + if {[string equal $new $refip]} { + # No change, quick return + return $data + } + + set refkey [list interp $refip] + set DATA([list interp $new]) $DATA($refkey) + unset DATA($refkey) + + foreach key [array names DATA [list * $refip]] { + if {![string equal [lindex $key 0] "usec"]} continue + foreach {__ desc ip} $key break + set DATA([list usec $desc $new]) $DATA($key) + unset DATA($key) + } + + return [array get DATA] +} + +# ::bench::del -- +# +# Remove the data for an interp. +# +# Arguments: +# Data to edit +# Index of column to remove +# +# Results: +# The changed data set. + +proc ::bench::del {data col} { + + if {![string is integer -strict $col]} { + return -code error "Ref.column: Expected integer, but got \"$col\"" + } + if {$col < 1} { + return -code error "Ref.column out of bounds" + } + + array set DATA $data + set ipkeys [array names DATA interp*] + + if {$col > [llength $ipkeys]} { + return -code error "Ref.column out of bounds" + } + incr col -1 + set refip [lindex [lindex [lsort -dict $ipkeys] $col] 1] + + unset DATA([list interp $refip]) + + # Do not use 'array unset'. Keep 8.2 clean. + foreach key [array names DATA [list * $refip]] { + if {![string equal [lindex $key 0] "usec"]} continue + unset DATA($key) + } + + return [array get DATA] +} + +# ### ### ### ######### ######### ######### ########################### +## Public API - Result formatting. + +# ::bench::out::raw -- +# +# Format the result of a benchmark run. +# Style: Raw data. +# +# Arguments: +# DATA dict +# +# Results: +# String containing the formatted DATA. + +proc ::bench::out::raw {data} { + return $data +} + +# ### ### ### ######### ######### ######### ########################### +## Internal commands + +proc ::bench::CheckPkgDirArg {path {expected {}}} { + # Allow empty string, special. + if {![string length $path]} return + + if {![file isdirectory $path]} { + return -code error \ + "The path \"$path\" is not a directory." + } + if {![file readable $path]} { + return -code error \ + "The path \"$path\" is not readable." + } +} + +proc ::bench::Invoke {ip ver pkgdir} { + variable self + # Import remainder of the current configuration/settings. + + upvar 1 DATA DATA match match rmatch rmatch \ + iters iters errors errors threads threads \ + files files + + if {[string length $pkgdir]} { + log::info "Benchmark $ver ($pkgdir) $ip" + set idstr "$ip ($pkgdir)" + } else { + log::info "Benchmark $ver $ip" + set idstr $ip + } + + set DATA([list interp $idstr]) $ver + + set cmd [list $ip [file join $self libbench.tcl] \ + -match $match \ + -rmatch $rmatch \ + -iters $iters \ + -interp $ip \ + -errors $errors \ + -threads $threads \ + -pkgdir $pkgdir \ + ] + + # Determine elapsed time per file, logged. + set start [clock seconds] + + array set tmp {} + + if {$threads} { + foreach f $files { lappend cmd $f } + if {[catch { + close [Process [open |$cmd r+]] + } output]} { + if {$errors} { + error $::errorInfo + } + } + } else { + foreach file $files { + log::info [file tail $file] + if {[catch { + close [Process [open |[linsert $cmd end $file] r+]] + } output]} { + if {$errors} { + error $::errorInfo + } else { + continue + } + } + } + } + + foreach desc [array names tmp] { + set DATA([list desc $desc]) {} + set DATA([list usec $desc $idstr]) $tmp($desc) + } + + unset tmp + set elapsed [expr {[clock seconds] - $start}] + + set hour [expr {$elapsed / 3600}] + set min [expr {$elapsed / 60}] + set sec [expr {$elapsed % 60}] + log::info " [format %.2d:%.2d:%.2d $hour $min $sec] elapsed" + return +} + + +proc ::bench::Process {pipe} { + while {1} { + if {[eof $pipe]} break + if {[gets $pipe line] < 0} break + # AK: FUTURE: Log all lines?! + #puts |$line| + set line [string trim $line] + if {[string equal $line ""]} continue + + Result + Feedback + # Unknown lines are printed. Future: Callback?! + log::info $line + } + return $pipe +} + +proc ::bench::Result {} { + upvar 1 line line + if {[lindex $line 0] ne "RESULT"} return + upvar 2 tmp tmp + foreach {_ desc result} $line break + set tmp($desc) $result + return -code continue +} + +proc ::bench::Feedback {} { + upvar 1 line line + if {[lindex $line 0] ne "LOG"} return + # AK: Future - Run through callback?! + log::info [lindex $line 1] + return -code continue +} + +# ### ### ### ######### ######### ######### ########################### +## Initialize internal data structures. + +namespace eval ::bench { + variable self [file join [pwd] [file dirname [info script]]] + + logger::init bench + logger::import -force -all -namespace log bench +} + +# ### ### ### ######### ######### ######### ########################### +## Ready to run + +package provide bench 0.4 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_read.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_read.tcl new file mode 100644 index 00000000..7cebb7bd --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_read.tcl @@ -0,0 +1,162 @@ +# bench_read.tcl -- +# +# Management of benchmarks, reading results in various formats. +# +# Copyright (c) 2005 by Andreas Kupries +# library derived from runbench.tcl application (C) Jeff Hobbs. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: bench_read.tcl,v 1.3 2006/06/13 23:20:30 andreas_kupries Exp $ + +# ### ### ### ######### ######### ######### ########################### +## Requisites - Packages and namespace for the commands and data. + +package require Tcl 8.2 +package require csv + +namespace eval ::bench::in {} + +# ### ### ### ######### ######### ######### ########################### +## Public API - Result reading + +# ::bench::in::read -- +# +# Read a bench result in any of the raw/csv/text formats +# +# Arguments: +# path to file to read +# +# Results: +# DATA dictionary, internal representation of the bench results. + +proc ::bench::in::read {file} { + + set f [open $file r] + set head [gets $f] + + if {![string match "# -\\*- tcl -\\*- bench/*" $head]} { + return -code error "Bad file format, not a benchmark file" + } else { + regexp {bench/(.*)$} $head -> format + + switch -exact -- $format { + raw - csv - text { + set res [RD$format $f] + } + default { + return -code error "Bad format \"$val\", expected text, csv, or raw" + } + } + } + close $f + return $res +} + +# ### ### ### ######### ######### ######### ########################### +## Internal commands + +proc ::bench::in::RDraw {chan} { + return [string trimright [::read $chan]] +} + +proc ::bench::in::RDcsv {chan} { + # Lines Format + # First line is number of interpreters #n. int + # Next to 1+n is interpreter data. id,ver,path + # Beyond is benchmark results. id,desc,res1,...,res#n + + array set DATA {} + + # #Interp ... + + set nip [lindex [csv::split [gets $chan]] 0] + + # Interp data ... + + set iplist {} + for {set i 0} {$i < $nip} {incr i} { + foreach {__ ver ip} [csv::split [gets $chan]] break + + set DATA([list interp $ip]) $ver + lappend iplist $ip + } + + # Benchmark data ... + + while {[gets $chan line] >= 0} { + set line [string trim $line] + if {$line == {}} break + set line [csv::split $line] + set desc [lindex $line 1] + + set DATA([list desc $desc]) {} + foreach val [lrange $line 2 end] ip $iplist { + if {$val == {}} continue + set DATA([list usec $desc $ip]) $val + } + } + + return [array get DATA] +} + +proc ::bench::in::RDtext {chan} { + array set DATA {} + + # Interp data ... + + # Empty line - ignore + # "id: ver path" - interp data. + # Empty line - separator before benchmark data. + + set n 0 + set iplist {} + while {[gets $chan line] >= 0} { + set line [string trim $line] + if {$line == {}} { + incr n + if {$n == 2} break + continue + } + + regexp {[^:]+: ([^ ]+) (.*)$} $line -> ver ip + set DATA([list interp $ip]) $ver + lappend iplist $ip + } + + # Benchmark data ... + + # '---' -> Ignore. + # '|' column separators. Remove spaces around it. Then treat line + # as CSV data with a particular separator. + # Ignore the INTERP line. + + while {[gets $chan line] >= 0} { + set line [string trim $line] + if {$line == {}} continue + if {[string match "+---*" $line]} continue + if {[string match "*INTERP*" $line]} continue + + regsub -all "\\| +" $line {|} line + regsub -all " +\\|" $line {|} line + set line [csv::split [string trim $line |] |] + set desc [lindex $line 1] + + set DATA([list desc $desc]) {} + foreach val [lrange $line 2 end] ip $iplist { + if {$val == {}} continue + set DATA([list usec $desc $ip]) $val + } + } + + return [array get DATA] +} + +# ### ### ### ######### ######### ######### ########################### +## Initialize internal data structures. + +# ### ### ### ######### ######### ######### ########################### +## Ready to run + +package provide bench::in 0.1 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_wcsv.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_wcsv.tcl new file mode 100644 index 00000000..cb3d4c59 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_wcsv.tcl @@ -0,0 +1,101 @@ +# bench_wtext.tcl -- +# +# Management of benchmarks, formatted text. +# +# Copyright (c) 2005 by Andreas Kupries +# library derived from runbench.tcl application (C) Jeff Hobbs. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: bench_wcsv.tcl,v 1.4 2007/01/21 23:29:06 andreas_kupries Exp $ + +# ### ### ### ######### ######### ######### ########################### +## Requisites - Packages and namespace for the commands and data. + +package require Tcl 8.2 +package require csv + +namespace eval ::bench::out {} + +# ### ### ### ######### ######### ######### ########################### +## Public API - Benchmark execution + +# ### ### ### ######### ######### ######### ########################### +## Public API - Result formatting. + +# ::bench::out::csv -- +# +# Format the result of a benchmark run. +# Style: CSV +# +# Arguments: +# DATA dict +# +# Results: +# String containing the formatted DATA. + +proc ::bench::out::csv {data} { + array set DATA $data + set CSV {} + + # 1st record: #shells + # 2nd record to #shells+1: Interpreter data (id, version, path) + # #shells+2 to end: Benchmark data (id,desc,result1,...,result#shells) + + # --- --- ---- + # #interpreters used + + set ipkeys [array names DATA interp*] + lappend CSV [csv::join [list [llength $ipkeys]]] + + # --- --- ---- + # Table 1: Interpreter information. + + set n 1 + set iplist {} + foreach key [lsort -dict $ipkeys] { + set ip [lindex $key 1] + lappend CSV [csv::join [list $n $DATA($key) $ip]] + set DATA($key) $n + incr n + lappend iplist $ip + } + + # --- --- ---- + # Table 2: Benchmark information + + set dlist {} + foreach key [lsort -dict -index 1 [array names DATA desc*]] { + lappend dlist [lindex $key 1] + } + + set n 1 + foreach desc $dlist { + set record {} + lappend record $n + lappend record $desc + foreach ip $iplist { + if {[catch { + lappend record $DATA([list usec $desc $ip]) + }]} { + lappend record {} + } + } + lappend CSV [csv::join $record] + incr n + } + + return [join $CSV \n] +} + +# ### ### ### ######### ######### ######### ########################### +## Internal commands + +# ### ### ### ######### ######### ######### ########################### +## Initialize internal data structures. + +# ### ### ### ######### ######### ######### ########################### +## Ready to run + +package provide bench::out::csv 0.1.2 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_wtext.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_wtext.tcl new file mode 100644 index 00000000..aaa4100a --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/bench_wtext.tcl @@ -0,0 +1,165 @@ +# bench_wtext.tcl -- +# +# Management of benchmarks, formatted text. +# +# Copyright (c) 2005 by Andreas Kupries +# library derived from runbench.tcl application (C) Jeff Hobbs. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: bench_wtext.tcl,v 1.4 2007/01/21 23:29:06 andreas_kupries Exp $ + +# ### ### ### ######### ######### ######### ########################### +## Requisites - Packages and namespace for the commands and data. + +package require Tcl 8.2 +package require struct::matrix +package require report + +namespace eval ::bench::out {} + +# ### ### ### ######### ######### ######### ########################### +## Public API - Result formatting. + +# ::bench::out::text -- +# +# Format the result of a benchmark run. +# Style: TEXT +# +# General structure like CSV, but nicely formatted and aligned +# columns. +# +# Arguments: +# DATA dict +# +# Results: +# String containing the formatted DATA. + +proc ::bench::out::text {data} { + array set DATA $data + set LINES {} + + # 1st line to #shells: Interpreter data (id, version, path) + # #shells+1 to end: Benchmark data (id,desc,result1,...,result#shells) + + lappend LINES {} + + # --- --- ---- + # Table 1: Interpreter information. + + set ipkeys [array names DATA interp*] + set n 1 + set iplist {} + set vlen 0 + foreach key [lsort -dict $ipkeys] { + lappend iplist [lindex $key 1] + incr n + set l [string length $DATA($key)] + if {$l > $vlen} {set vlen $l} + } + set idlen [string length $n] + + set dlist {} + set n 1 + foreach key [lsort -dict -index 1 [array names DATA desc*]] { + lappend dlist [lindex $key 1] + incr n + } + set didlen [string length $n] + + set n 1 + set record [list "" INTERP] + foreach ip $iplist { + set v $DATA([list interp $ip]) + lappend LINES " [PADL $idlen $n]: [PADR $vlen $v] $ip" + lappend record $n + incr n + } + + lappend LINES {} + + # --- --- ---- + # Table 2: Benchmark information + + set m [struct::matrix m] + $m add columns [expr {2 + [llength $iplist]}] + $m add row $record + + set n 1 + foreach desc $dlist { + set record [list $n] + lappend record $desc + + foreach ip $iplist { + if {[catch { + set val $DATA([list usec $desc $ip]) + }]} { + set val {} + } + if {[string is double -strict $val]} { + lappend record [format %.2f $val] + } else { + lappend record [format %s $val] + } + } + $m add row $record + incr n + } + + ::report::defstyle simpletable {} { + data set [split "[string repeat "| " [columns]]|"] + top set [split "[string repeat "+ - " [columns]]+"] + bottom set [top get] + top enable + bottom enable + + set c [columns] + justify 0 right + pad 0 both + + if {$c > 1} { + justify 1 left + pad 1 both + } + for {set i 2} {$i < $c} {incr i} { + justify $i right + pad $i both + } + } + ::report::defstyle captionedtable {{n 1}} { + simpletable + topdata set [data get] + topcapsep set [top get] + topcapsep enable + tcaption $n + } + + set r [report::report r [$m columns] style captionedtable] + lappend LINES [$m format 2string $r] + $m destroy + $r destroy + + return [join $LINES \n] +} + +# ### ### ### ######### ######### ######### ########################### +## Internal commands + +proc ::bench::out::PADL {max str} { + format "%${max}s" $str + #return "[PAD $max $str]$str" +} + +proc ::bench::out::PADR {max str} { + format "%-${max}s" $str + #return "$str[PAD $max $str]" +} + +# ### ### ### ######### ######### ######### ########################### +## Initialize internal data structures. + +# ### ### ### ######### ######### ######### ########################### +## Ready to run + +package provide bench::out::text 0.1.2 diff --git a/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/libbench.tcl b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/libbench.tcl new file mode 100644 index 00000000..ebf9f716 --- /dev/null +++ b/src/vfs/punk86.vfs/lib_tcl8/tcllib1.21/bench/libbench.tcl @@ -0,0 +1,561 @@ +# -*- tcl -*- +# libbench.tcl ?(