Dumping Data to Disk
TCL API
C Routine Interface
An introduction to Object Schema
Manipulating Values from TCL
An object's schema is a term stolen from the world of databases, and means
a description of the internals of a complex object (the sort of information
that is available from the symbol table information generated by compilers).
Because one incarnation of DERVISH is as a high-level debugger, DERVISH needs
access to this information. It is automatically generated by a program
called make_io, which reads the definitions in C header files (.h files)
and generates the requisite C.
The source code for this example may be found in
$DERVISH_DIR/etc/dump_example.tcl.
An executable that knows about the
type FOO that this example uses may be built as
$DERVISH_DIR/examples/dervish_foo, but analogous examples could be built around
any of the SDSS data types (e.g. Regions).
Let us imagine that you are running dervish_foo, and are curious about what
a FOO is. That's easily discovered, type:
schemaPrintFromType FOO
and dervish will say:
type TYPE
next FOO*
prev FOO*
name char*
i int
l long
f float
If you now look for the relevant include file, $DERVISH_DIR/examples/foo.h,
you'll find that the C is:
typedef struct foo {
TYPE type;
struct foo *next, *prev;
char *name;
int i;
long l;
float f;
} FOO;
which is reassuring. Let's now make a FOO and print it:
set foo [fooNew]
exprPrint -header $foo
to which the reply is:
h7 FOO
(h7).type (enum)1009
(h7).next 0x0
(h7).prev 0x0
(h7).name (null)
(h7).i 0
(h7).l 0
(h7).f 0
The first line "h7 FOO" tells you that $foo is a handle-to-FOO, the
rest are the values of the elements (and are not very interesting). Let's
set one of them:
handleSet $foo.name "Hello World"
exprPrint -header -noquote $foo
to which the reply is:
h7 FOO
(h7).type (enum)1009
(h7).next 0x0
(h7).prev 0x0
(h7).name Hello World
(h7).i 0
(h7).l 0
(h7).f 0
Thus emboldened, we can write a procedure to initialise FOOs:
proc fooInit { foo name i l f } {
foreach el "name i l f" {
handleSet $foo.$el [set $el]
}
return $foo
}
and say things like
set foo2 [fooInit [fooNew] "God Bless the Queen" 12 65536 1.234]
exprPrint -header -noquote $foo2
h9 FOO
(h9).type (enum)1009
(h9).next 0x0
(h9).prev 0x0
(h9).name God Bless the Queen
(h9).i 12
(h9).l 65536
(h9).f 1.234
If you want to know how these procedures work, you should look at the
description of the TCL interface for schema
or for accessing handle and their contents; the basic
routines are schemaGet and
exprGet which return TCL lists. For example:
exprGet -header $foo2
{type FOO} {type (enum)1009} {next 0x0} {prev 0x0}
{name {God Bless the Queen}} {i 12} {l 65536} {f 1.234}
Dumping and Restoring Complex Objects to Disk
An introduction to disk dumps
An example of generating and reading a dump from TCL
Details of the
C and TCL interfaces
may be found elsewhere.
The source code for this example may be found in
$DERVISH_DIR/etc/dump_example.tcl. An executable that knows about the
type FOO that this example uses may be built as
$DERVISH_DIR/examples/dervish_foo, but the code will work even with a
vanilla version of dervish.
This code generates a dump, and then reads it back. There are two procs:
- fooInit
- Initialises a FOO
- testDumpWrite
- Writes a test dump file
There is then a section of code that writes a dump file, and reads it back.
There are also a number of other procs in dervishStartup.tcl, which should
have been read for you automatically. These deal with
disk dumps.
The way that dumpRead works is to generate a list of handles; I put
this list into a variable d1. So to look at the
results of the dump say
dumpPrint $d1
which will print something like:
tst_dump.dat: Created Fri Jun 11 09:01:18 1993
h3 REGION
h4 REGION
h5 REGION
h6 FLOAT
h7 STR
h8 INT
h9 FOO
h10 LIST
Then you can say
exprPrint h4
to look at things. I pretty soon get fed up with typing exprPrint, so:
alias p exprPrint
alias pl listPrint
and
p h10
pl h10
You get the point.
First a utility proc to initialise FOOs:
#
# TCL procedures to manipulate FOOs
#
# Initialise a FOO
#
proc fooInit { foo name i l f } {
foreach el "name i l f" {
handleSet $foo.$el [set $el]
}
return $foo
}
And then a proc to generate things to dump, and then
dump them:
#
# Write a test disk dump to <file>
#
proc testDumpWrite { file } {
#
# create a set of regions
#
set r0 [regNew -type=S16 -mask 20 10]
regSetWithDbl $r0 10
regPixSetWithDbl $r0 5 8 100
set r1 [subRegNew $r0 10 5 2 4]
set r2 [subRegNew $r0 8 5 1 4]
#
# dump various things to a file; first these [sub]regions,
# then some primitive types, then a FOO and a list of FOOs
# if FOOs are available
#
dumpOpen $file w
dumpHandleWrite $r0
dumpHandleWrite $r1
dumpHandleWrite $r2
dumpValueWrite 3.14159 FLOAT
dumpValueWrite "For the Snark was a Boojum, you see" STR
dumpValueWrite 32767 INT
catch { # we may not be FOO capable
set foo [fooInit [fooNew] "Hello World" 10 1000 3.14159]
dumpHandleWrite $foo; handleDel $foo
set list [listNew FOO]
foreach n {"Yr Wyfdda" "Carnedd Llewellyn" "Pen Yr Oleu Wen"} {
set foo [fooInit [fooNew] $n 0 1 2.71828]
listAdd $list $foo
handleDel $foo
}
dumpHandleWrite $list; handleDel $list
}
dumpClose
}
We can now actually write a dump, read it back, and
see what we got:
#
# write a dump
#
set test_file_name "tst_dump.dat"
testDumpWrite $test_file_name
#
# and read it back. The list of handles is in $d1
#
set d1 [dumpRead $test_file_name]
dumpPrint $d1