pool-get.c
pool-get.c
is probably the simplest introduction to
programming FramerD. It does nothing more than open the pool
specified on the command-line, and retrieve the value associated
with the OID specified on the command-line. A simple invocation
(against the data you created in the Test Server
Setup) looks like this:
pool-get atut@defiant @/atut/0
And produces this output:
[03:17:14 MIT FramerD library 1.0 (c) 1994-1999, built Jun 7 1999] [03:17:14 Session id=framerd tlilley@defiant /PID:2424 /OS:i686-unknown-linux /Compiled:Jun 7 1999 /Started:Mon Jun 7 03:17:14 1999] [03:17:14 Added pool atut@defiant] The OID @/atut/0 in the pool atut@defiant has the value: "a simple OID value"
Now, using the OID you marked earlier when you were creating and
adding data, go ahead and try using a literal OID (note that
this literal OID must be the one you got as the output from
fdscript's "allocate-oid" command, combined with the information
found in the #POOL
message from fdscript
when you connected to the pool in the setup phase.
pool-get atut@defiant @375ae87e/20020
Your output should be the same as the previous invocation (except, of course, for the timestamps).
pool-get.c
itself is so small and elegant
that it seems a shame to clutter it with extensive
commentary. Heck, I felt bad just adding the usage message!
Instead, we'll explore it line-by-line here. There are
horizontal rules between each function call (line of the
original program) to clarify the context of the discussion.
Of course, to do anything, you'll have to include the FramerD include files :-) Fortunately, they're nicely bundled through one file:
#include <framerd/framerd.h>
The first meaningful statement in the program is the call to
void fd_initialize_framerd(void)
[src/odb/libframerd.c
], which does the basic
initialization of all of the FramerD library components. This
call is, of course, necessary for any subsequent FramerD work.
fd_initialize_framerd();
NOTE: Obviously, it's important to call this initializer
if you're doing anything with the FramerD libraries, like OID or
DType manipulation. What may not strike you, though, when you go
to write a simple little test program to exercise
fd_fprintf
, for example, is that you have to
put this call in for any program using the FramerD
libraries! We wrote a simple test program that contained nothing
more than a single call to fd_fprintf
to
display the time, and were baffled when it consistenly printed
out two copies of our message, regardless of what we put in the
format string. Once the lightbulb went on and we inserted a call
to fd_initialize_framerd
, things returned to
normal :-) The moral of the story is: be careful out
there.
Next is the call to fd_use_pool fd_use_pool(char * c)
[src/odb/odb.c
], which opens a file pool, or
connects to a network pool server, depending on the pool name
given it. If the pool name is in the form
server@host
, the system treats it as a
network pool server, otherwise it treats it as a pool file.
fd_use_pool(pool);
Note that the call to fd_use_pool
has the
side effect of registering the pool's name in a hashtable that
the FramerD libraries use to map logical OIDs to literal
OIDs. The internal function parse_oid_ref
[src/cons/io.c
] uses this hashtable to
resolve an OID string into a 64-bit OID structure. Therefore, if
you haven't mounted the pool before calling any functions which
attempt to parse OID strings, logical OIDs won't resolve
properly (the program will die with an unhandled exception: "No
logical OIDs found"). The version of
pool-get.c
shipped with the framerd-1.0
distribution calls fd_arg2lisp
on the OID
string before calling fd_use_pool
,
and thus will not properly recognize logical OIDs. The
pool-get.c
we're dissecting here, however,
has this corrected.
Next, the call to fd_lisp fd_arg2lisp(u8char *string)
[src/cons/io.c
] takes the string OID
representation passed in on the command line, and converts it
into a LISP structure containing the OID. Internally, the
function calls parse_atom
, then
parse_oid_ref
to accomplish this.
oid=fd_arg2lisp(oid_str);
Note that this function will throw the exception "No logical
OIDs defined" if you pass it a logical OID and the pool
named in the logical OID hasn't been mounted with
fd_use_pool
.
NOTE: Apparently,
fd_arg2lisp
likes to modify the contents of
the string you pass it during its parsing. Thus, if you pass it
a constant string, you're asking for a seg fault or GPF. This
code does not work:
u8char * oid_str = "@/test/0"; lisp oid = fd_arg2lisp( oid_str );
But this code, which copies the string into a dynamically-allocated char array, does work:
u8char * oid_str = (u8char *) malloc( (strlen( "@/test/0" ) + 1) * sizeof( u8char ) ); strcpy( oid_str, "@/test/0" ); lisp oid = fd_arg2lisp( oid_str );
(Note that lisp
is effectively the same as
fd_lisp
, and is described in the C Manual for FramerD.)
The invocation of the macro lisp oid_value(lisp oid)
[include/framerd/odb.h
] resolves the OID and
retrieves whatever is stored in the "body" of the DType as a
LISP structure. Thus, if the value is more than a simple datum,
you will receive the full, complex value.
value=oid_value(oid);
oid_value
is actually a wrapper around
wrappers :-), implemented as C macros and, eventually, function
calls into the FramerD library. I suggest you study the source
to divine exactly what's happening, but, in brief,
oid_value
is a macro which either locks the
OID, then evaluates it, in a multi-threaded build, or simply
evaluates the OID directly, in a single-threaded build. In
either case, oid_value checks to make sure the OID is valid, and
has a value. Otherwise it throws an exception.
The last series of calls are to FramerD's modified output
functions, void fd_fprintf(FILE *f, char
*format_string, ...)
[src/os/fdprintf.c
], and
void fd_pprint_lisp(fd_lisp x, FILE *stream, int width)
[src/cons/io.c
]. The
fd_fprintf
function is a replacement for the
standard IO library's fprintf
, supporting
internationalization and some extensions to integrally print
FramerD LISP objects. The fd_pprint_lisp
function is a simple pretty-printer for LISP objects.
fd_fprintf(stdout,"The OID %q in the pool %s has the value:\n",oid,argv[1]); fd_pprint_lisp(value,stdout,40); fd_fprintf(stdout,"\n"); return 0;
The fd_fprintf
is a simple wrapper around
do_printf
[src/os/fdprintf.c
]. I encourage you to read
do_printf
closely to make sure you
understand how it handles your data.
void fd_printf(fd_string_stream s, char *format_string,
...)
(and its derivatives,
void fd_fprintf(FILE *f, char *format_string, ...)
, and
void fd_xprintf(char *fstring)
] supports the following extended
formatting characters:
%m
- internationalized string (ie: a
string that's passed through the translation tables).
%q
- plain-print a LISP object
%Q
- pretty-print a LISP object
%t
- the current time as
hh:mm:ss
(uses strftime
]
%lt
- the current time as
DDMoYYYY@hh:mm:ssTZ
(ex:
07Jun1999@14:58:43-0400
)
pool-get.c
Clone
So, you've successfully dissected
pool-get.c
, and want to retype it and build
it in your own directory. That's simple enough (under Linux
2.0.36, Debian 2.1 (slink), anyway). Here's a typical
command-line for compiling pool-get.c
to
pool-get
on a GNU-ified Unixish system:
gcc pool-get.c -o pool-get -L/usr/local/lib -L/usr/lib -lframerd -ldtypes -lreadline -lpthread
Apps that use the FramerD core require
libframerd
and
libdtypes
, at a minimum. On systems where
FramerD comes with GNU Readline support compiled in, you'll also
need to link to libreadline
. Finally, on
systems where you've built FramerD with pthreads (multithreading
under UNIX) support, you'll need to link in
libpthread
, as well.
(NOTE: on our test system (Linux 2.0.36 Debian 2.1
(slink), gcc 2.7.2.3, GNU ld 2.9.1), it seems that the order of
the command-line arguments is, indeed important. So, the command
line given above works as specified, but moving the source file
and -o pool-get
specified to the end of the
line seemed to not work. I'm quite sure this is explained
adequately in the GNU gcc and ld docs. Have you seen the size of
those docs?)
Of course, this is only a very simplistic treatment of the libraries and options available for compiling FramerD applications. Once I understand them all, I'll be happy to explain them to you :-)