📄 genstubs.tcl
字号:
# genStubs.tcl --## This script generates a set of stub files for a given# interface. # ## Copyright (c) 1998-1999 by Scriptics Corporation.# See the file "license.terms" for information on usage and redistribution# of this file, and for a DISCLAIMER OF ALL WARRANTIES.# # RCS: @(#) $Id: genStubs.tcl,v 1.13 2002/10/04 08:25:14 dkf Exp $package require Tcl 8namespace eval genStubs { # libraryName -- # # The name of the entire library. This value is used to compute # the USE_*_STUB_PROCS macro and the name of the init file. variable libraryName "UNKNOWN" # interfaces -- # # An array indexed by interface name that is used to maintain # the set of valid interfaces. The value is empty. array set interfaces {} # curName -- # # The name of the interface currently being defined. variable curName "UNKNOWN" # hooks -- # # An array indexed by interface name that contains the set of # subinterfaces that should be defined for a given interface. array set hooks {} # stubs -- # # This three dimensional array is indexed first by interface name, # second by platform name, and third by a numeric offset or the # constant "lastNum". The lastNum entry contains the largest # numeric offset used for a given interface/platform combo. Each # numeric offset contains the C function specification that # should be used for the given entry in the stub table. The spec # consists of a list in the form returned by parseDecl. array set stubs {} # outDir -- # # The directory where the generated files should be placed. variable outDir .}# genStubs::library --## This function is used in the declarations file to set the name# of the library that the interfaces are associated with (e.g. "tcl").# This value will be used to define the inline conditional macro.## Arguments:# name The library name.## Results:# None.proc genStubs::library {name} { variable libraryName $name}# genStubs::interface --## This function is used in the declarations file to set the name# of the interface currently being defined.## Arguments:# name The name of the interface.## Results:# None.proc genStubs::interface {name} { variable curName $name variable interfaces set interfaces($name) {} return}# genStubs::hooks --## This function defines the subinterface hooks for the current# interface.## Arguments:# names The ordered list of interfaces that are reachable through the# hook vector.## Results:# None.proc genStubs::hooks {names} { variable curName variable hooks set hooks($curName) $names return}# genStubs::declare --## This function is used in the declarations file to declare a new# interface entry.## Arguments:# index The index number of the interface.# platform The platform the interface belongs to. Should be one# of generic, win, unix, or mac, or macosx or aqua or x11.# decl The C function declaration, or {} for an undefined# entry.## Results:# None.proc genStubs::declare {args} { variable stubs variable curName if {[llength $args] != 3} { puts stderr "wrong # args: declare $args" } lassign $args index platformList decl # Check for duplicate declarations, then add the declaration and # bump the lastNum counter if necessary. foreach platform $platformList { if {[info exists stubs($curName,$platform,$index)]} { puts stderr "Duplicate entry: declare $args" } } regsub -all "\[ \t\n\]+" [string trim $decl] " " decl set decl [parseDecl $decl] foreach platform $platformList { if {$decl != ""} { set stubs($curName,$platform,$index) $decl if {![info exists stubs($curName,$platform,lastNum)] \ || ($index > $stubs($curName,$platform,lastNum))} { set stubs($curName,$platform,lastNum) $index } } } return}# genStubs::rewriteFile --## This function replaces the machine generated portion of the# specified file with new contents. It looks for the !BEGIN! and# !END! comments to determine where to place the new text.## Arguments:# file The name of the file to modify.# text The new text to place in the file.## Results:# None.proc genStubs::rewriteFile {file text} { if {![file exists $file]} { puts stderr "Cannot find file: $file" return } set in [open ${file} r] set out [open ${file}.new w] while {![eof $in]} { set line [gets $in] if {[regexp {!BEGIN!} $line]} { break } puts $out $line } puts $out "/* !BEGIN!: Do not edit below this line. */" puts $out $text while {![eof $in]} { set line [gets $in] if {[regexp {!END!} $line]} { break } } puts $out "/* !END!: Do not edit above this line. */" puts -nonewline $out [read $in] close $in close $out file rename -force ${file}.new ${file} return}# genStubs::addPlatformGuard --## Wrap a string inside a platform #ifdef.## Arguments:# plat Platform to test.## Results:# Returns the original text inside an appropriate #ifdef.proc genStubs::addPlatformGuard {plat text} { switch $plat { win { return "#ifdef __WIN32__\n${text}#endif /* __WIN32__ */\n" } unix { return "#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */\n${text}#endif /* UNIX */\n" } mac { return "#ifdef MAC_TCL\n${text}#endif /* MAC_TCL */\n" } macosx { return "#ifdef MAC_OSX_TCL\n${text}#endif /* MAC_OSX_TCL */\n" } aqua { return "#ifdef MAC_OSX_TK\n${text}#endif /* MAC_OSX_TK */\n" } x11 { return "#if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK)) /* X11 */\n${text}#endif /* X11 */\n" } } return "$text"}# genStubs::emitSlots --## Generate the stub table slots for the given interface. If there# are no generic slots, then one table is generated for each# platform, otherwise one table is generated for all platforms.## Arguments:# name The name of the interface being emitted.# textVar The variable to use for output.## Results:# None.proc genStubs::emitSlots {name textVar} { variable stubs upvar $textVar text forAllStubs $name makeSlot 1 text {" void *reserved$i;\n"} return}# genStubs::parseDecl --## Parse a C function declaration into its component parts.## Arguments:# decl The function declaration.## Results:# Returns a list of the form {returnType name args}. The args# element consists of a list of type/name pairs, or a single# element "void". If the function declaration is malformed# then an error is displayed and the return value is {}.proc genStubs::parseDecl {decl} { if {![regexp {^(.*)\((.*)\)$} $decl all prefix args]} { puts stderr "Malformed declaration: $decl" return } set prefix [string trim $prefix] if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} { puts stderr "Bad return type: $decl" return } set rtype [string trim $rtype] foreach arg [split $args ,] { lappend argList [string trim $arg] } if {![string compare [lindex $argList end] "..."]} { if {[llength $argList] != 2} { puts stderr "Only one argument is allowed in varargs form: $decl" } set arg [parseArg [lindex $argList 0]] if {$arg == "" || ([llength $arg] != 2)} { puts stderr "Bad argument: '[lindex $argList 0]' in '$decl'" return } set args [list TCL_VARARGS $arg] } else { set args {} foreach arg $argList { set argInfo [parseArg $arg] if {![string compare $argInfo "void"]} { lappend args "void" break } elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} { lappend args $argInfo } else { puts stderr "Bad argument: '$arg' in '$decl'" return } } } return [list $rtype $fname $args]}# genStubs::parseArg --## This function parses a function argument into a type and name.## Arguments:# arg The argument to parse.## Results:# Returns a list of type and name with an optional third array# indicator. If the argument is malformed, returns "".proc genStubs::parseArg {arg} { if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} { if {$arg == "void"} { return $arg } else { return } } set result [list [string trim $type] $name] if {$array != ""} { lappend result $array } return $result}# genStubs::makeDecl --## Generate the prototype for a function.## Arguments:# name The interface name.# decl The function declaration.# index The slot index for this function.## Results:# Returns the formatted declaration string.proc genStubs::makeDecl {name decl index} { lassign $decl rtype fname args append text "/* $index */\n" set line "EXTERN $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 } append line "$fname _ANSI_ARGS_(" set arg1 [lindex $args 0] switch -exact $arg1 { void { append line "(void)" } TCL_VARARGS { set arg [lindex $args 1] append line "TCL_VARARGS([lindex $arg 0],[lindex $arg 1])" } default { set sep "(" foreach arg $args { append line $sep set next {} append next [lindex $arg 0] " " [lindex $arg 1] \ [lindex $arg 2] if {[string length $line] + [string length $next] \ + $pad > 76} { append text $line \n set line "\t\t\t\t" set pad 28 } append line $next set sep ", " } append line ")" } } append text $line append text ");\n" return $text}# genStubs::makeMacro --## Generate the inline macro for a function.## Arguments:# name The interface name.# decl The function declaration.# index The slot index for this function.## Results:# Returns the formatted macro definition.proc genStubs::makeMacro {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text "#ifndef $fname\n#define $fname" set arg1 [lindex $args 0] set argList "" switch -exact $arg1 { void { set argList "()" } TCL_VARARGS { } default { set sep "(" foreach arg $args { append argList $sep [lindex $arg 1] set sep ", " } append argList ")" } } append text " \\\n\t(${name}StubsPtr->$lfname)" append text " /* $index */\n#endif\n" return $text}# genStubs::makeStub --## Emits a stub function definition.## Arguments:# name The interface name.# decl The function declaration.# index The slot index for this function.## Results:# Returns the formatted stub function definition.proc genStubs::makeStub {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] append text "/* Slot $index */\n" $rtype "\n" $fname set arg1 [lindex $args 0] if {![string compare $arg1 "TCL_VARARGS"]} { lassign [lindex $args 1] type argName append text " TCL_VARARGS_DEF($type,$argName)\n\{\n" append text " " $type " var;\n va_list argList;\n" if {[string compare $rtype "void"]} { append text " " $rtype " resultValue;\n" } append text "\n var = (" $type ") TCL_VARARGS_START(" \ $type "," $argName ",argList);\n\n " if {[string compare $rtype "void"]} { append text "resultValue = " } append text "(" $name "StubsPtr->" $lfname "VA)(var, argList);\n" append text " va_end(argList);\n" if {[string compare $rtype "void"]} { append text "return resultValue;\n" } append text "\}\n\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -