record.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 namespace ::struct {}
00031
00032 namespace ::struct::record {
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 variable _recorddefn
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 variable _count
00057
00058
00059
00060
00061
00062
00063
00064
00065 variable _defn
00066 array _defn = {}
00067
00068
00069
00070
00071
00072
00073
00074 variable _defaults
00075
00076
00077
00078
00079
00080 variable commands
00081 commands = [list define delete exists show]
00082
00083
00084
00085
00086
00087
00088
00089 _level = 0
00090
00091 namespace export record
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 ret ::struct::record::record (type cmd_ , type args) {
00108 variable commands
00109
00110 if {[lsearch $commands $cmd_] < 0} {
00111 error "Sub command \"$cmd_\" is not recognized. Must be [join $commands ,]"
00112 }
00113
00114 set cmd_ [string totitle "$cmd_"]
00115 return [uplevel 1 ::struct::record::${cmd_} $args]
00116
00117 };
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 ret ::struct::record::Define (type defn_ , type vars_ , type args) {
00136
00137 variable _recorddefn
00138 variable _count
00139 variable _defaults
00140
00141 set defn_ [Qualify $defn_]
00142
00143 if {[info exists _recorddefn($defn_)]} {
00144 error "Record definition $defn_ already exists"
00145 }
00146
00147 if {[lsearch [info commands] $defn_] >= 0} {
00148 error "Structure definition name can not be a Tcl command name"
00149 }
00150
00151 set _defaults($defn_) [list]
00152 set _recorddefn($defn_) [list]
00153
00154
00155 ##
00156 ## Loop through the members of the record
00157 ## definition
00158 ##
00159 foreach V $vars_ {
00160
00161 set len [llength $V]
00162 set D ""
00163
00164 ##
00165 ## 2 --> there is a default value
00166 ## assigned to the member
00167 ##
00168 ## 3 --> there is a nested record
00169 ## definition given as a member
00170 ##
00171 if {$len == 2} {
00172
00173 set D [lindex $V 1]
00174 set V [lindex $V 0]
00175
00176 } elseif {$len == 3} {
00177
00178 if {![string match "record" "[lindex $V 0]"]} {
00179
00180 Delete record $defn_
00181 error "$V is a Bad member for record definition
00182 definition creation aborted."
00183 }
00184
00185 set new [lindex $V 1]
00186
00187 set new [Qualify $new]
00188
00189 ##
00190 ## Right now, there can not be circular records
00191 ## so, we abort the creation
00192 ##
00193 if {[string match "$defn_" "$new"]} {
00194 Delete record $defn_
00195 error "Can not have circular records. Structure was not created."
00196 }
00197
00198 ##
00199 ## Will take care of the nested record later
00200 ## We just join by :: because this is how it
00201 ## use to be declared, so the parsing code
00202 ## is already there.
00203 ##
00204 set V [join [lrange $V 1 2] "::"]
00205 }
00206
00207 lappend _recorddefn($defn_) $V
00208 lappend _defaults($defn_) $D
00209 }
00210
00211
00212 uplevel #0 [list interp alias {} $defn_ {} ::struct::record::Create $defn_]
00213
00214 set _count($defn_) 0
00215
00216 namespace eval ::struct::record${defn_} {
00217 variable values
00218 variable instances
00219
00220 set instances [list]
00221 }
00222
00223 ##
00224 ## If there were args given (instances), then
00225 ## create them now
00226 ##
00227 foreach A $args {
00228
00229 uplevel 1 [list ::struct::record::Create $defn_ $A]
00230 }
00231
00232 return $defn_
00233
00234 };
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 ret ::struct::record::Create (type defn_ , type inst_ , type args) {
00252
00253 variable _recorddefn
00254 variable _count
00255 variable _defn
00256 variable _defaults
00257 variable _level
00258
00259 set inst_ [Qualify "$inst_"]
00260
00261 ##
00262 ## test to see if the record
00263 ## definition has been defined yet
00264 ##
00265 if {![info exists _recorddefn($defn_)]} {
00266 error "Structure $defn_ does not exist"
00267 }
00268
00269
00270 ##
00271 ## if there was no argument given,
00272 ## then assume that the record
00273 ## variable is automatically
00274 ## generated
00275 ##
00276 if {[string match "[Qualify #auto]" "$inst_"]} {
00277 set c $_count($defn_)
00278 set inst_ [format "%s%s" ${defn_} $_count($defn_)]
00279 incr _count($defn_)
00280 }
00281
00282 ##
00283 ## Test to see if this instance is already
00284 ## created. This avoids any collisions with
00285 ## previously created instances
00286 ##
00287 if {[info exists _defn($inst_)]} {
00288 incr _count($defn_) -1
00289 error "Instances $inst_ already exists"
00290 }
00291
00292 set _defn($inst_) $defn_
00293
00294 ##
00295 ## Initialize record variables to
00296 ## defaults
00297 ##
00298
00299 uplevel #0 [list interp alias {} ${inst_} {} ::struct::record::Cmd $inst_]
00300
00301 set cnt 0
00302 foreach V $_recorddefn($defn_) D $_defaults($defn_) {
00303
00304 set [Ns $inst_]values($inst_,$V) $D
00305
00306 ##
00307 ## Test to see if there is a nested record
00308 ##
00309 if {[regexp -- {([\w]*)::([\w]*)} $V m def inst]} {
00310
00311 if {$_level == 0} {
00312 set _level 2
00313 }
00314
00315 ##
00316 ## This is to guard against if the creation
00317 ## had failed, that there isn't any
00318 ## lingering variables/alias around
00319 ##
00320 set def [Qualify $def $_level]
00321
00322 if {![info exists _recorddefn($def)]} {
00323
00324 Delete inst "$inst_"
00325
00326 return
00327 }
00328
00329 ##
00330 ## evaluate the nested record. If there
00331 ## were values for the variables passed
00332 ## in, then we assume that the value for
00333 ## this nested record is a list
00334 ## corresponding the the nested list's
00335 ## variables, and so we pass that to
00336 ## the nested record's instantiation.
00337 ## We then get rid of those args for later
00338 ## processing.
00339 ##
00340 set cnt_plus [expr {$cnt + 1}]
00341 set mem [lindex $args $cnt]
00342 if {![string match "" "$mem"]} {
00343 if {![string match "-$inst" "$mem"]} {
00344 Delete inst "$inst_"
00345 error "$inst is not a member of $defn_"
00346 }
00347 }
00348 incr _level
00349 set narg [lindex $args $cnt_plus]
00350 eval [linsert $narg 0 Create $def ${inst_}.${inst}]
00351 set args [lreplace $args $cnt $cnt_plus]
00352
00353 incr _level -1
00354 } else {
00355
00356 uplevel #0 [list interp alias {} ${inst_}.$V {} ::struct::record::Access $defn_ $inst_ $V]
00357 incr cnt 2
00358 }
00359
00360 }; # end foreach variable
00361
00362 lappend [Ns $inst_]instances $inst_
00363
00364 foreach {k v} $args {
00365
00366 Access $defn_ $inst_ [string trimleft "$k" -] $v
00367
00368 }; # end foreach arg {}
00369
00370 if {$_level == 2} {
00371 set _level 0
00372 }
00373
00374 return $inst_
00375
00376 };
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 ret ::struct::record::Access (type defn_ , type inst_ , type var_ , type args) {
00396
00397 variable _recorddefn
00398 variable _defn
00399
00400 set i [lsearch $_recorddefn($defn_) $var_]
00401
00402 if {$i < 0} {
00403 error "$var_ does not exist in record $defn_"
00404 }
00405
00406 if {![info exists _defn($inst_)]} {
00407
00408 error "$inst_ does not exist"
00409 }
00410
00411 if {[set idx [lsearch $args "="]] >= 0} {
00412 set args [lreplace $args $idx $idx]
00413 }
00414
00415 ##
00416 ## If a value was given, then set it
00417 ##
00418 if {[llength $args] != 0} {
00419
00420 set val_ [lindex $args 0]
00421
00422 set [Ns $inst_]values($inst_,$var_) $val_
00423 }
00424
00425 return [set [Ns $inst_]values($inst_,$var_)]
00426
00427 };
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 ret ::struct::record::Cmd (type inst_ , type args) {
00447
00448 variable _defn
00449
00450 set result [list]
00451
00452 set len [llength $args]
00453 if {$len <= 1} {return [Show values "$inst_"]}
00454
00455 set cmd [lindex $args 0]
00456
00457 if {[string match "cget" "$cmd"]} {
00458
00459 set cnt 0
00460 foreach k [lrange $args 1 end] {
00461 if {[catch {set r [${inst_}.[string trimleft ${k} -]]} err]} {
00462 error "Bad option \"$k\""
00463 }
00464
00465 lappend result $r
00466 incr cnt
00467 }
00468 if {$cnt == 1} {set result [lindex $result 0]}
00469 return $result
00470
00471 } elseif {[string match "config*" "$cmd"]} {
00472
00473 set L [lrange $args 1 end]
00474 foreach {k v} $L {
00475 ${inst_}.[string trimleft ${k} -] $v
00476 }
00477
00478 } else {
00479 error "Wrong argument.
00480 must be \"object cget|configure args\""
00481 }
00482
00483 return [list]
00484
00485 };
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 ret ::struct::record::Ns (type inst_) {
00502
00503 variable _defn
00504
00505 if {[catch {set ret $_defn($inst_)} err]} {
00506 return $inst_
00507 }
00508
00509 return [format "%s%s%s" "::struct::record" $ret "::"]
00510
00511 };
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 ret ::struct::record::Show (type what_ , optional record_ ="") {
00535
00536 variable _recorddefn
00537 variable _defn
00538 variable _defaults
00539
00540 ##
00541 ## We just prepend :: to the record_ argument
00542 ##
00543 if {![string match "::*" "$record_"]} {set record_ "::$record_"}
00544
00545 if {[string match "record*" "$what_"]} {
00546 return [lsort [array names _recorddefn]]
00547 } elseif {[string match "mem*" "$what_"]} {
00548
00549 if {[string match "" "$record_"] || ![info exists _recorddefn($record_)]} {
00550 error "Bad arguments while accessing members. Bad record name"
00551 }
00552
00553 set res [list]
00554 set cnt 0
00555 foreach m $_recorddefn($record_) {
00556 set def [lindex $_defaults($record_) $cnt]
00557 if {[regexp -- {([\w]+)::([\w]+)} $m m d i]} {
00558 lappend res [list record $d $i]
00559 } elseif {![string match "" "$def"]} {
00560 lappend res [list $m $def]
00561 } else {
00562 lappend res $m
00563 }
00564
00565 incr cnt
00566 }
00567
00568 return $res
00569
00570 } elseif {[string match "inst*" "$what_"]} {
00571
00572 if {![info exists ::struct::record${record_}::instances]} {
00573 return [list]
00574 }
00575 return [lsort [set ::struct::record${record_}::instances]]
00576
00577 } elseif {[string match "val*" "$what_"]} {
00578
00579 set ns $_defn($record_)
00580
00581 if {[string match "" "$record_"] || ([lsearch [set [Ns $record_]instances] $record_] < 0)} {
00582
00583 error "Wrong arguments to values. Bad instance name"
00584 }
00585
00586 set ret [list]
00587 foreach k $_recorddefn($ns) {
00588
00589 set v [set [Ns $record_]values($record_,$k)]
00590
00591 if {[regexp -- {([\w]*)::([\w]*)} $k m def inst]} {
00592 set v [::struct::record::Show values ${record_}.${inst}]
00593 }
00594
00595 lappend ret -[namespace tail $k] $v
00596 }
00597 return $ret
00598
00599 }
00600
00601 return [list]
00602
00603 };
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 ret ::struct::record::Delete (type sub_ , type item_) {
00622
00623 variable _recorddefn
00624 variable _defn
00625 variable _count
00626 variable _defaults
00627
00628 ##
00629 ## We just semi-blindly prepend :: to the record_ argument
00630 ##
00631 if {![string match "::*" "$item_"]} {set item_ "::$item_"}
00632
00633 switch -- $sub_ {
00634
00635 instance -
00636 instances -
00637 inst {
00638
00639
00640 if {[Exists instance $item_]} {
00641
00642 set ns $_defn($item_)
00643 foreach A [info commands ${item_}.*] {
00644 Delete inst $A
00645 }
00646
00647 catch {
00648 foreach {k v} [array get [Ns $item_]values $item_,*] {
00649
00650 unset [Ns $item_]values($k)
00651 }
00652 set i [lsearch [set [Ns $item_]instances] $item_]
00653 set [Ns $item_]instances [lreplace [set [Ns $item_]instances] $i $i]
00654 unset _defn($item_)
00655 }
00656
00657 # Auto-generated id numbers increase monotonically.
00658 # Reverting here causes the next auto to fail, claiming
00659 # that the instance exists.
00660 # incr _count($ns) -1
00661
00662 } else {
00663 #error "$item_ is not a instance"
00664 }
00665 }
00666 record -
00667 records {
00668
00669
00670 ##
00671 ## Delete the instances for this
00672 ## record
00673 ##
00674 foreach I [Show instance "$item_"] {
00675 catch {Delete instance "$I"}
00676 }
00677
00678 catch {
00679 unset _recorddefn($item_)
00680 unset _defaults($item_)
00681 unset _count($item_)
00682 namespace delete ::struct::record${item_}
00683 }
00684
00685
00686 }
00687 default {
00688 error "Wrong arguments to delete"
00689 }
00690
00691 }; # end switch
00692
00693 catch { uplevel #0 [list interp alias {} $item_ {}]}
00694
00695 return
00696
00697 };
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 ret ::struct::record::Exists (type sub_ , type item_) {
00716
00717
00718 switch -glob -- $sub_ {
00719 inst* {
00720
00721 if {([lsearch ::[Ns $item_]instances $item_] >=0) || [llength [info commands ::${item_}.*]]} {
00722 return 1
00723 } else {
00724 return 0
00725 }
00726 }
00727 record {
00728
00729 set item_ "::$item_"
00730 if {[info exists _recorddefn($item_)] || [llength [info commands ${item_}]]} {
00731 return 1
00732 } else {
00733 return 0
00734 }
00735 }
00736 default {
00737 error "Wrong arguments. Must be exists record|instance target"
00738 }
00739 }; # end switch
00740
00741 };
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760 ret ::struct::record::Qualify (type item_ , optional level_ =2) {
00761
00762 if {![string match "::*" "$item_"]} {
00763 set ns [uplevel $level_ [list namespace current]]
00764
00765 if {![string match "::" "$ns"]} {
00766 append ns "::"
00767 }
00768
00769 set item_ "$ns${item_}"
00770 }
00771
00772 return "$item_"
00773
00774 };
00775
00776
00777
00778
00779 namespace ::struct {
00780
00781 namespace import -force record::record
00782 namespace export record
00783 }
00784 package provide struct::record 1.2.1
00785