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

通讯编程

开发平台:

Visual C++

  1. #
  2. # Copyright (c) 1996 Regents of the University of California.
  3. # All rights reserved.
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. # 1. Redistributions of source code must retain the above copyright
  8. #    notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. #    notice, this list of conditions and the following disclaimer in the
  11. #    documentation and/or other materials provided with the distribution.
  12. # 3. All advertising materials mentioning features or use of this software
  13. #    must display the following acknowledgement:
  14. #  This product includes software developed by the MASH Research
  15. #  Group at the University of California Berkeley.
  16. # 4. Neither the name of the University nor of the Research Group may be
  17. #    used to endorse or promote products derived from this software without
  18. #    specific prior written permission.
  19. # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  20. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. # ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  23. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. # SUCH DAMAGE.
  30. #
  31. # $Header: /cvsroot/otcl-tclcl/tclcl/tcl-object.tcl,v 1.41 2000/07/28 23:15:08 johnh Exp $
  32. #
  33. #
  34. # InitObject is an OTcl object that exports "init-vars" to initialize
  35. # default variables, and mimic Object's args processing.
  36. #
  37. Class InitObject
  38. #
  39. # init-vars: calls init-default-vars to initilize all default variables
  40. #   then process args the way Object::init does, and return unused args
  41. #
  42. #  This is how it should be used from "init" instproc of split objects
  43. # set args [eval $self init-vars $args]
  44. # eval $self next $args
  45. #
  46. Object instproc init-vars {args} {
  47. $self init-default-vars [$self info class]
  48. # Emulate Object's args processing
  49. #  1.  Look for pairs of {-cmd val} in args
  50. #  2.  If "$self $cmd $val" is not valid then put it in $shadow_args
  51. set shadow_args ""
  52. for {} {$args != ""} {set args [lrange $args 2 end]} {
  53. set key [lindex $args 0]
  54. set val [lindex $args 1]
  55. if {$val != "" && [string match {-[A-z]*} $key]} {
  56. set cmd [string range $key 1 end]
  57. if ![catch "$self $cmd $val"] {
  58. continue
  59. }
  60. }
  61. lappend shadow_args $key $val
  62. }
  63. return $shadow_args
  64. }
  65. #
  66. # init-all-vars:  initializes all default variables for an object
  67. #
  68. Object instproc init-default-vars {classes} {
  69. foreach cl $classes {
  70. if {$cl == "Object"} continue
  71. # depth first: set vars of ancestors first
  72. $self init-default-vars "[$cl info superclass]"
  73. foreach var [$cl info vars] {
  74. if [catch "$self set $var"] {
  75. $self set $var [$cl set $var]
  76. }
  77. }
  78. }
  79. }
  80. #
  81. # A SplitObject is an OTcl object with a C++ shadow object, i.e., an object
  82. # whose implementation is split across OTcl and C++.  This is the base
  83. # class of all such objects.
  84. #
  85. Class SplitObject
  86. SplitObject set id 0
  87. SplitObject instproc init args {
  88. $self next
  89. if [catch "$self create-shadow $args"] {
  90. error "__FAILED_SHADOW_OBJECT_" ""
  91. }
  92. }
  93. #
  94. # reimplement set and get in terms of instvar
  95. # to handle classinstvars
  96. #
  97. SplitObject instproc set args {
  98. set var [lindex $args 0]
  99. $self instvar -parse-part1 $var
  100. if {[llength $args] == 1} {
  101. return [subst $[subst $var]]
  102. } else {
  103. return [set $var [lindex $args 1]]
  104. }
  105. }
  106. SplitObject instproc destroy {} {
  107. $self delete-shadow
  108. $self next
  109. }
  110. SplitObject proc getid {} {
  111. $self instvar id
  112. incr id
  113. return _o$id
  114. }
  115. SplitObject proc is-class cl {
  116. if [catch "SplitObject info subclass $cl" v] {
  117. return 0
  118. }
  119. return $v
  120. }
  121. SplitObject instproc unknown args {
  122. if [catch "$self cmd $args" ret] {
  123. set cls [$self info class]
  124. global errorInfo
  125. set savedInfo $errorInfo
  126. error "error when calling class $cls: $args" $savedInfo
  127. }
  128. return $ret
  129. }
  130. proc new { className args } {
  131. set o [SplitObject getid]
  132. if [catch "$className create $o $args" msg] {
  133. if [string match "__FAILED_SHADOW_OBJECT_" $msg] {
  134. #
  135. # The shadow object failed to be allocated.
  136. delete $o
  137. return ""
  138. }
  139. global errorInfo
  140. error "class $className: constructor failed: $msg" $errorInfo
  141. }
  142. return $o
  143. }
  144. proc delete o {
  145. $o delete_tkvar
  146. $o destroy
  147. }
  148. #
  149. # Register a C++ compiled-in class with OTcl
  150. # Arrange things so we catch create and destroy
  151. # and manage the underlying C++ object accordingly.
  152. # Classes have structured names with the hierarchy
  153. # delineated by slashes, e.g., a side effect of
  154. # creating class "A/B/C" is to create classes "A"
  155. # and "A/B".
  156. # This routine invoked by TclClass::bind.
  157. #
  158. SplitObject proc register className {
  159. set classes [split $className /]
  160. set parent SplitObject
  161. set path ""
  162. set sep ""
  163. foreach cl $classes {
  164. set path $path$sep$cl
  165. if ![$self is-class $path] {
  166. Class $path -superclass $parent
  167. }
  168. set sep /
  169. set parent $path
  170. }
  171. }
  172. #
  173. # warn if a class variable not defined
  174. # this is in a separate method so user can nop it
  175. #
  176. # In ns, this error happens for several possible reasons:
  177. #
  178. # 1. you bound a variable in C but didn't initialize it in tcl
  179. # To fix:  put initialization code in tcl/lib/ns-default.tcl
  180. # (and make sure that this code ends up compiled into your
  181. # version of ns!)
  182. #
  183. # 2. You bound it in C and think you initialized it in Tcl,
  184. # but there's an error in your class hierarchy
  185. # (for example, the Tcl hierarchy name given in
  186. # the XxxClass declaration in C++
  187. # doesn't match the name used in the Tcl initialization).
  188. #
  189. # 3. you invoked something which assumed that something else had
  190. # been built (for example, doing "new Node" without having
  191. # first done "new Simulator")
  192. # To fix:  do new Simulator (or whatever).
  193. #
  194. # 4. You created a split object from C++ (with new)
  195. # rather than from Tcl.
  196. # Nitin Vaidya <Nitin.Vaidya@Eng.Sun.COM> found this problem
  197. # and suggested working around it either by avoiding
  198. # binding the variable or invoking tcl to create the object.
  199. # See the discussion at
  200. # http://www-mash.cs.berkeley.edu/dist/archive/ns-users/9808/
  201. # for more details.
  202. #
  203. SplitObject instproc warn-instvar item {
  204. $self instvar issuedWarning
  205. if ![info exists issuedWarning($item)] {
  206. set issuedWarning($item) 1
  207. puts stderr "warning: no class variable $itemn"
  208. $self instvar SplitObject_issued_undeclared_warning
  209. if ![info exists SplitObject_issued_undeclared_warning] {
  210. puts stderr "tsee tcl-object.tcl in tclcl for info about this warning.n"
  211. # (i.e., see the comment 20 lines back)
  212. set SplitObject_issued_undeclared_warning 1
  213. }
  214. }
  215. }
  216. #
  217. # Initialize a class instance variable from its
  218. # parent class' member value.  If no such variable,
  219. # call the warning method (which can be overridden).
  220. # We search the class hierarchy for the variable
  221. # until we give up at the SplitObject class.
  222. #
  223. SplitObject instproc init-instvar var {
  224. set cl [$self info class]
  225. while { "$cl" != "" && "$cl" != "SplitObject" } {
  226. foreach c $cl {
  227. if ![catch "$c set $var" val] {
  228. $self set $var $val
  229. return
  230. }
  231. }
  232. set parents ""
  233. foreach c $cl {
  234. if { $cl != "SplitObject" && $cl != "Object" } {
  235. set parents "$parents [$c info superclass]"
  236. }
  237. }
  238. set cl $parents
  239. }
  240. $self warn-instvar [$self info class]::$var
  241. }
  242. proc tkerror msg {
  243. global errorInfo
  244. puts -nonewline "$msg: "
  245. puts $errorInfo
  246. exit 1
  247. }
  248. # somehow tkerror is *evaluated* as 'bgerror', and put 'tkerror' in
  249. # bgerror's body will cause an infinite execution loop... :(
  250. proc bgerror msg {
  251. global errorInfo
  252. puts -nonewline "$msg: "
  253. puts $errorInfo
  254. exit 1
  255. }
  256. #
  257. # Method hooks to allow using public/private keywords
  258. # instead of instproc to define methods.  For now, we
  259. # don't actually enforce these semantics.  Rather, they
  260. # serve only to document the API (and as a hook for
  261. # the automatic doc generator).
  262. #
  263. Object instproc public args {
  264. eval $self instproc $args
  265. }
  266. Object instproc private args {
  267. eval $self instproc $args
  268. }
  269. Object instproc proc.public args {
  270. eval $self proc $args
  271. }
  272. Object instproc proc.private args {
  273. eval $self proc $args
  274. }
  275. Object instproc proc.invoke { arglist body args } {
  276. $self proc invokeproc_ $arglist $body
  277. eval [list $self] invokeproc_ $args
  278. }
  279. #tkvar stuff
  280. Object instproc tkvar args {
  281. foreach var $args {
  282. if { [llength $var] > 1 } {
  283. set varname [lindex $var 1]
  284. set var [lindex $var 0]
  285. } else {
  286. set varname $var
  287. }
  288. uplevel upvar #0 $self/$var $varname
  289. }
  290. }
  291. Object instproc tkvarname var {
  292. return $self/$var
  293. }
  294. Object instproc delete_tkvar { } {
  295. set fullname [$self tkvarname foo]
  296. regexp "(.*)foo$" $fullname dummy prefix
  297. foreach global [info globals "$prefix*"] {
  298. global $global
  299. unset $global
  300. }
  301. }
  302. Object instproc info_tkvar { pattern } {
  303. set pattern [$self tkvarname $pattern]
  304. return [info globals $pattern]
  305. }
  306. #
  307. # Backward compat: SplitObjects used to be called TclObjects
  308. #
  309. proc TclObject args {
  310. return [eval SplitObject $args]
  311. }
  312. # Misc. helpers
  313. #
  314. # Procedure to order a list of SplitObject's.
  315. #
  316. # use as: "lsort -command SplitObjectCompare {list}"
  317. #
  318. proc SplitObjectCompare {a b} {
  319. set o1 [string range $a 2 end]
  320. set o2 [string range $b 2 end]
  321. if {$o1 < $o2} {
  322. return -1
  323. } elseif {$o1 == $o2} {
  324. return 0
  325. } else {
  326. return 1
  327. }
  328. }
  329. Object instproc extract-var varname {
  330.         set aidx [string first "(" $varname]
  331.         if { $aidx >= 0 } {
  332.                 string range $varname 0 [incr aidx -1]
  333.         } else {
  334.                 set varname
  335.         }
  336. }
  337. Object instproc add-to-list {list elem} {
  338. $self instvar [$self extract-var $list]
  339. set ret 0
  340. if ![info exists $list] {
  341. set $list $elem
  342. set ret 1
  343. } elseif { [lsearch [set $list] $elem] < 0 } {
  344.                 lappend $list $elem
  345. set ret 1
  346.         }
  347. set ret
  348. }
  349. Object instproc remove-from-list {list elem} {
  350. $self instvar [$self extract-var $list]
  351. set wtag "$self: remove $elem from $list failed"
  352. set ret  0
  353. if ![info exists $list] {
  354. warn "$wtag: list does not exist"
  355. } else {
  356. set k [lsearch [set $list] $elem]
  357. if { $k < 0 } {
  358. warn "$wtag: element does not exist"
  359. } else {
  360. set $list [lreplace [set $list] $k $k]
  361. set ret 1
  362. }
  363. }
  364. set ret
  365. }