genStubs.tcl
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:24k
源码类别:

通讯编程

开发平台:

Visual C++

  1. # genStubs.tcl --
  2. #
  3. # This script generates a set of stub files for a given
  4. # interface.  
  5. #
  6. #
  7. # Copyright (c) 1998-1999 by Scriptics Corporation.
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. # RCS: @(#) $Id: genStubs.tcl,v 1.13 2002/10/04 08:25:14 dkf Exp $
  11. package require Tcl 8
  12. namespace eval genStubs {
  13.     # libraryName --
  14.     #
  15.     # The name of the entire library.  This value is used to compute
  16.     # the USE_*_STUB_PROCS macro and the name of the init file.
  17.     variable libraryName "UNKNOWN"
  18.     # interfaces --
  19.     #
  20.     # An array indexed by interface name that is used to maintain
  21.     #   the set of valid interfaces.  The value is empty.
  22.     array set interfaces {}
  23.     # curName --
  24.     #
  25.     # The name of the interface currently being defined.
  26.     variable curName "UNKNOWN"
  27.     # hooks --
  28.     #
  29.     # An array indexed by interface name that contains the set of
  30.     # subinterfaces that should be defined for a given interface.
  31.     array set hooks {}
  32.     # stubs --
  33.     #
  34.     # This three dimensional array is indexed first by interface name,
  35.     # second by platform name, and third by a numeric offset or the
  36.     # constant "lastNum".  The lastNum entry contains the largest
  37.     # numeric offset used for a given interface/platform combo.  Each
  38.     # numeric offset contains the C function specification that
  39.     # should be used for the given entry in the stub table.  The spec
  40.     # consists of a list in the form returned by parseDecl.
  41.     array set stubs {}
  42.     # outDir --
  43.     #
  44.     # The directory where the generated files should be placed.
  45.     variable outDir .
  46. }
  47. # genStubs::library --
  48. #
  49. # This function is used in the declarations file to set the name
  50. # of the library that the interfaces are associated with (e.g. "tcl").
  51. # This value will be used to define the inline conditional macro.
  52. #
  53. # Arguments:
  54. # name The library name.
  55. #
  56. # Results:
  57. # None.
  58. proc genStubs::library {name} {
  59.     variable libraryName $name
  60. }
  61. # genStubs::interface --
  62. #
  63. # This function is used in the declarations file to set the name
  64. # of the interface currently being defined.
  65. #
  66. # Arguments:
  67. # name The name of the interface.
  68. #
  69. # Results:
  70. # None.
  71. proc genStubs::interface {name} {
  72.     variable curName $name
  73.     variable interfaces
  74.     set interfaces($name) {}
  75.     return
  76. }
  77. # genStubs::hooks --
  78. #
  79. # This function defines the subinterface hooks for the current
  80. # interface.
  81. #
  82. # Arguments:
  83. # names The ordered list of interfaces that are reachable through the
  84. # hook vector.
  85. #
  86. # Results:
  87. # None.
  88. proc genStubs::hooks {names} {
  89.     variable curName
  90.     variable hooks
  91.     set hooks($curName) $names
  92.     return
  93. }
  94. # genStubs::declare --
  95. #
  96. # This function is used in the declarations file to declare a new
  97. # interface entry.
  98. #
  99. # Arguments:
  100. # index The index number of the interface.
  101. # platform The platform the interface belongs to.  Should be one
  102. # of generic, win, unix, or mac, or macosx or aqua or x11.
  103. # decl The C function declaration, or {} for an undefined
  104. # entry.
  105. #
  106. # Results:
  107. # None.
  108. proc genStubs::declare {args} {
  109.     variable stubs
  110.     variable curName
  111.     if {[llength $args] != 3} {
  112. puts stderr "wrong # args: declare $args"
  113.     }
  114.     lassign $args index platformList decl
  115.     # Check for duplicate declarations, then add the declaration and
  116.     # bump the lastNum counter if necessary.
  117.     foreach platform $platformList {
  118. if {[info exists stubs($curName,$platform,$index)]} {
  119.     puts stderr "Duplicate entry: declare $args"
  120. }
  121.     }
  122.     regsub -all "[ tn]+" [string trim $decl] " " decl
  123.     set decl [parseDecl $decl]
  124.     foreach platform $platformList {
  125. if {$decl != ""} {
  126.     set stubs($curName,$platform,$index) $decl
  127.     if {![info exists stubs($curName,$platform,lastNum)] 
  128.     || ($index > $stubs($curName,$platform,lastNum))} {
  129. set stubs($curName,$platform,lastNum) $index
  130.     }
  131. }
  132.     }
  133.     return
  134. }
  135. # genStubs::rewriteFile --
  136. #
  137. # This function replaces the machine generated portion of the
  138. # specified file with new contents.  It looks for the !BEGIN! and
  139. # !END! comments to determine where to place the new text.
  140. #
  141. # Arguments:
  142. # file The name of the file to modify.
  143. # text The new text to place in the file.
  144. #
  145. # Results:
  146. # None.
  147. proc genStubs::rewriteFile {file text} {
  148.     if {![file exists $file]} {
  149. puts stderr "Cannot find file: $file"
  150. return
  151.     }
  152.     set in [open ${file} r]
  153.     set out [open ${file}.new w]
  154.     while {![eof $in]} {
  155. set line [gets $in]
  156. if {[regexp {!BEGIN!} $line]} {
  157.     break
  158. }
  159. puts $out $line
  160.     }
  161.     puts $out "/* !BEGIN!: Do not edit below this line. */"
  162.     puts $out $text
  163.     while {![eof $in]} {
  164. set line [gets $in]
  165. if {[regexp {!END!} $line]} {
  166.     break
  167. }
  168.     }
  169.     puts $out "/* !END!: Do not edit above this line. */"
  170.     puts -nonewline $out [read $in]
  171.     close $in
  172.     close $out
  173.     file rename -force ${file}.new ${file}
  174.     return
  175. }
  176. # genStubs::addPlatformGuard --
  177. #
  178. # Wrap a string inside a platform #ifdef.
  179. #
  180. # Arguments:
  181. # plat Platform to test.
  182. #
  183. # Results:
  184. # Returns the original text inside an appropriate #ifdef.
  185. proc genStubs::addPlatformGuard {plat text} {
  186.     switch $plat {
  187. win {
  188.     return "#ifdef __WIN32__n${text}#endif /* __WIN32__ */n"
  189. }
  190. unix {
  191.     return "#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */n${text}#endif /* UNIX */n"
  192. }     
  193. mac {
  194.     return "#ifdef MAC_TCLn${text}#endif /* MAC_TCL */n"
  195. }
  196. macosx {
  197.     return "#ifdef MAC_OSX_TCLn${text}#endif /* MAC_OSX_TCL */n"
  198. }
  199. aqua {
  200.     return "#ifdef MAC_OSX_TKn${text}#endif /* MAC_OSX_TK */n"
  201. }
  202. x11 {
  203.     return "#if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK)) /* X11 */n${text}#endif /* X11 */n"
  204. }
  205.     }
  206.     return "$text"
  207. }
  208. # genStubs::emitSlots --
  209. #
  210. # Generate the stub table slots for the given interface.  If there
  211. # are no generic slots, then one table is generated for each
  212. # platform, otherwise one table is generated for all platforms.
  213. #
  214. # Arguments:
  215. # name The name of the interface being emitted.
  216. # textVar The variable to use for output.
  217. #
  218. # Results:
  219. # None.
  220. proc genStubs::emitSlots {name textVar} {
  221.     variable stubs
  222.     upvar $textVar text
  223.     forAllStubs $name makeSlot 1 text {"    void *reserved$i;n"}
  224.     return
  225. }
  226. # genStubs::parseDecl --
  227. #
  228. # Parse a C function declaration into its component parts.
  229. #
  230. # Arguments:
  231. # decl The function declaration.
  232. #
  233. # Results:
  234. # Returns a list of the form {returnType name args}.  The args
  235. # element consists of a list of type/name pairs, or a single
  236. # element "void".  If the function declaration is malformed
  237. # then an error is displayed and the return value is {}.
  238. proc genStubs::parseDecl {decl} {
  239.     if {![regexp {^(.*)((.*))$} $decl all prefix args]} {
  240. puts stderr "Malformed declaration: $decl"
  241. return
  242.     }
  243.     set prefix [string trim $prefix]
  244.     if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} {
  245. puts stderr "Bad return type: $decl"
  246. return
  247.     }
  248.     set rtype [string trim $rtype]
  249.     foreach arg [split $args ,] {
  250. lappend argList [string trim $arg]
  251.     }
  252.     if {![string compare [lindex $argList end] "..."]} {
  253. if {[llength $argList] != 2} {
  254.     puts stderr "Only one argument is allowed in varargs form: $decl"
  255. }
  256. set arg [parseArg [lindex $argList 0]]
  257. if {$arg == "" || ([llength $arg] != 2)} {
  258.     puts stderr "Bad argument: '[lindex $argList 0]' in '$decl'"
  259.     return
  260. }
  261. set args [list TCL_VARARGS $arg]
  262.     } else {
  263. set args {}
  264. foreach arg $argList {
  265.     set argInfo [parseArg $arg]
  266.     if {![string compare $argInfo "void"]} {
  267. lappend args "void"
  268. break
  269.     } elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} {
  270. lappend args $argInfo
  271.     } else {
  272. puts stderr "Bad argument: '$arg' in '$decl'"
  273. return
  274.     }
  275. }
  276.     }
  277.     return [list $rtype $fname $args]
  278. }
  279. # genStubs::parseArg --
  280. #
  281. # This function parses a function argument into a type and name.
  282. #
  283. # Arguments:
  284. # arg The argument to parse.
  285. #
  286. # Results:
  287. # Returns a list of type and name with an optional third array
  288. # indicator.  If the argument is malformed, returns "".
  289. proc genStubs::parseArg {arg} {
  290.     if {![regexp {^(.+[ ][*]*)([^][ *]+)([])?$} $arg all type name array]} {
  291. if {$arg == "void"} {
  292.     return $arg
  293. } else {
  294.     return
  295. }
  296.     }
  297.     set result [list [string trim $type] $name]
  298.     if {$array != ""} {
  299. lappend result $array
  300.     }
  301.     return $result
  302. }
  303. # genStubs::makeDecl --
  304. #
  305. # Generate the prototype for a function.
  306. #
  307. # Arguments:
  308. # name The interface name.
  309. # decl The function declaration.
  310. # index The slot index for this function.
  311. #
  312. # Results:
  313. # Returns the formatted declaration string.
  314. proc genStubs::makeDecl {name decl index} {
  315.     lassign $decl rtype fname args
  316.     append text "/* $index */n"
  317.     set line "EXTERN $rtype"
  318.     set count [expr {2 - ([string length $line] / 8)}]
  319.     append line [string range "ttt" 0 $count]
  320.     set pad [expr {24 - [string length $line]}]
  321.     if {$pad <= 0} {
  322. append line " "
  323. set pad 0
  324.     }
  325.     append line "$fname _ANSI_ARGS_("
  326.     set arg1 [lindex $args 0]
  327.     switch -exact $arg1 {
  328. void {
  329.     append line "(void)"
  330. }
  331. TCL_VARARGS {
  332.     set arg [lindex $args 1]
  333.     append line "TCL_VARARGS([lindex $arg 0],[lindex $arg 1])"
  334. }
  335. default {
  336.     set sep "("
  337.     foreach arg $args {
  338. append line $sep
  339. set next {}
  340. append next [lindex $arg 0] " " [lindex $arg 1] 
  341. [lindex $arg 2]
  342. if {[string length $line] + [string length $next] 
  343. + $pad > 76} {
  344.     append text $line n
  345.     set line "tttt"
  346.     set pad 28
  347. }
  348. append line $next
  349. set sep ", "
  350.     }
  351.     append line ")"
  352. }
  353.     }
  354.     append text $line
  355.     
  356.     append text ");n"
  357.     return $text
  358. }
  359. # genStubs::makeMacro --
  360. #
  361. # Generate the inline macro for a function.
  362. #
  363. # Arguments:
  364. # name The interface name.
  365. # decl The function declaration.
  366. # index The slot index for this function.
  367. #
  368. # Results:
  369. # Returns the formatted macro definition.
  370. proc genStubs::makeMacro {name decl index} {
  371.     lassign $decl rtype fname args
  372.     set lfname [string tolower [string index $fname 0]]
  373.     append lfname [string range $fname 1 end]
  374.     set text "#ifndef $fnamen#define $fname"
  375.     set arg1 [lindex $args 0]
  376.     set argList ""
  377.     switch -exact $arg1 {
  378. void {
  379.     set argList "()"
  380. }
  381. TCL_VARARGS {
  382. }
  383. default {
  384.     set sep "("
  385.     foreach arg $args {
  386. append argList $sep [lindex $arg 1]
  387. set sep ", "
  388.     }
  389.     append argList ")"
  390. }
  391.     }
  392.     append text " \nt(${name}StubsPtr->$lfname)"
  393.     append text " /* $index */n#endifn"
  394.     return $text
  395. }
  396. # genStubs::makeStub --
  397. #
  398. # Emits a stub function definition.
  399. #
  400. # Arguments:
  401. # name The interface name.
  402. # decl The function declaration.
  403. # index The slot index for this function.
  404. #
  405. # Results:
  406. # Returns the formatted stub function definition.
  407. proc genStubs::makeStub {name decl index} {
  408.     lassign $decl rtype fname args
  409.     set lfname [string tolower [string index $fname 0]]
  410.     append lfname [string range $fname 1 end]
  411.     append text "/* Slot $index */n" $rtype "n" $fname
  412.     set arg1 [lindex $args 0]
  413.     if {![string compare $arg1 "TCL_VARARGS"]} {
  414. lassign [lindex $args 1] type argName 
  415. append text " TCL_VARARGS_DEF($type,$argName)n{n"
  416. append text "    " $type " var;n    va_list argList;n"
  417. if {[string compare $rtype "void"]} {
  418.     append text "    " $rtype " resultValue;n"
  419. }
  420. append text "n    var = (" $type ") TCL_VARARGS_START(" 
  421. $type "," $argName ",argList);nn    "
  422. if {[string compare $rtype "void"]} {
  423.     append text "resultValue = "
  424. }
  425. append text "(" $name "StubsPtr->" $lfname "VA)(var, argList);n"
  426. append text "    va_end(argList);n"
  427. if {[string compare $rtype "void"]} {
  428.     append text "return resultValue;n"
  429. }
  430. append text "}nn"
  431. return $text
  432.     }
  433.     if {![string compare $arg1 "void"]} {
  434. set argList "()"
  435. set argDecls ""
  436.     } else {
  437. set argList ""
  438. set sep "("
  439. foreach arg $args {
  440.     append argList $sep [lindex $arg 1]
  441.     append argDecls "    " [lindex $arg 0] " " 
  442.     [lindex $arg 1] [lindex $arg 2] ";n"
  443.     set sep ", "
  444. }
  445. append argList ")"
  446.     }
  447.     append text $argList "n" $argDecls "{n    "
  448.     if {[string compare $rtype "void"]} {
  449. append text "return "
  450.     }
  451.     append text "(" $name "StubsPtr->" $lfname ")" $argList ";n}nn"
  452.     return $text
  453. }
  454. # genStubs::makeSlot --
  455. #
  456. # Generate the stub table entry for a function.
  457. #
  458. # Arguments:
  459. # name The interface name.
  460. # decl The function declaration.
  461. # index The slot index for this function.
  462. #
  463. # Results:
  464. # Returns the formatted table entry.
  465. proc genStubs::makeSlot {name decl index} {
  466.     lassign $decl rtype fname args
  467.     set lfname [string tolower [string index $fname 0]]
  468.     append lfname [string range $fname 1 end]
  469.     set text "    "
  470.     append text $rtype " (*" $lfname ") _ANSI_ARGS_("
  471.     set arg1 [lindex $args 0]
  472.     switch -exact $arg1 {
  473. void {
  474.     append text "(void)"
  475. }
  476. TCL_VARARGS {
  477.     set arg [lindex $args 1]
  478.     append text "TCL_VARARGS([lindex $arg 0],[lindex $arg 1])"
  479. }
  480. default {
  481.     set sep "("
  482.     foreach arg $args {
  483. append text $sep [lindex $arg 0] " " [lindex $arg 1] 
  484. [lindex $arg 2]
  485. set sep ", "
  486.     }
  487.     append text ")"
  488. }
  489.     }
  490.     
  491.     append text "); /* $index */n"
  492.     return $text
  493. }
  494. # genStubs::makeInit --
  495. #
  496. # Generate the prototype for a function.
  497. #
  498. # Arguments:
  499. # name The interface name.
  500. # decl The function declaration.
  501. # index The slot index for this function.
  502. #
  503. # Results:
  504. # Returns the formatted declaration string.
  505. proc genStubs::makeInit {name decl index} {
  506.     append text "    " [lindex $decl 1] ", /* " $index " */n"
  507.     return $text
  508. }
  509. # genStubs::forAllStubs --
  510. #
  511. # This function iterates over all of the platforms and invokes
  512. # a callback for each slot.  The result of the callback is then
  513. # placed inside appropriate platform guards.
  514. #
  515. # Arguments:
  516. # name The interface name.
  517. # slotProc The proc to invoke to handle the slot.  It will
  518. # have the interface name, the declaration,  and
  519. # the index appended.
  520. # onAll If 1, emit the skip string even if there are
  521. # definitions for one or more platforms.
  522. # textVar The variable to use for output.
  523. # skipString The string to emit if a slot is skipped.  This
  524. # string will be subst'ed in the loop so "$i" can
  525. # be used to substitute the index value.
  526. #
  527. # Results:
  528. # None.
  529. proc genStubs::forAllStubs {name slotProc onAll textVar 
  530. {skipString {"/* Slot $i is reserved */n"}}} {
  531.     variable stubs
  532.     upvar $textVar text
  533.     set plats [array names stubs $name,*,lastNum]
  534.     if {[info exists stubs($name,generic,lastNum)]} {
  535. # Emit integrated stubs block
  536. set lastNum -1
  537. foreach plat [array names stubs $name,*,lastNum] {
  538.     if {$stubs($plat) > $lastNum} {
  539. set lastNum $stubs($plat)
  540.     }
  541. }
  542. for {set i 0} {$i <= $lastNum} {incr i} {
  543.     set slots [array names stubs $name,*,$i]
  544.     set emit 0
  545.     if {[info exists stubs($name,generic,$i)]} {
  546. if {[llength $slots] > 1} {
  547.     puts stderr "platform entry duplicates generic entry: $i"
  548. }
  549. append text [$slotProc $name $stubs($name,generic,$i) $i]
  550. set emit 1
  551.     } elseif {[llength $slots] > 0} {
  552. foreach plat {unix win mac} {
  553.     if {[info exists stubs($name,$plat,$i)]} {
  554. append text [addPlatformGuard $plat 
  555. [$slotProc $name $stubs($name,$plat,$i) $i]]
  556. set emit 1
  557.     } elseif {$onAll} {
  558. append text [eval {addPlatformGuard $plat} $skipString]
  559. set emit 1
  560.     }
  561. }
  562.                 #
  563.                 # "aqua" and "macosx" and "x11" are special cases, 
  564.                 # since "macosx" always implies "unix" and "aqua", 
  565.                 # "macosx", so we need to be careful not to 
  566.                 # emit duplicate stubs entries for the two.
  567.                 #
  568. if {[info exists stubs($name,aqua,$i)]
  569.                         && ![info exists stubs($name,macosx,$i)]} {
  570.     append text [addPlatformGuard aqua 
  571.     [$slotProc $name $stubs($name,aqua,$i) $i]]
  572.     set emit 1
  573. }
  574. if {[info exists stubs($name,macosx,$i)]
  575.                         && ![info exists stubs($name,unix,$i)]} {
  576.     append text [addPlatformGuard macosx 
  577.     [$slotProc $name $stubs($name,macosx,$i) $i]]
  578.     set emit 1
  579. }
  580. if {[info exists stubs($name,x11,$i)]
  581.                         && ![info exists stubs($name,unix,$i)]} {
  582.     append text [addPlatformGuard x11 
  583.     [$slotProc $name $stubs($name,x11,$i) $i]]
  584.     set emit 1
  585. }
  586.     }
  587.     if {$emit == 0} {
  588. eval {append text} $skipString
  589.     }
  590. }
  591.     } else {
  592. # Emit separate stubs blocks per platform
  593. foreach plat {unix win mac} {
  594.     if {[info exists stubs($name,$plat,lastNum)]} {
  595. set lastNum $stubs($name,$plat,lastNum)
  596. set temp {}
  597. for {set i 0} {$i <= $lastNum} {incr i} {
  598.     if {![info exists stubs($name,$plat,$i)]} {
  599. eval {append temp} $skipString
  600.     } else {
  601. append temp [$slotProc $name $stubs($name,$plat,$i) $i]
  602.     }
  603. }
  604. append text [addPlatformGuard $plat $temp]
  605.     }
  606. }
  607.         # Again, make sure you don't duplicate entries for macosx & aqua.
  608. if {[info exists stubs($name,aqua,lastNum)]
  609.                 && ![info exists stubs($name,macosx,lastNum)]} {
  610.     set lastNum $stubs($name,aqua,lastNum)
  611.     set temp {}
  612.     for {set i 0} {$i <= $lastNum} {incr i} {
  613. if {![info exists stubs($name,aqua,$i)]} {
  614.     eval {append temp} $skipString
  615. } else {
  616. append temp [$slotProc $name $stubs($name,aqua,$i) $i]
  617.     }
  618. }
  619. append text [addPlatformGuard aqua $temp]
  620.     }
  621.         # Again, make sure you don't duplicate entries for macosx & unix.
  622. if {[info exists stubs($name,macosx,lastNum)]
  623.                 && ![info exists stubs($name,unix,lastNum)]} {
  624.     set lastNum $stubs($name,macosx,lastNum)
  625.     set temp {}
  626.     for {set i 0} {$i <= $lastNum} {incr i} {
  627. if {![info exists stubs($name,macosx,$i)]} {
  628.     eval {append temp} $skipString
  629. } else {
  630. append temp [$slotProc $name $stubs($name,macosx,$i) $i]
  631.     }
  632. }
  633. append text [addPlatformGuard macosx $temp]
  634.     }
  635.         # Again, make sure you don't duplicate entries for x11 & unix.
  636. if {[info exists stubs($name,x11,lastNum)]
  637.                 && ![info exists stubs($name,unix,lastNum)]} {
  638.     set lastNum $stubs($name,x11,lastNum)
  639.     set temp {}
  640.     for {set i 0} {$i <= $lastNum} {incr i} {
  641. if {![info exists stubs($name,x11,$i)]} {
  642.     eval {append temp} $skipString
  643. } else {
  644. append temp [$slotProc $name $stubs($name,x11,$i) $i]
  645.     }
  646. }
  647. append text [addPlatformGuard x11 $temp]
  648.     }
  649.     }
  650. }
  651. # genStubs::emitDeclarations --
  652. #
  653. # This function emits the function declarations for this interface.
  654. #
  655. # Arguments:
  656. # name The interface name.
  657. # textVar The variable to use for output.
  658. #
  659. # Results:
  660. # None.
  661. proc genStubs::emitDeclarations {name textVar} {
  662.     variable stubs
  663.     upvar $textVar text
  664.     append text "n/*n * Exported function declarations:n */nn"
  665.     forAllStubs $name makeDecl 0 text
  666.     return
  667. }
  668. # genStubs::emitMacros --
  669. #
  670. # This function emits the inline macros for an interface.
  671. #
  672. # Arguments:
  673. # name The name of the interface being emitted.
  674. # textVar The variable to use for output.
  675. #
  676. # Results:
  677. # None.
  678. proc genStubs::emitMacros {name textVar} {
  679.     variable stubs
  680.     variable libraryName
  681.     upvar $textVar text
  682.     set upName [string toupper $libraryName]
  683.     append text "n#if defined(USE_${upName}_STUBS) && !defined(USE_${upName}_STUB_PROCS)n"
  684.     append text "n/*n * Inline function declarations:n */nn"
  685.     
  686.     forAllStubs $name makeMacro 0 text
  687.     append text "n#endif /* defined(USE_${upName}_STUBS) && !defined(USE_${upName}_STUB_PROCS) */n"
  688.     return
  689. }
  690. # genStubs::emitHeader --
  691. #
  692. # This function emits the body of the <name>Decls.h file for
  693. # the specified interface.
  694. #
  695. # Arguments:
  696. # name The name of the interface being emitted.
  697. #
  698. # Results:
  699. # None.
  700. proc genStubs::emitHeader {name} {
  701.     variable outDir
  702.     variable hooks
  703.     set capName [string toupper [string index $name 0]]
  704.     append capName [string range $name 1 end]
  705.     emitDeclarations $name text
  706.     if {[info exists hooks($name)]} {
  707. append text "ntypedef struct ${capName}StubHooks {n"
  708. foreach hook $hooks($name) {
  709.     set capHook [string toupper [string index $hook 0]]
  710.     append capHook [string range $hook 1 end]
  711.     append text "    struct ${capHook}Stubs *${hook}Stubs;n"
  712. }
  713. append text "} ${capName}StubHooks;n"
  714.     }
  715.     append text "ntypedef struct ${capName}Stubs {n"
  716.     append text "    int magic;n"
  717.     append text "    struct ${capName}StubHooks *hooks;nn"
  718.     emitSlots $name text
  719.     append text "} ${capName}Stubs;n"
  720.     append text "n#ifdef __cplusplusnextern "C" {n#endifn"
  721.     append text "extern ${capName}Stubs *${name}StubsPtr;n"
  722.     append text "#ifdef __cplusplusn}n#endifn"
  723.     emitMacros $name text
  724.     rewriteFile [file join $outDir ${name}Decls.h] $text
  725.     return
  726. }
  727. # genStubs::emitStubs --
  728. #
  729. # This function emits the body of the <name>Stubs.c file for
  730. # the specified interface.
  731. #
  732. # Arguments:
  733. # name The name of the interface being emitted.
  734. #
  735. # Results:
  736. # None.
  737. proc genStubs::emitStubs {name} {
  738.     variable outDir
  739.     append text "n/*n * Exported stub functions:n */nn"
  740.     forAllStubs $name makeStub 0 text
  741.     rewriteFile [file join $outDir ${name}Stubs.c] $text
  742.     return    
  743. }
  744. # genStubs::emitInit --
  745. #
  746. # Generate the table initializers for an interface.
  747. #
  748. # Arguments:
  749. # name The name of the interface to initialize.
  750. # textVar The variable to use for output.
  751. #
  752. # Results:
  753. # Returns the formatted output.
  754. proc genStubs::emitInit {name textVar} {
  755.     variable stubs
  756.     variable hooks
  757.     upvar $textVar text
  758.     set capName [string toupper [string index $name 0]]
  759.     append capName [string range $name 1 end]
  760.     if {[info exists hooks($name)]} {
  761.   append text "nstatic ${capName}StubHooks ${name}StubHooks = {n"
  762. set sep "    "
  763. foreach sub $hooks($name) {
  764.     append text $sep "&${sub}Stubs"
  765.     set sep ",n    "
  766. }
  767. append text "n};n"
  768.     }
  769.     append text "n${capName}Stubs ${name}Stubs = {n"
  770.     append text "    TCL_STUB_MAGIC,n"
  771.     if {[info exists hooks($name)]} {
  772. append text "    &${name}StubHooks,n"
  773.     } else {
  774. append text "    NULL,n"
  775.     }
  776.     
  777.     forAllStubs $name makeInit 1 text {"    NULL, /* $i */n"}
  778.     append text "};n"
  779.     return
  780. }
  781. # genStubs::emitInits --
  782. #
  783. # This function emits the body of the <name>StubInit.c file for
  784. # the specified interface.
  785. #
  786. # Arguments:
  787. # name The name of the interface being emitted.
  788. #
  789. # Results:
  790. # None.
  791. proc genStubs::emitInits {} {
  792.     variable hooks
  793.     variable outDir
  794.     variable libraryName
  795.     variable interfaces
  796.     # Assuming that dependencies only go one level deep, we need to emit
  797.     # all of the leaves first to avoid needing forward declarations.
  798.     set leaves {}
  799.     set roots {}
  800.     foreach name [lsort [array names interfaces]] {
  801. if {[info exists hooks($name)]} {
  802.     lappend roots $name
  803. } else {
  804.     lappend leaves $name
  805. }
  806.     }
  807.     foreach name $leaves {
  808. emitInit $name text
  809.     }
  810.     foreach name $roots {
  811. emitInit $name text
  812.     }
  813.     rewriteFile [file join $outDir ${libraryName}StubInit.c] $text
  814. }
  815. # genStubs::init --
  816. #
  817. # This is the main entry point.
  818. #
  819. # Arguments:
  820. # None.
  821. #
  822. # Results:
  823. # None.
  824. proc genStubs::init {} {
  825.     global argv argv0
  826.     variable outDir
  827.     variable interfaces
  828.     if {[llength $argv] < 2} {
  829. puts stderr "usage: $argv0 outDir declFile ?declFile...?"
  830. exit 1
  831.     }
  832.     set outDir [lindex $argv 0]
  833.     foreach file [lrange $argv 1 end] {
  834. source $file
  835.     }
  836.     foreach name [lsort [array names interfaces]] {
  837. puts "Emitting $name"
  838. emitHeader $name
  839.     }
  840.     emitInits
  841. }
  842. # lassign --
  843. #
  844. # This function emulates the TclX lassign command.
  845. #
  846. # Arguments:
  847. # valueList A list containing the values to be assigned.
  848. # args The list of variables to be assigned.
  849. #
  850. # Results:
  851. # Returns any values that were not assigned to variables.
  852. proc lassign {valueList args} {
  853.   if {[llength $args] == 0} {
  854.       error "wrong # args: lassign list varname ?varname..?"
  855.   }
  856.   uplevel [list foreach $args $valueList {break}]
  857.   return [lrange $valueList [llength $args] end]
  858. }
  859. genStubs::init