home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / struct / stack.tcl < prev    next >
Encoding:
Text File  |  2001-08-17  |  6.0 KB  |  267 lines

  1. # stack.tcl --
  2. #
  3. #    Stack implementation for Tcl.
  4. #
  5. # Copyright (c) 1998-2000 by Ajuba Solutions.
  6. #
  7. # See the file "license.terms" for information on usage and redistribution
  8. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  9. # RCS: @(#) $Id: stack.tcl,v 1.3 2000/06/02 18:43:56 ericm Exp $
  10.  
  11. namespace eval ::struct {}
  12.  
  13. namespace eval ::struct::stack {
  14.     # The stacks array holds all of the stacks you've made
  15.     variable stacks
  16.     
  17.     # counter is used to give a unique name for unnamed stacks
  18.     variable counter 0
  19.  
  20.     # commands is the list of subcommands recognized by the stack
  21.     variable commands [list \
  22.         "clear"    \
  23.         "destroy"    \
  24.         "peek"    \
  25.         "pop"    \
  26.         "push"    \
  27.         "rotate"    \
  28.         "size"    \
  29.         ]
  30.  
  31.     # Only export one command, the one used to instantiate a new stack
  32.     namespace export stack
  33. }
  34.  
  35. # ::struct::stack::stack --
  36. #
  37. #    Create a new stack with a given name; if no name is given, use
  38. #    stackX, where X is a number.
  39. #
  40. # Arguments:
  41. #    name    name of the stack; if null, generate one.
  42. #
  43. # Results:
  44. #    name    name of the stack created
  45.  
  46. proc ::struct::stack::stack {{name ""}} {
  47.     variable stacks
  48.     variable counter
  49.     
  50.     if { [llength [info level 0]] == 1 } {
  51.     incr counter
  52.     set name "stack${counter}"
  53.     }
  54.  
  55.     if { ![string equal [info commands ::$name] ""] } {
  56.     error "command \"$name\" already exists, unable to create stack"
  57.     }
  58.     set stacks($name) [list ]
  59.  
  60.     # Create the command to manipulate the stack
  61.     interp alias {} ::$name {} ::struct::stack::StackProc $name
  62.  
  63.     return $name
  64. }
  65.  
  66. ##########################
  67. # Private functions follow
  68.  
  69. # ::struct::stack::StackProc --
  70. #
  71. #    Command that processes all stack object commands.
  72. #
  73. # Arguments:
  74. #    name    name of the stack object to manipulate.
  75. #    args    command name and args for the command
  76. #
  77. # Results:
  78. #    Varies based on command to perform
  79.  
  80. proc ::struct::stack::StackProc {name cmd args} {
  81.     # Split the args into command and args components
  82.     if { [lsearch -exact $::struct::stack::commands $cmd] == -1 } {
  83.     set optlist [join $::struct::stack::commands ", "]
  84.     set optlist [linsert $optlist "end-1" "or"]
  85.     error "bad option \"$cmd\": must be $optlist"
  86.     }
  87.     eval [list ::struct::stack::_$cmd $name] $args
  88. }
  89.  
  90. # ::struct::stack::_clear --
  91. #
  92. #    Clear a stack.
  93. #
  94. # Arguments:
  95. #    name    name of the stack object.
  96. #
  97. # Results:
  98. #    None.
  99.  
  100. proc ::struct::stack::_clear {name} {
  101.     set ::struct::stack::stacks($name) [list ]
  102.     return
  103. }
  104.  
  105. # ::struct::stack::_destroy --
  106. #
  107. #    Destroy a stack object by removing it's storage space and 
  108. #    eliminating it's proc.
  109. #
  110. # Arguments:
  111. #    name    name of the stack object.
  112. #
  113. # Results:
  114. #    None.
  115.  
  116. proc ::struct::stack::_destroy {name} {
  117.     unset ::struct::stack::stacks($name)
  118.     interp alias {} ::$name {}
  119.     return
  120. }
  121.  
  122. # ::struct::stack::_peek --
  123. #
  124. #    Retrive the value of an item on the stack without popping it.
  125. #
  126. # Arguments:
  127. #    name    name of the stack object.
  128. #    count    number of items to pop; defaults to 1
  129. #
  130. # Results:
  131. #    items    top count items from the stack; if there are not enough items
  132. #        to fufill the request, throws an error.
  133.  
  134. proc ::struct::stack::_peek {name {count 1}} {
  135.     variable stacks
  136.     if { $count < 1 } {
  137.     error "invalid item count $count"
  138.     }
  139.  
  140.     if { $count > [llength $stacks($name)] } {
  141.     error "insufficient items on stack to fill request"
  142.     }
  143.  
  144.     if { $count == 1 } {
  145.     # Handle this as a special case, so single item pops aren't listified
  146.     set item [lindex $stacks($name) end]
  147.     return $item
  148.     }
  149.  
  150.     # Otherwise, return a list of items
  151.     set result [list ]
  152.     for {set i 0} {$i < $count} {incr i} {
  153.     lappend result [lindex $stacks($name) "end-${i}"]
  154.     }
  155.     return $result
  156. }
  157.  
  158. # ::struct::stack::_pop --
  159. #
  160. #    Pop an item off a stack.
  161. #
  162. # Arguments:
  163. #    name    name of the stack object.
  164. #    count    number of items to pop; defaults to 1
  165. #
  166. # Results:
  167. #    item    top count items from the stack; if the stack is empty, 
  168. #        returns a list of count nulls.
  169.  
  170. proc ::struct::stack::_pop {name {count 1}} {
  171.     variable stacks
  172.     if { $count > [llength $stacks($name)] } {
  173.     error "insufficient items on stack to fill request"
  174.     } elseif { $count < 1 } {
  175.     error "invalid item count $count"
  176.     }
  177.  
  178.     if { $count == 1 } {
  179.     # Handle this as a special case, so single item pops aren't listified
  180.     set item [lindex $stacks($name) end]
  181.     set stacks($name) [lreplace $stacks($name) end end]
  182.     return $item
  183.     }
  184.  
  185.     # Otherwise, return a list of items
  186.     set result [list ]
  187.     for {set i 0} {$i < $count} {incr i} {
  188.     lappend result [lindex $stacks($name) "end-${i}"]
  189.     }
  190.  
  191.     # Remove these items from the stack
  192.     incr i -1
  193.     set stacks($name) [lreplace $stacks($name) "end-${i}" end]
  194.  
  195.     return $result
  196. }
  197.  
  198. # ::struct::stack::_push --
  199. #
  200. #    Push an item onto a stack.
  201. #
  202. # Arguments:
  203. #    name    name of the stack object
  204. #    args    items to push.
  205. #
  206. # Results:
  207. #    None.
  208.  
  209. proc ::struct::stack::_push {name args} {
  210.     if { [llength $args] == 0 } {
  211.     error "wrong # args: should be \"$name push item ?item ...?\""
  212.     }
  213.     foreach item $args {
  214.     lappend ::struct::stack::stacks($name) $item
  215.     }
  216. }
  217.  
  218. # ::struct::stack::_rotate --
  219. #
  220. #    Rotate the top count number of items by step number of steps.
  221. #
  222. # Arguments:
  223. #    name    name of the stack object.
  224. #    count    number of items to rotate.
  225. #    steps    number of steps to rotate.
  226. #
  227. # Results:
  228. #    None.
  229.  
  230. proc ::struct::stack::_rotate {name count steps} {
  231.     variable stacks
  232.     set len [llength $stacks($name)]
  233.     if { $count > $len } {
  234.     error "insufficient items on stack to fill request"
  235.     }
  236.  
  237.     # Rotation algorithm:
  238.     # do
  239.     #   Find the insertion point in the stack
  240.     #   Move the end item to the insertion point
  241.     # repeat $steps times
  242.  
  243.     set start [expr {$len - $count}]
  244.     set steps [expr {$steps % $count}]
  245.     for {set i 0} {$i < $steps} {incr i} {
  246.     set item [lindex $stacks($name) end]
  247.     set stacks($name) [lreplace $stacks($name) end end]
  248.     set stacks($name) [linsert $stacks($name) $start $item]
  249.     }
  250.     return
  251. }
  252.  
  253. # ::struct::stack::_size --
  254. #
  255. #    Return the number of objects on a stack.
  256. #
  257. # Arguments:
  258. #    name    name of the stack object.
  259. #
  260. # Results:
  261. #    count    number of items on the stack.
  262.  
  263. proc ::struct::stack::_size {name} {
  264.     return [llength $::struct::stack::stacks($name)]
  265. }
  266.