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