1 <!doctype linuxdoc system>
4 $Id: ir-tcl.sgml,v 1.34 2004-04-26 09:09:06 adam Exp $
8 <title>IrTcl User's Guide and Reference
9 <author><htmlurl url="http://www.indexdata.dk/" name="Index Data">,
10 <tt><htmlurl url="mailto:info@indexdata.dk" name="info@indexdata.dk"></tt>
11 <date>$Date: 2004-04-26 09:09:06 $
13 IrTcl version 1.4.2 -- a Tcl extension that allows you to build
22 This document describes the <sf/IrTcl/ information retrieval toolkit,
23 which offers a high-level interface for the development of Z39.50
24 clients. The toolkit is based on the Tcl/Tk toolkit developed by Prof. John
25 K. Ousterhout at the University of California [ref 1].
26 The core of Tcl is rather small but it offers a flexible C API
27 for easy development of Tcl extensions. The most important Tcl
28 extension is probably Tk -- A portale GUI for X/WIN32/MAC.
30 To interface the Z39.50 protocol <sf/IrTcl/ uses the <bf/YAZ/ toolkit.
32 <sf/IrTcl/ is usually build as a <it/dynamic/ library (WIN32)
33 or a shared object (Unix) which is dynamically loaded by using the Tcl's
34 <tt/load/ command. However, <sf/IrTcl/ can also be compiled as a
35 traditional <it/static/ library.
37 <sect>Compilation and installation
42 In order to compile the software on UNIX you need:
44 <item> An ANSI C compiler such as GNU C.
45 <item> <htmlurl url="http://www.scriptics.com" name="Tcl">.
46 Version 8.0 and 8.3 has been tested.
47 <item> <htmlurl url="http://www.indexdata.dk/yaz/" name="YAZ">
48 version 1.6 or higher.
51 Unpack the <sf/IrTcl/ package at the same directory level as <bf/YAZ/.
58 This command tries to configure <sf/IrTcl/ for your system and creates
61 The <tt>configure</tt> script tries to locate the file <tt/tclConfig.sh/
62 which should be generated by Tcl's installation script. Configure
63 looks for ther Tcl shell on your system in order to locate this file.
64 For example if <tt/tclsh/ is located in <tt>/home/joe/bin</tt>, configure will
65 assume that <tt>tclConfig.sh</tt> is installed in <tt>/home/joe/lib</tt>,
66 in which case the prefix is <tt>/home/joe</tt>. If you have
67 more than one Tcl version installed on your system, or if configure
68 cannot find the <tt/tclConfig.sh/, you can specify in which directory
69 it is, by supplying option <tt>--with-tclconfig</tt> - for example:
71 $ ./configure --with-tclconfig=/home/joe/lib
74 The <sf/IrTcl/ executables are installed in prefix/bin and libraries
75 and support files are installed in prefix/irtcl.
77 Compile <sf/IrTcl/ by typing:
82 For Tcl versions that support dynamic libraries the command above
83 will create the shared library, <tt/irtcl.so/, as well as the
84 normal static library, <tt/libirtcl.a/.
86 For Tcl versions that doesn't support dynamic libraries the
87 make command will create two shells will build-in <sf/IrTcl/ support --
88 a Tcl shell called <tt/ir-tcl/. The traditional static
89 library, <tt/libirtcl.a/, is build as well.
91 To install the programs and support files type:
96 If you wish to install man pages type:
101 Summary of files installed (the names refer to the Makefile variables):
104 <tag><tt>irtcl.so</tt></tag> The <sf/IrTcl/ shared dynamic library.
105 The actual name of this library vary. Installed in <tt>IRTCLDIR</tt>.
106 This file is only generated when using newer versions of Tcl/Tk.
108 <tag><tt>ir-tcl</tt></tag> The <sf/IrTcl/ shell for Tcl. This program
109 is not needed when using a Tcl that supports shared libraries. Installed
110 in <tt>BINDIR</tt> -- defaults to <tt>/usr/local/bin</tt>.
112 <tag><tt>client.tcl</tt></tag> A graphical client for Tk.
113 The client is installed as an executable script called <tt>irclient</tt> in
114 <tt>BINDIR</tt>. This client needs a number of files, bitmaps, etc.
115 The client looks for the files in the current directory &mdash if
116 this fails it tries to look in the directory <tt>IRTCLDIR</tt>
117 -- defaults to <tt>/usr/local/lib/irtcl</tt>.
119 <tag><tt>libirtcl.a</tt></tag> The <sf/IrTcl/ library.
120 Installed in <tt>LIBDIR</tt> -- defaults to <tt>/usr/local/lib</tt>.
122 <tag><tt>ir-tcl.h</tt></tag> The <sf/IrTcl/ header file.
123 Installed in <tt>INCDIR</tt> -- defaults to <tt>/usr/local/include</tt>.
125 <tag><tt>irtdb.tcl</tt></tag> A setup file with definitions
126 of target and queries. Read and updated by <tt>client.tcl</tt>. Installed
127 in <tt>IRTCLDIR</tt> -- defaults to <tt>/usr/local/lib/irtcl</tt>.
129 <tag><tt>formats/*</tt></tag> Display format files written
130 in Tk. Read by <tt>client.tcl</tt>. Installed
131 in <tt>IRTCLDIR</tt> -- defaults to <tt>/usr/local/lib/irtcl</tt>.
133 <tag><tt>bitmaps/*</tt></tag> Various bitmap files. Read by
134 <tt>client.tcl</tt>. Installed
135 in <tt>IRTCLDIR</tt> -- defaults to <tt>/usr/local/lib/irtcl</tt>.
137 <tag><tt>LICENSE</tt></tag> LICENSE file. Read by
138 <tt>client.tcl</tt>. Installed
139 in <tt>IRTCLDIR</tt> -- defaults to <tt>/usr/local/lib/irtcl</tt>.
143 <sf/IrTcl/ can be used either from the Tcl interpreter
144 <tt/tclsh/ or the statically linked program <tt/ir-tcl/.
145 Using <tt/tclsh/ is the preferred method. You must load
146 the <sf/IrTcl/ library by using the <tt/load/ command.
148 A static, non-dynamic, version goes like this:
153 and the dynamic version (preferred) goes like:
163 <sf/IrTcl/ is shipped with a "makefile" for the NMAKE tool part of
164 with Microsoft Visual C++.
166 Start an MS-DOS prompt and switch the sub directory <tt>WIN</tt> where
167 the file <tt>makefile</tt> is located. Customize the installation
168 by editing the <tt>makefile</tt> file (for example by using wordpad).
170 The following summarises the most important settings in that
174 <tag><tt>YAZDIR</tt></tag> Specifies where YAZ is located.
175 <tag><tt>DEBUG</tt></tag> If set to 1, the software is
176 compiled with debugging libraries. If set to 0, the software
177 is compiled with release (non-debugging) libraries.
180 When satisfied with the settings in the makefile type
185 If compilation was successful the executables <tt>irtcl.dll</tt>
186 is put in directory <tt>BIN</tt>.
188 To start the test client that comes with <sf/IrTcl/ make sure
189 both <tt/YAZ.DLL/ and <tt/IRTCL.DLL/ are in current directory
190 or in your PATH. Go to the top-level directory of <sf/IrTcl/
191 and type "wish -f client.tcl". You might want to make a
192 short-cut to start this.
197 If your Tcl/Tk supports dynamic libraries you can use the
198 <tt/load/ command from within <tt/wish/ as described in the previous
201 The enclosed script <tt>client.tcl</tt> is a graphical client
202 which demonstates an example of a user interface for the Z39.50 protocol.
203 At first the script was relatively small but it has grown since the
204 beginning. At present it is about 3000 lines.
206 To start the client with dynamic library support use:
211 Note: Substitute the real name for the wish interpreter above, for
212 version 8.0 it is probably called <tt/wish8.0/.
214 The client lets up define targets and query types within the interface.
215 Hence, you will not need to modify configuration files.
217 Stuff regarding targets can be found in the pull down menu 'Target'
218 with the following options:
220 <tag>Connect</tag> Establishes connection to a target.
221 <tag>Disconnect</tag> Closes a target connection.
222 <tag>About</tag> Shows implementation Id, implementation Version, etc
223 for the current target.
224 <tag>Setup</tag> Pops up a target definition window. You may alter
226 <tag>Setup new</tag> Lets you define a new target.
229 The term query type refers to a collection of search fields. The
230 pull down menu Options|Query deals with queries. You may
231 insert/modify/remove query types.
233 <sect>Overview of the API
236 Basically, <sf/IrTcl/ is a set of commands introduced to Tcl.
237 When extending Tcl there are two approaches: action-oriented commands
238 and object-oriented commands.
240 Action-oriented commands manipulate
241 Tcl variables and each command introduces only one action.
242 The string manipulation commands in Tcl are action oriented.
244 Object-oriented commands are added for every declared
245 variable (object). Object-oriented commands usually provide a set of
246 actions (methods) to manipulate the object.
247 The widgets in Tk (X objects) are examples of the object-oriented style.
249 <sf/IrTcl/ commands are object-oriented. The main reason
250 for this is that the data structures involved in the IR protocol
251 are not easily represented by Tcl data structures.
252 Also, the <sf/IrTcl/ objects tend to exist for a relativly long time.
253 Note that although we use the term object-oriented commands, this
254 does not mean that the programming style is strictly object-oriented. For
255 example, there is such no such thing as inheritance.
257 We are now ready to present the three commands introduced to Tcl by
261 <tag/ir/ The ir object represents a connection to a target. More
262 precisely it describes a Z-association.
263 <tag/ir-set/ The ir-set describes a result set, which is
264 conceptually a collection of records returned by the target.
265 The ir-set object may retrieve records from a target by means of
266 the ir object; it may read/write records from/to a local file or it may be
267 updated with a user-edited record.
268 <tag/ir-scan/ The scan object represents a list of scan lines
269 retrieved from a target.
274 To create a new IR object called <tt/z-assoc/ write:
281 Each object provides a set of <em/settings/ which may either be
282 readable, writeable of both. All settings immediately follow
283 the name of the object. If a value is present the setting
284 is set to <em/value/.
288 We wish to set the preferred-message-size to 18000 on the
292 z-assoc preferredMessageSize 18000
295 To read the current value of preferred-message-size use:
298 z-assoc preferredMessageSize
302 One important category consists of settings is those that relate to the
303 event-driven model. When <sf/IrTcl/ receives responses from the target, i.e.
304 init responses, search responses, etc., a <em/callback/ routine
305 is called. Callback routines are represented in Tcl as
306 a list, which is re-interpreted prior to invocation.
307 The method is similar to the one used in Tk to capture X events.
309 For each Z39.50 request there is a corresponding object action. The most
310 important actions are:
312 <tag/connect/ Establishes connection with a target
313 <tag/init/ Sends an initialize request.
314 <tag/search/ Sends a search request.
315 <tag/present/ Sends a present request.
316 <tag/scan/ Sends a scan request.
321 This example shows a complete connect - init - search - present scenario.
323 First an IR object, called <tt/z/, is created.
324 Also a result set <tt/z.1/ is introduced by the <tt/ir-set/
325 and it is specified that the result set uses <tt/z/ as its association.
327 The setting <tt/databaseNames/ is set to the
328 database <tt/books/ to which the following searches are directed.
329 A callback is then defined and a connection is established to
330 <tt/fake.com/ by the <tt/connect/ action.
331 If the connect succeeds the <tt/connect-response/ is called.
333 In the Tcl procedure, <tt/connect-response/, a callback is defined
334 <em/before/ the init request is executed.
335 The Tcl procedure <tt/init-response/ is called when a
336 init response is returned from the target.
338 The <tt/init-response/ procedure sets up a <tt/search-response/
339 callback handler and sends a search-request by using a query which
340 consists of a single word <tt/science/.
342 When the <tt/search-response/ procedure is called it defines
343 a variable <tt/hits/ and sets it to the value of the setting
344 <tt/resultCount/. If <tt/hits/ is positive a present-request is
345 sent -- asking for 5 records from position 1.
347 Finally, a present response is received and the number of records
348 returned is stored in the variable <tt/ret/.
352 z databaseNames books
354 z callback {connect-response}
357 proc connect-response {} {
358 z callback {init-response}
362 proc init-response {} {
363 z callback {search-response}
367 proc search-response {} {
368 set hits [z.1 resultCount]
371 z callback {present-response}
376 proc present-response {} {
377 set ret [z.1 numberOfRecordsReturned]
378 puts "$ret records returned"
383 The previous example program doesn't care about error conditions.
384 If errors occur in the program they will be trapped by the Tcl error
385 handler. This is not always appropriate. However, Tcl offers a
386 <tt/catch/ command to support error handling by the program itself.
391 The ir object describes an association with a target.
392 This section covers the connect-init-disconnect actions provided
394 An ir object is created by the <tt/ir/ command and the
395 created object enters a 'not connected' state, because it isn't
396 connected to a target yet.
401 A connection is established by the <tt/connect/ action which is
402 immediately followed by a hostname. A number of settings affect the
403 <tt/connect/ action. Obviously, these settings should be set
404 <bf/before/ connecting. The settings are:
407 <tag><tt>comstack </tt><tt>mosi|tcpip</tt></tag>
408 Comstack type. Note that <tt/mosi/ is no longer supported by <bf/YAZ/.
409 <tag><tt>protocol </tt><tt>Z39|SR</tt></tag>
410 Protocol type - ANSI/NISO Z39.50 or ISO SR. Note, that SR
411 is no longer supported by <bf/YAZ/.
412 <tag><tt>callback </tt><em>list</em></tag>
413 Tcl script called when the connection is established.
414 <tag><tt>failback </tt><em>list</em></tag>
415 Fatal error Tcl script. Called on protocol errors or if target
419 If the connect is unsuccessful either the connect action itself
420 will return an error code or the failback handler is invoked.
422 In general, the <tt>failback</tt> handler is invoked when serious
423 unrecoverable errors occur when communicating with the target.
424 In this case the <sf/IrTcl/ system shuts down the connection.
425 The <tt>failback</tt> handler might inspect the <tt>failInfo</tt>
426 setting to determine the cause of the failure; it returns
427 two elements. The first is an error integer; the second is an
428 english representation of the error. The error codes and
429 the corresponding messages are:
432 <tag><tt>0</tt></tag>ok
433 <tag><tt>1</tt></tag>connect failed
434 <tag><tt>2</tt></tag>connection closed
435 <tag><tt>3</tt></tag>connection closed
436 <tag><tt>4</tt></tag>failed to decode incoming APDU
437 <tag><tt>5</tt></tag>unknown APDU
440 Note: in case 3 the connection was closed during read a read operation
441 whereas in case 4 it was closed during a write operation.
446 If the connect operation succeeds the <tt/init/ action should be used.
447 The init related settings are:
450 <tag><tt>preferredMessageSize </tt><em>integer</em></tag>
451 Preferred-message-size. Default value is 30000.
452 <tag><tt>maximumRecordSize </tt><em>integer</em></tag>
453 Maximum-record-size. Default value is 30000.
454 <tag><tt>idAuthentication </tt><em>string</em> ...</tag>
455 Id-authentication. There are three forms. If any empty is
456 given, the Id-authentication is not used. If one non-empty string
457 is given, the 'open' authentication is used. If three strings are
458 specified, the version 'id-pass' authentication (version 3 only)
459 is used in which case the first string is groupId; the second string
460 is userId and the third string is password.
461 <tag><tt>implementationName </tt><em>string</em></tag>
462 Implementation-name of origin system.
463 <tag><tt>implementationId</tt></tag>
464 Implementation-id of origin system. This setting is read-only.
465 <tag><tt>implementationVersion</tt></tag>
466 Implementation-version of origin system. This settings is read-only.
467 <tag><tt>options </tt><em>list</em></tag>
468 Options to be negotiated in the init service. The list contains
469 the options that are set. Possible values are <tt>search</tt>,
470 <tt>present</tt>, <tt>delSet</tt>, <tt>resourceReport</tt>,
471 <tt>triggerResourceCtrl</tt>, <tt>resourceCtrl</tt>,
472 <tt>accessCtrl</tt>, <tt>scan</tt>, <tt>sort</tt>,
473 <tt>extendedServices</tt>, <tt>level-1Segmentation</tt>,
474 <tt>level-2Segmentation</tt>, <tt>concurrentOperations</tt> and
475 <tt>namedResultSets</tt>. Currently the default options are:
476 <tt>search</tt>, <tt>present</tt>, <tt>scan</tt> and
477 <tt>namedResultSets</tt>. The <tt>options</tt> setting is set to its default
478 value when an ir object is created and when a <tt>disconnect</tt>
480 <tag><tt>protocolVersion </tt><em>integer</em></tag>
481 Protocol version: 2, 3, etc. Default is 2.
482 <tag><tt>referenceId </tt><em>string</em></tag>
483 Reference-id of init operation. If <em>string</em> is empty no
484 reference-id is used.
485 <tag><tt>initResponse </tt><em>list</em></tag>
486 Init-response Tcl script.
487 <tag><tt>callback </tt><em>list</em></tag>
488 General response Tcl script. Only used if <tt>initResponse</tt>
492 The init-response handler should inspect some of the settings shown
496 <tag><tt>initResult </tt>returns <em>boolean</em></tag>
497 Init response status. True if init operation was successful;
499 <tag><tt>preferredMessageSize </tt>returns <em>integer</em></tag>
500 Preferred-message-size after negotiation.
501 <tag><tt>maximumRecordSize </tt>returns <em>integer</em></tag>
502 Maximum-record-size after negotiation.
503 <tag><tt>targetImplementationName </tt>returns <em>string</em></tag>
504 Implementation-name of target system.
505 <tag><tt>targetImplementationId </tt>returns <em>string</em></tag>
506 Implementation-id of target system.
507 <tag><tt>targetImplementationVersion </tt>returns <em>string</em></tag>
508 Implementation-version of target system.
509 <tag><tt>options </tt>returns <em>list</em></tag>
510 Options after negotiation. The list contains the options that are set.
511 <tag><tt>protocolVersion </tt>returns <em>integer</em></tag>
512 Protocol version: 2, 3, etc after negotiation.
513 <tag><tt>userInformationField </tt>returns <em>string</em></tag>
514 User information field.
515 <tag><tt>referenceId </tt>returns <em>string</em></tag>
516 Reference-id of init response.
521 Consider a client with the ability to access multiple targets.
523 We define a list of targets that we wish to connect to.
524 Each item in the list describes the target parameters with
525 the following four components: association-name, comstack-type,
526 protocol-type and a hostname.
528 The list for the two targets: Library of Congress and Z39.50
529 target Data Research, will be defined as:
531 set targetList { {loc tcpip Z39 z3950.loc.gov:7090}
532 {drs tcpip Z39 dranet.dra.com} }
535 The Tcl code below defines, connect and initialize the
536 targets in <tt/targetList/:
539 foreach target $targetList {
540 set assoc [lindex $target 0]
542 $assoc comstack [lindex $target 1]
543 $assoc protocol [lindex $target 2]
544 $assoc failback [list fail-response $assoc]
545 $assoc callback [list connect-response $assoc]
546 $assoc connect [lindex $target 3]
549 proc connect-response {assoc} {
550 $assoc callback [list init-response $assoc]
554 proc fail-response {assoc} {
555 puts "$assoc closed connection or protocol error"
558 proc init-response {assoc} {
559 if {[$assoc initResult]} {
560 puts "$assoc initialized ok"
562 puts "$assoc didn't initialize"
567 <tt/target/ is bound to each item in the list of targets.
568 The <tt/assoc/ is set to the ir object name.
569 Then, the comstack, protocol and failback are set for the <tt/assoc/ object.
570 The ir object name is argument to the <tt/fail-response/ and
571 <tt/connect-response/ routines.
572 Note the use of the Tcl <tt/list/ command which
573 is necessary here because the argument contains variables
574 (<tt/assoc/) that should be substituted before the handler is defined.
575 After the connect operation, the <tt/init-response/ handler
576 is defined in much the same way as the failback handler.
577 And, finally, an init request is executed.
584 To terminate the connection the <tt/disconnect/ action should be used.
585 This action has no parameters.
586 Another connection may be established by a new <tt/connect/ action on
592 This section covers the queries used by <sf/IrTcl/, and how searches and
593 presents are handled.
595 A search operation and a result set is described by the ir set object.
596 The ir set object is defined by the <tt/ir-set/ command which
597 has two parameters. The first is the name of the new ir set object, and
598 the second, which is optional, is the name of an assocation -- an ir
599 object. The second argument is required if the ir set object should be able
600 to perform searches and presents. However, it is not required if
601 only ``local'' operations is done with the ir set object.
603 When the ir set object is created a number of settings are inherited
604 from the ir object, such as the selected databass, query type,
605 etc. Thus, the ir object contains what we could call default
611 Search requests are sent by the <tt/search/ action which
612 takes a query as parameter. There are two types of queries,
613 RPN and CCL, controlled by the setting <tt/queryType/.
614 A string representation for the query is used in <sf/IrTcl/ since
615 Tcl has reasonably powerful string manipulaton capabilities.
616 The RPN query used in <sf/IrTcl/ is the prefix query notation also used in
617 the <bf/YAZ/ test client.
619 The CCL query is an uninterpreted octet-string which is parsed by the target.
620 We refer to the standard: ISO 8777. Note that only a few targets
621 actually support the CCL query and the interpretation of
622 the standard may vary.
624 The prefix query notation (which is converted to RPN) offer a few
628 <tag><tt>@attr </tt><em>list op</em></tag>
629 The attributes in list are applied to op
630 <tag><tt>@and </tt><em>op1 op2</em></tag>
631 Boolean <em/and/ on op1 and op2
632 <tag><tt>@or </tt><em>op1 op2</em></tag>
633 Boolean <em/or/ on op1 and op2
634 <tag><tt>@not </tt><em>op1 op2</em></tag>
635 Boolean <em/not/ on op1 and op2
636 <tag><tt>@prox </tt><em>list op1 op2</em></tag>
637 Proximity operation on op1 and op2. Not implemented yet.
638 <tag><tt>@set </tt><em>name</em></tag>
640 <tag><tt>@attrset </tt><em>set</em></tag>
641 Whole query uses the specified attribute <em>set</em>. If this operator is
642 used it must be defined at the beginning of the query.
645 It is simple to build RPN queries in <sf/IrTcl/. Search terms
646 are sequences of characters, as in:
651 Boolean operators use the prefix notation (instead of the suffix/RPN),
654 @and science technology
657 Search terms may be associated with attributes. These
658 attributes are indicated by the <tt/@attr/ operator.
659 Assuming the bib-1 attribute set, we can set the use-attribute
660 (type is 1) to title (value is 4):
666 Also, it is possible to apply attributes to a range of search terms.
667 In the query below, both search terms have use=title but the <tt/tech/
668 term is right truncated:
671 @attr 1=4 @and @attr 5=1 tech beta
674 To search for the DatabaseInfo records from an Explain server, we
677 @attrset exp1 @attr 1=1 DatabaseInfo
683 The settings that affect the search are listed below:
686 <tag><tt>databaseNames </tt><em>list</em></tag>
688 <tag><tt>smallSetUpperBound </tt><em>integer</em></tag>
689 Small set upper bound. Default 0.
690 <tag><tt>largeSetLowerBound </tt><em>integer</em></tag>
691 Large set lower bound. Default 1.
692 <tag><tt>mediumSetPresentNumber </tt><em>integer</em></tag>
693 Medium set present number. Default 0.
694 <tag><tt>replaceIndicator </tt><em>boolean</em></tag>
695 Replace-indicator. Default true (1).
696 <tag><tt>setName </tt><em>string</em></tag>
697 Name of result set. Default name of set is <tt/default/.
698 <tag><tt>queryType rpn|ccl</tt></tag>
699 Query type-1 or query type-2. Default rpn (type-1).
700 <tag><tt>preferredRecordSyntax </tt><em>string</em></tag>
701 Preferred record syntax -- UNIMARC, USMARC, etc.
702 <tag><tt>smallSetElementSetNames </tt><em>string</em></tag>
703 small-set-element-set names. If <em>string</em> is empty
704 the element set is not set. Default is empty (not set).
705 <tag><tt>mediumSetElementSetNames </tt><em>string</em></tag>
706 medium-set-element-set names. If <em>string</em> is empty
707 the element set is not set. Default is empty (not set).
708 <tag><tt>nextResultSetPosition </tt>returns <em>integer</em></tag>
709 Next result set position.
710 <tag><tt>referenceId </tt><em>string</em></tag>
711 Reference-id. If <em>string</em> is empty no reference-id is used.
712 <tag><tt>searchResponse </tt><em>list</em></tag>
713 Search-response Tcl script.
714 <tag><tt>callback </tt><em>list</em></tag>
715 General response Tcl script. Only used if searchResponse is not specified.
716 This setting is valid only for the <tt/ir/ object -- not the
720 Setting the <tt/databaseNames/ is mandatory. All other settings
721 have reasonable defaults.
722 The search-response handler, specified by the <tt/callback/ - or
723 the <tt/searchResponse/ setting,
724 should read some of the settings shown below:
727 <tag><tt>searchStatus</tt> returns <em>boolean</em></tag>
728 Search-status. True if search operation was successful; false
730 <tag><tt>responseStatus </tt>returns <em>list</em></tag>
731 Response status information.
732 <tag><tt>resultCount </tt>returns <em>integer</em></tag>
734 <tag><tt>numberOfRecordsReturned </tt>returns <em>integer</em></tag>
735 Number of records returned.
736 <tag><tt>referenceId </tt>returns <em>string</em></tag>
737 Reference-id of search response.
740 The <tt/responseStatus/ signals one of three conditions which
741 is indicated by the value of the first item in the list:
744 <tag><tt>NSD</tt></tag> indicates that the target has returned one or
745 more non-surrogate diagnostic messages. The <tt/NSD/ item is followed by
746 a list with all non-surrogate messages. Each non-surrogate message consists
747 of three items. The first item of the three items is the error
748 code (integer); the next item is a textual representation of the error
749 code in plain english; the third item is additional information, possibly
750 empty if no additional information was returned by the target.
752 <tag><tt>DBOSD</tt></tag> indicates a successful operation where the
753 target has returned one or more records. Each record may be
754 either a database record or a surrogate diagnostic.
756 <tag><tt>OK</tt></tag> indicates a successful operation -- no records are
757 returned from the target.
762 We continue with the multiple-targets example.
763 The <tt/init-response/ procedure will attempt to make searches:
766 proc init-response {assoc} {
767 puts "$assoc connected"
768 ir-set ${assoc}.1 $assoc
769 $assoc.1 queryType rpn
770 $assoc.1 databaseNames base-a base-b
771 $assoc callback [list search-response $assoc ${assoc}.1]
772 $assoc.1 search "@attr 1=4 @and @attr 5=1 tech beta"
776 An ir set object is defined and the
777 ir object is told about the name of ir object.
778 The ir set object use the name of the ir object as prefix.
780 Then, the query-type is defined to be RPN, i.e. we will
781 use the prefix query notation later on.
783 Two databases, <tt/base-a/ and <tt/base-b/, are selected.
785 A <tt/search-response/ handler is defined with the
786 ir object and the ir-set object as parameters and
787 the search is executed.
789 The first part of the <tt/search-response/ looks like:
791 proc search-response {assoc rset} {
792 set status [$rset responseStatus]
793 set type [lindex $status 0]
794 if {$type == "NSD"} {
795 set code [lindex $status 1]
796 set msg [lindex $status 2]
797 set addinfo [lindex $status 3]
798 puts "NSD $code: $msg: $addinfo"
801 set hits [$rset resultCount]
802 if {$type == "DBOSD"} {
803 set ret [$rset numberOfRecordsReturned]
808 The response status is stored in variable <tt/status/ and
809 the first element indicates the condition.
810 If non-surrogate diagnostics are returned they are displayed.
811 Otherwise, the search was a success and the number of hits
812 is read. Finally, it is tested whether the search response
813 returned records (database or diagnostic).
815 Note that we actually didn't inspect the search status (setting
816 <tt/searchStatus/) to determine whether the search was successful or not,
817 because the standard specifies that one or more non-surrogate
818 diagnostics should be returned by the target in case of errors.
822 If one or more records are returned from the target they
823 will be stored in the result set object.
824 In the case in which the search response contains records, it is
825 very similar to the present response case. Therefore, some settings
826 are common to both situations.
831 The <tt/present/ action sends a present request. The <tt/present/ is
832 followed by two optional integers. The first integer is the
833 result-set starting position -- defaults to 1. The second integer
834 is the number of records requested -- defaults to 10.
835 The settings which could be modified before a <tt/present/
839 <tag><tt>preferredRecordSyntax </tt><em>string</em></tag>
840 preferred record syntax -- UNIMARC, USMARC, etc.
841 <tag><tt>elementSetNames </tt><em>string</em></tag>
842 Element-set names. If <em>string</em> is empty
843 the element set is not set. Default is empty (not set).
844 <tag><tt>referenceId </tt><em>string</em></tag>
845 Reference-id. If <em>string</em> is empty no reference-id is used.
846 <tag><tt>presentResponse </tt><em>list</em></tag>
847 Present-response Tcl script.
848 <tag><tt>callback </tt><em>list</em></tag>
849 General response Tcl script. Only used if presentResponse is not specified
850 This setting is valid only for the <tt/ir/ object -- not the
854 The present-response handler should inspect the settings
855 shown in table below.
856 Note that <tt/responseStatus/ and <tt/numberOfRecordsReturned/
857 settings were also used in the search-response case.
859 As in the search response case, records returned from the
860 target are stored in the result set object.
863 <tag><tt>presentStatus </tt>returns <em>boolean</em></tag>
865 <tag><tt>responseStatus </tt>returns <em>list</em></tag>
866 Response status information.
867 <tag><tt>numberOfRecordsReturned </tt>returns <em>integer</em></tag>
868 Number of records returned.
869 <tag><tt>nextResultSetPosition </tt>returns <em>integer</em></tag>
870 Next result set position.
871 <tag><tt>referenceId </tt>returns <em>string</em></tag>
872 Reference-id of present response.
878 Search responses and present responses may result in
879 one or more records stored in the ir set object if
880 the <tt/responseStatus/ setting indicates database or
881 surrogate diagnostics (<tt/DBOSD/). The individual
882 records, indexed by an integer position offset, should then be
885 If element set names have been specified either in the
886 search requests (<tt>smallSetElementSetNames</tt> /
887 <tt>mediumSetElementSetNames</tt>) or present requests
888 (<tt>elementSetNames</tt>) the individual records in the
889 ir set object are assigned appropriate element set ids.
890 In this mode records at a given position are treated different as
891 long as they have difference element set ids.
892 To inspect records with a particular element set id in subsequent
893 operations use the <tt>recordElements</tt> setting followed by the id.
894 If you have more than one record at a given position and you do not
895 use <tt>recordElements</tt> the record selected at the given position
898 The action <tt>type</tt> followed by an integer returns information
899 about a given position in an ir set. There are three possiblities:
902 <tag><tt/SD/</tag> The item is a surrogate diagnostic record.
903 <tag><em/empty/</tag> There is no record at the specified position.
904 <tag><tt/DB/</tag> The item is a database record.
907 To handle the first case, surrogate diagnostic record, the
908 <tt/Diag/ action should be used. It returns three
909 items: error code (integer), text representation in plain english
910 (string), and additional information (string, possibly empty).
912 In the second case, no record, note that there still might
913 be a record at the position but with an id that differs from that
914 specified by <tt>recordElements</tt>.
916 In the third case, database record, the <tt/recordType/ action should
917 be used. It returns the record type at the given position.
918 Some record types are:
935 We continue our search-response example. In the case,
936 <tt/DBOSD/, we should inspect the result set items.
937 Recall that the ir set name was passed to the
938 search-response handler as argument <tt/rset/.
941 if {$type == "DBOSD"} {
942 set ret [$rset numberOfRecordsReturned]
943 for {set i 1} {$i<=$ret} {incr i} {
944 set itype [$rset type $i]
945 if {$itype == "SD"} {
946 set diag [$rset Diag $i]
947 set code [lindex $diag 0]
948 set msg [lindex $diag 1]
949 set addinfo [lindex $diag 2]
950 puts "$i: NSD $code: $msg: $addinfo"
951 } elseif {$itype == "DB"} {
952 set rtype [$rset recordType $i]
953 puts "$i: type is $rtype"
958 Each item in the result set is examined.
959 If an item is a diagnostic message it is displayed; otherwise
960 if it's a database record its type is displayed.
967 In the case, where there is a MARC record at a given position we
968 want to display it somehow. The action <tt/getMarc/ is what we need.
969 The <tt/getMarc/ is followed by a position integer and the type of
970 extraction we want to make: <tt/field/ or <tt/line/.
972 The <tt/field/ and <tt/line/ type are followed by three
973 parameters that serve as extraction masks.
974 They are called tag, indicator and field.
975 If the mask matches a tag/indicator/field of a record the information
976 is extracted. Two characters have special meaning in masks: the
977 dot (any character) and star (any number of any character).
979 The <tt/field/ type returns one or more lists of field information
980 that matches the mask specification. Only the content of fields
983 The <tt/line/ type, on the other hand, returns a Tcl list that
984 completely describe the layout of the MARC record -- including
987 The <tt/field/ type is sufficient and efficient in the case, where only a
988 small number of fields are extracted, and in the case where no
989 further processing (in Tcl) is necessary.
991 However, if the MARC record is to be edited or altered in any way, the
992 <tt/line/ extraction is more powerful -- only limited by the Tcl
997 Consider the record below:
1001 005 00000000000000.0
1002 008 910710c19910701nju 00010 eng
1006 100 10 $a Jack Collins
1007 245 10 $a How to program a computer
1013 Assuming this record is at position 1 in ir-set <tt/z.1/, we
1014 might extract the title-field (245 * a), with the following command:
1016 z.1 getMarc 1 field 245 * a
1021 {How to program a computer}
1024 Using the <tt/line/ instead of <tt/field/ gives:
1026 {245 {10} {{a {How to program a computer}} }}
1029 If we wish to extract the whole record as a list, we use:
1031 z.1 getMarc 1 line * * *
1036 {001 {} {{{} { 11224466 }} }}
1037 {003 {} {{{} DLC} }}
1038 {005 {} {{{} 00000000000000.0} }}
1039 {008 {} {{{} {910710c19910701nju 00010 eng }} }}
1040 {010 { } {{a { 11224466 }} }}
1041 {040 { } {{a DLC} {c DLC} }}
1042 {050 {00} {{a 123-xyz} }}
1043 {100 {10} {{a {Jack Collins}} }}
1044 {245 {10} {{a {How to program a computer}} }}
1045 {260 {1 } {{a Penguin} }}
1046 {263 { } {{a 8710} }}
1047 {300 { } {{a {p. cm.}} }}
1054 This example demonstrates how Tcl can be used to examine
1055 a MARC record in the list notation.
1057 The procedure <tt/extract-format/ makes an extraction of
1058 fields in a MARC record based on a number of masks.
1059 There are 5 parameters, <tt/r/: a
1060 record in list notation, <tt/tag/: regular expression to
1061 match the record tags, <tt/ind/: regular expression to
1062 match indicators, <tt/field/: regular expression to
1063 match fields, and finally <tt/text/: regular expression to
1064 match the content of a field.
1067 proc extract-format {r tag ind field text} {
1069 if {[regexp $tag [lindex $line 0]] && \
1070 [regexp $ind [lindex $line 1]]} {
1071 foreach f [lindex $line 2] {
1072 if {[regexp $field [lindex $f 0]]} {
1073 if {[regexp $text [lindex $f 1]]} {
1083 To match <tt/comput/ followed by any number of character(s) in the
1084 245 fields in the record from the previous example, we could use:
1086 set r [z.1 getMarc 1 line * * *]
1088 extract-format $r 245 .. . comput
1092 How to program a computer
1097 The <tt/putMarc/ action does the opposite of <tt/getMarc/. It
1098 copies a record in Tcl list notation to a ir set object and is
1099 needed if a result-set must be updated by a Tcl modified (user-edited)
1105 In <sf/IrTcl/ a SUTRS record is treated as one single string. To retrieve
1106 a SUTRS record use the <tt>getSutrs</tt> followed by an index.
1111 In <sf/IrTcl/ an XML record is treated as one single string. To retrieve
1112 a XML record use the <tt>getXml</tt> followed by an index.
1116 A GRS-1 record in <sf/IrTcl/ is represented as a list of elements.
1117 Each element specifies a tag as well as data. The data may
1118 be a subtree, which is represented as a list, and so on.
1120 The method <tt/getGrs/ is followed by a record index and
1121 optional specifiers that selects a specific sub-tree. Each element
1122 consists of 5 elements:
1125 <tag>tag-set</tag> Tag set number.
1127 <tag>value-type</tag> Type of tag value. May be either
1128 <tt/numeric/ of <tt/string/.
1130 <tag>value</tag> The value it self.
1132 <tag>data-type</tag> May be either <tt/octets/, <tt/numeric/,
1133 <tt/ext/, <tt/string/, <tt/bool/, <tt/intUnit/, <tt/empty/,
1134 <tt/notRequested/, <tt/diagnostic/ or <tt/subtree/.
1136 <tag>data</tag>The data associated with element of given type as
1137 indicated before. If data-type is <tt/numeric/ or <tt/string/
1138 then data is encoded as a single Tcl token. The data-type <tt/bool/
1139 is encoded as 0 or 1 for false and true respectively. If the
1140 data-type is <tt/subtree/ the data is a sub-list.
1141 In all other cases, the data is the empty string.
1146 Consider the GRS-1 record below as shown by the <bf/YAZ/ client program:
1149 (1,1) OID: GILS-schema
1151 (2,1) UTAH EARTHQUAKE EPICENTERS
1152 class=4,type=1,value=us
1153 (4,52) UTAH GEOLOGICAL AND MINERAL SURVEY
1154 (3,Local-Subject-Index) APPALACHIAN VALLEY; EARTHQUAKE; EPICENTER
1156 (1,19) Five files of epicenter data arranged by ...
1157 (3,Format) DIGITAL DATA SETS
1158 (3,Data-Category) TERRESTRIAL
1159 (3,Comments) Data are supplied by the University of Utah ...
1162 (2,10) UTAH GEOLOGICAL AND MINERAL SURVEY
1163 (4,2) 606 BLACK HAWK WAY
1164 (4,3) SALT LAKE CITY
1168 (2,14) (801) 581-6831
1169 (4,7) UTAH EARTHQUAKE EPICENTERS
1174 The record may be fetched from the result set, <tt/z.1/, at position 1
1181 { 1 numeric 1 oid 1.2.840.10003.13.2 }
1182 { 1 numeric 14 string 2 }
1183 { 2 numeric 1 string
1184 { UTAH EARTHQUAKE EPICENTERS} }
1185 { 4 numeric 52 string {UTAH GEOLOGICAL AND MINERAL SURVEY} }
1186 { 3 string Local-Subject-Index string
1187 {APPALACHIAN VALLEY; EARTHQUAKE; EPICENTER} }
1188 { 2 numeric 6 subtree
1189 { { 1 numeric 19 string
1190 {Five files of epicenter data arranged by ...} }
1191 { 3 string Format string {DIGITAL DATA SETS} }
1192 { 3 string Data-Category string TERRESTRIAL }
1193 { 3 string Comments string
1194 {Data are supplied by the University of Utah ...} } } }
1195 { 4 numeric 70 subtree
1196 { { 4 numeric 90 subtree
1197 { { 2 numeric 10 string
1198 {UTAH GEOLOGICAL AND MINERAL SURVEY} }
1199 { 4 numeric 2 string {606 BLACK HAWK WAY} }
1200 { 4 numeric 3 string {SALT LAKE CITY} }
1201 { 3 string State string UT }
1202 { 3 string Zip-Code string 84108 }
1203 { 2 numeric 16 string USA }
1204 { 2 numeric 14 string {(801) 581-6831} } } }
1205 { 4 numeric 7 string {UTAH EARTHQUAKE EPICENTERS} } } }
1206 { 4 numeric 1 string ESDD0006 }
1207 { 1 numeric 16 string 198903 }
1210 We can choose only to get the path (2,6) by using:
1217 { 2 numeric 6 subtree { { 1 numeric 19 string
1218 {Five files of epicenter data arranged by ...} }
1219 { 3 string Format string {DIGITAL DATA SETS} }
1220 { 3 string Data-Category string TERRESTRIAL }
1222 string {Data are supplied by the University of Utah ...} } } }
1225 To get the well known (1,19) within the subject (2,6) we use
1227 z.1 getGrs 1 (2,6) (1,19)
1231 { 2 numeric 6 subtree
1232 { { 1 numeric 19 string
1233 {Five files of epicenter data arranged by ...} } } }
1239 Explain records are retrieved like other records. The method,
1240 <tt>getExplain</tt> is followed by an index and and an optional
1241 Explain record pattern.
1243 The returned record is a canonical representation of the Explain record.
1244 An ASN.1 sequence is represented as a list. Each item in the list
1245 consists of the name of the element, followed by its value if the value
1248 The optional pattern that follows the index after <tt>getExplain</tt>
1249 consists of one or more elements, that is matched against the elements
1250 of the actual record.
1254 One of the few targets that support explain is the ATT research server
1255 at <tt>z3950.research.att.com</tt>.
1257 The targetInfo record was returned by the target and it's stored in
1258 position 1 in the result set, <tt>z.1</tt>. To retrieve the whole
1264 and we get in return
1267 {targetInfo commonInfo {name {Lucent Technologies Research Server}}
1268 recentNews icon {namedResultSets 1} {multipleDBsearch 0}
1269 {maxResultSets 100} {maxResultSize 600000} maxTerms timeoutInterval
1270 {welcomeMessage {strings { {language eng}
1272 {Salutations - this is Lucent Technologies experimental Z39.50 server.
1273 No guarentees, but free and unlimited access!}} } } }
1274 {contactInfo {name {Robert Waldstein}} {description {strings
1276 {text {Librarian system designer - no legal anythings}} } } }
1277 {address {strings { {language eng} {text {Room 3D-591
1280 N.J. USA 07974}} } } } {email wald@lucent.com} {phone {908 582-6171}} }
1281 description nicknames {usageRest {strings { {language eng}
1282 {text {None - as long as nonProfit research}} } } } paymentAddr
1283 {hours {strings { {language eng} {text {Should never be down}} } } }
1284 dbCombinations addresses commonAccessInfo }
1287 The <tt>targetInfo</tt> above indicates the the record is really a
1288 <tt>targetInfo</tt> record. The <tt>commonInfo</tt>, which is optional, is
1289 not supplied by this server. The <tt>name</tt>, however is supplied,
1290 with the value <tt>Lucent Technologies Research Server</tt>.
1292 To retrieve the <tt>contactInfo</tt> from the record above we can
1293 extract the element from the record by using Tcl's list manipulation
1294 facilities, for example by doing
1296 set ti [z.1 getExplain 1]
1297 lindex [lindex $ti 0] 12
1301 contactInfo {name {Robert Waldstein}} {description {strings
1303 {text {Librarian system designer - no legal anythings}} }
1304 } } {address {strings { {language eng} {text {Room 3D-591
1307 N.J. USA 07974}} } } } {email wald@lucent.com} {phone {908 582-6171}}
1310 We can also extract almost the same by doing
1312 z.1 getExplain 1 targetInfo contactInfo
1316 {name {Robert Waldstein}} {description {strings { {language eng}
1317 {text {Librarian system designer - no legal anythings}} } } }
1318 {address {strings { {language eng} {text {Room 3D-591
1321 N.J. USA 07974}} } } } {email wald@lucent.com} {phone {908 582-6171}}
1329 To perform scan, a scan object must be created by the <tt>ir-scan</tt>
1330 command. This command has two arguments -- name of the scan object and
1331 name of the ir object. Basically, the scan object, provides one <tt>scan</tt>
1332 action which sends a scan request to the target. The <tt>action</tt>
1333 is followed by a string describing starting point of the term list. The
1334 format used is a simple subset of the query used in search requests. Only
1335 <tt>@attr</tt> specifications and simple terms are allowed.
1336 The settings that affect the scan are:
1339 <tag><tt>stepSize </tt><em>integer</em></tag>
1340 Step size. Default is 0.
1341 <tag><tt>numberOfTermsRequested </tt><em>integer</em></tag>
1342 Number of terms requested. Default is 20.
1343 <tag><tt>preferredPositionInResponse </tt><em>integer</em></tag>
1344 Preferred position in response. Default is 1.
1345 <tag><tt>databaseNames </tt><em>list</em></tag>
1346 Database names. Note that this setting is not (yet) supported for
1347 the scan object. You must set this for the ir object instead.
1348 <tag><tt>referenceId </tt><em>string</em></tag>
1349 Reference-id. If <em>string</em> is empty no reference-id is used.
1350 <tag><tt>scanResponse </tt><em>list</em></tag>
1351 Scan-response Tcl script.
1352 <tag><tt>callback </tt><em>list</em></tag>
1353 General response Tcl script. Only used if <tt>scanResponse</tt>
1355 This setting is valid only for the <tt/ir/ object -- not the
1359 The scan object normally holds one or more scan line entries upon
1360 successful completion. The table below summarizes the settings
1361 that should be used in a response handler.
1364 <tag><tt>scanStatus </tt>returns <em>integer</em></tag>
1365 Scan status. An integer between 0 and 6.
1366 <tag><tt>numberOfTermsReturned </tt>returns <em>integer</em></tag>
1367 Number of terms returned.
1368 <tag><tt>positionOfTerm </tt>returns <em>integer</em></tag>
1369 An integer describing the position of term.
1370 <tag><tt>scanLine </tt>returns <em>list</em></tag>
1371 This function returns information about a given scan line (entry) at a given
1372 index specified by the integer. The first scan line is numbered zero;
1373 the second 1 and so on. A list is returned by the <tt>scanLine</tt>
1374 setting. The first element is <tt>T</tt> if the scan line
1375 is a normal term and <tt>SD</tt> if the scan line is a surrogate
1376 diagnostic. In the first case (normal) the scan term is second element
1377 in the list and the number of occurences is the third element.
1378 In the other case (surrogate diagnostic), the second element
1379 is the diagnostic code, the third a text representation of the error
1380 code and the fourth element is additional information.
1381 <tag><tt>referenceId </tt>returns <em>string</em></tag>
1382 Reference-id of scan response.
1387 We will scan for the terms after <tt>science</tt> in the Title index.
1388 We will assume that an ir object called <tt>z-assoc</tt> has already
1392 z-assoc callback {scan-response}
1393 ir-scan z-scan z-assoc
1394 z-scan scan "@attr 1=4 science"
1396 proc scan-response {} {
1397 set status [z-scan status]
1399 set no [z-scan numberOfTermsReturned]
1400 for {set i 0} {$i < $no} {incr i} {
1401 set line [z-scan scanLine $i]
1402 set type [lindex $line 0]
1404 puts [lindex $line 1]
1405 } elseif {$type == "SD"} {
1406 puts [lindex $line 1]
1417 Copyright © 1995-2004, Index Data ApS.
1419 Permission to use, copy, modify, distribute, and sell this software and
1420 its documentation, in whole or in part, for any purpose, is hereby granted,
1423 1. This copyright and permission notice appear in all copies of the
1424 software and its documentation. Notices of copyright or attribution
1425 which appear at the beginning of any file must remain unchanged.
1427 2. The names of Index Data or the individual authors may not be used to
1428 endorse or promote products derived from this software without specific
1429 prior written permission.
1431 THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
1432 EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
1433 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
1434 IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
1435 INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
1436 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
1437 NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
1438 LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
1441 <sect>About Index Data
1444 Index Data is a consulting and software-development enterprise that
1445 specialises in library and information management systems. Our
1446 interests and expertise span a broad range of related fields, and one
1447 of our primary, long-term objectives is the development of a powerful
1448 information management
1449 system with open network interfaces and hypermedia capabilities.
1451 We make this software available free of charge, on a fairly unrestrictive
1452 license; as a service to the networking community, and to further the
1453 development of quality software for open network communication.
1455 We'll be happy to answer questions about the software, and about ourselves
1466 Phone: +45 3341 0100
1468 Email: info@indexdata.dk
1476 <tag>1 IrTcl Homepage</tag>
1477 <htmlurl url="http://www.indexdata.dk/irtcl/"
1478 name="http://www.indexdata.dk/irtcl/">
1480 <tag>2 Ousterhout, John K.:</tag>
1481 Tcl and the Tk Toolkit. Addison-Wesley Company Inc (ISBN
1482 0-201-63337-X). The Tcl/Tk toolkit home page is
1483 <htmlurl url="http://tcl.activestate.com"
1484 name="http://tcl.activestate.com">.
1485 The primary download area is
1486 <htmlurl url="http://prdownloads.sourceforge.net/tcl/"
1487 name="http://prdownloads.sourceforge.net/tcl/">.
1489 <tag>3 Welch, Brent B.:</tag>
1490 Practical Programming in Tcl and Tk. Prentice Hall
1491 (ISBN 0-13-616830-2).