1[comment {-*- tcl -*-}] 2[manpage_begin struct::record n 1.2.1] 3[copyright {2002, Brett Schwarz <brett_schwarz@yahoo.com>}] 4[moddesc {Tcl Data Structures}] 5[titledesc {Define and create records (similar to 'C' structures)}] 6[category {Data structures}] 7[require Tcl 8.2] 8[require struct::record [opt 1.2.1]] 9[description] 10 11The [cmd ::struct::record] package provides a mechanism to group variables together 12as one data structure, similar to a 'C' structure. The members of a 13record can be variables or other records. However, a record can not contain circular 14record, i.e. records that contain the same record as a 15member. 16 17[para] 18This package was structured so that it is very similar to how Tk objects work. Each record 19definition creates a record object that encompasses that definition. Subsequently, that 20record object can create instances of that record. These instances can then 21be manipulated with the [method cget] and [method configure] methods. 22 23[para] 24The package only contains one top level command, but several sub commands (see below). It also obeys the namespace in which the record was define, hence the objects returned are fully qualified. 25 26[list_begin definitions] 27 28[call [cmd {record define}] [arg recordName] [arg recordMembers] [opt [arg "instanceName1 instanceName2 ..."]]] 29 30Defines a record. [arg recordName] is the name of the record, and is also 31used as an object command. This object command is used to create instances of the 32record definition. [arg recordMembers] are the members of 33the record that make up the record definition. These are variables 34and other record. If optional [arg instanceName] args are given, then an instance 35is generated after the definition is created for each [arg instanceName]. 36 37[call [cmd {record show}] [arg record]] 38 39Returns a list of records that have been defined. 40 41[call [cmd {record show}] [arg instances] [arg recordName]] 42 43Returns the instances that have been instantiated by 44[arg recordName]. 45 46[call [cmd {record show}] [arg members] [arg recordName]] 47 48Returns the members that are defined for 49record [arg recordName]. It returns the same format as how the 50records were defined. 51 52[call [cmd {record show}] [arg values] [arg instanceName]] 53 54Returns a list of values that are set for the instance 55[arg instanceName]. The output is a list of key/value pairs. If there 56are nested records, then the values of the nested records will 57itself be a list. 58 59[call [cmd {record exists}] [arg record] [arg recordName]] 60 61Tests for the existence of a [arg record] with the 62name [arg recordName]. 63 64[call [cmd {record exists}] [arg instance] [arg instanceName]] 65 66Tests for the existence of a [arg instance] with the 67name [arg instanceName]. 68 69[call [cmd {record delete}] [arg record] [arg recordName]] 70 71Deletes [arg recordName], and all instances of [arg recordName]. It will return 72an error if the record does not exist. 73 74[call [cmd {record delete}] [arg instance] [arg instanceName]] 75 76Deletes [arg instance] with the name of [arg instanceName]. It 77will return an error if the instance does not exist. 78 79[list_end] 80[para] 81 82[section {RECORD MEMBERS}] 83 84Record members can either be variables, or other records, However, the 85same record can not be nested witin itself (circular). To define a 86nested record, you need to specify the [const record] keyword, along 87the with name of the record, and the name of the instance of that 88nested record. For example, it would look like this: 89 90[para] 91[example_begin] 92# this is the nested record 93record define mynestedrecord { 94 nest1 95 nest2 96} 97 98# This is the main record 99record define myrecord { 100 mem1 101 mem2 102 {record mynestedrecord mem3} 103} 104 105[example_end] 106 107You can also assign default or initial values to the members of a record, 108by enclosing the member entry in braces: 109 110[para] 111[example_begin] 112 113record define myrecord { 114 mem1 115 {mem2 5} 116} 117 118[example_end] 119 120All instances created from this record definition, will initially have 5 as 121the value for [arg mem2]. If no default is given, then the value will be the empty string. 122 123[para] 124[emph {Getting Values}] 125[para] 126 127To get a value of a member, there are several ways to do this. 128 129[list_begin enumerated] 130 131[enum] 132To get a member value, then use the instance built-in [method cget] method: 133[para] 134 [arg instanceName] [method cget] -mem1 135 136[enum] 137To get multiple member values, you can specify them all in one command: 138[para] 139 [arg instanceName] [method cget] -mem1 -mem2 140 141[enum] 142To get a list of the key/value of all of the members, there are 3 ways: 143[para] 144 - [arg instanceName] [method cget] 145[para] 146 - [arg instanceName] [method configure] 147[para] 148 - [arg instanceName] 149 150[enum] 151To get a value of a nested member, then use the dot notation: 152[para] 153 [arg instanceName] [method cget] -mem3.nest1 154 155[list_end] 156 157[para] 158[emph {Setting Values}] 159[para] 160 161To set a value of a member, there are several ways to do this. 162 163[list_begin enumerated] 164 165[enum] 166To set a member value, then use the instance built-in [method configure] method: 167[para] 168 [arg instanceName] [method configure] -mem1 val1 169 170[enum] 171To set multiple member values, you can specify them all in one command: 172[para] 173 [arg instanceName] [method configure] -mem1 va1 -mem2 val2 174 175[enum] 176To set a value of a nested member, then use the dot notation: 177[para] 178 [arg instanceName] [method configure] -mem3.nest1 value 179 180[list_end] 181 182[para] 183[emph {Alias access}] 184[para] 185 186In the original implementation, access was done by using dot notation similar to how 'C' structures are accessed. However, 187there was a concensus to make the interface more Tcl like, which made sense. However, the original alias access still 188exists. It might prove to be helpful to some. 189 190[para] 191Basically, for every member of every instance, an alias is created. This alias is used to get and set values for that 192member. An example will illustrate the point, using the above defined records: 193 194[para] 195[example_begin] 196# Create an instance first 197% myrecord inst1 198::inst1 199% # To get a member of an instance, just use the 200% # alias (it behaves like a Tcl command): 201% inst1.mem1 202% 203% # To set a member via the alias, just include 204% # a value (optionally the equal sign - syntactic sugar) 205% inst1.mem1 = 5 2065 207% inst1.mem1 2085 209% # For nested records, just continue with the 210% # dot notation (note no equal sign) 211% inst1.mem3.nest1 10 21210 213% inst1.mem3.nest1 21410 215% # just the instance by itself gives all 216% # member/values pairs for that instance 217% inst1 218-mem1 5 -mem2 {} -mem3 {-nest1 10 -nest2 {}} 219% # and to get all members within the nested record 220% inst1.mem3 221-nest1 10 -nest2 {} 222% 223 224[example_end] 225 226[section {RECORD COMMAND}] 227 228The following subcommands and corresponding arguments are available to any 229record command: 230 231[list_begin definitions] 232 233[call [arg recordName] [method [arg instanceName|#auto]] [opt [arg "-member1 value1 -member2 value2 ..."]]] 234 235Using the [arg recordName] object command that was created from the record definition, 236instances of the record definition can be created. Once a instance is 237created, then it inherits the members of the record definition, very 238similar to how objects work. During instance generation, an object command for the instance 239is created as well, using [arg instanceName]. This object command is used 240to access the data members of the instance. During the instantiation, values for 241that instance can be given, [emph but] all values must be given, and be given 242in key/value pairs. Nested records, need to be in list format. 243 244[para] 245Optionally, [arg #auto] can be used in place of [arg instanceName]. When #auto is used, 246then a instance name will automatically be generated, of the form recordName<integer>, where 247<integer> is a unique integer (starting at 0) that is generated. 248 249[list_end] 250[para] 251 252[section {INSTANCE COMMAND}] 253 254The following subcommands and corresponding arguments are available to 255any record instance command: 256 257[list_begin definitions] 258 259[call [arg instanceName] [method cget] [opt [arg "-member1 -member2 ..."]]] 260 261Each instance has the sub command [method cget] associated with it. This 262is very similar to how Tk widget's cget command works. It queries 263the values of the member for that particular instance. If 264no arguments are given, then a key/value list is returned. 265 266[call [arg instanceName] [method configure] [opt [arg "-member1 value1 -member2 value2 ..."]]] 267 268Each instance has the sub command [method configure] associated with it. This 269is very similar to how Tk widget's configure command works. It sets 270the values of the particular member for that particular instance. If 271no arguments are given, then a key/value list is returned. 272 273[list_end] 274 275[section EXAMPLES] 276 277Two examples are provided to give an good illustration on how to use 278this package. 279 280[para] 281[emph {Example 1}] 282[para] 283 284Probably the most obvious example would be to hold contact information, 285such as addresses, phone numbers, comments, etc. Since a person can have 286multiple phone numbers, multiple email addresses, etc, we will use nested 287records to define these. So, the first thing we do is define the nested 288records: 289 290[para] 291[example { 292 293## 294## This is an interactive example, to see what is 295## returned by each command as well. 296## 297 298% namespace import ::struct::record::* 299 300% # define a nested record. Notice that country has default 'USA'. 301% record define locations { 302 street 303 street2 304 city 305 state 306 zipcode 307 {country USA} 308 phone 309} 310::locations 311% # Define the main record. Notice that it uses the location record twice. 312% record define contacts { 313 first 314 middle 315 last 316 {record locations home} 317 {record locations work} 318} 319::contacts 320% # Create an instance for the contacts record. 321% contacts cont1 322::cont1 323% # Display some introspection values 324% record show records 325::contacts ::locations 326% # 327% record show values cont1 328-first {} -middle {} -last {} -home {-street {} -street2 {} -city {} -state {} -zipcode {} -country USA -phone {}} -work {-street {} -street2 {} -city {} -state {} -zipcode {} -country USA -phone {}} 329% # 330% record show instances contacts 331::cont1 332% # 333% cont1 config 334-first {} -middle {} -last {} -home {-street {} -street2 {} -city {} -state {} -zipcode {} -country USA -phone {}} -work {-street {} -street2 {} -city {} -state {} -zipcode {} -country USA -phone {}} 335% # 336% cont1 cget 337-first {} -middle {} -last {} -home {-street {} -street2 {} -city {} -state {} -zipcode {} -country USA -phone {}} -work {-street {} -street2 {} -city {} -state {} -zipcode {} -country USA -phone {}} 338% # copy one record to another record 339% record define contacts2 [record show members contacts] 340::contacts2 341% record show members contacts2 342first middle last {record locations home} {record locations work} 343% record show members contacts 344first middle last {record locations home} {record locations work} 345% 346}] 347 348[para] 349[emph {Example 1}] 350[para] 351 352This next example just illustrates a simple linked list 353[para] 354[example { 355 356% # define a very simple record for linked list 357% record define llist { 358 value 359 next 360} 361::llist 362% llist lstart 363::lstart 364% lstart config -value 1 -next [llist #auto] 365% [lstart cget -next] config -value 2 -next [llist #auto] 366% [[lstart cget -next] cget -next] config -value 3 -next "end" 367% set next lstart 368lstart 369% while 1 { 370lappend values [$next cget -value] 371set next [$next cget -next] 372if {[string match "end" $next]} {break} 373} 374% puts "$values" 3751 2 3 376% # cleanup linked list 377% # We could just use delete record llist also 378% foreach I [record show instances llist] { 379record delete instance $I 380} 381% record show instances llist 382% 383 384}] 385 386[para] 387 388[section {BUGS, IDEAS, FEEDBACK}] 389 390This document, and the package it describes, will undoubtedly contain 391bugs and other problems. 392 393Please report such in the category [emph {struct :: record}] of the 394[uri {http://sourceforge.net/tracker/?group_id=12883} {Tcllib SF Trackers}]. 395 396Please also report any ideas for enhancements you may have for either 397package and/or documentation. 398 399 400[keywords struct record {data structures}] 401[manpage_end] 402