
One of the problems with any programming language or operating system
is that the programmer always wishes it worked a different way. The
programming gurus have been preaching "modular programming" for years
as a way to lessen the support load. Let's look at how these two
ideas combine.
We have always used "wrappers" to isolate our code from the details
of system calls. The idea is that for every operating system routine
we use, we write a little function or subroutine that has a similar
name and makes the actual call for us. As an example, rather than
use the THEOS function getdate() to find out what day it is, we
call our function hgetdate() to do it. We always add and extra
argument to our routines and give it a zero value to mean the
THEOS function should be used in its normal fashion. The following
C example shows how we might implement hgetdate().
The idea is that if whichway is equal to zero, we just call the THEOS
function and let it do the work. Suppose, however, that we also need
to find out what the date is using the Martian calendar. The only
change we need to make in an application program is to set the
second argument to the proper value for the Martian calendar and
add a little code (actually a lot of code: dates on Mars are
pretty complicated) and we are all set.
Perhaps a little closer to home, suppose you don't like the way THEOS
has decided to change the operation of getdate(). No problem; just
stop calling their routine and supply your own entirely. 20 minutes
of work and it's over.
The concept of call wrappers is really central to being able to
implement client/server and all the other cool things you might want
to do under THEOS. In BASIC, it really isn't much more difficult,
except for cases in which the actual BASIC statement may have a
variable number of arguments. If you are used to listing a few dozen
variables on your READ statements, you are going to hate using call
wrappers. If you read and write records as single entities and
do your own block/deblock operations, it is no sweat.
On the subject of file I/O, I should point out that we also don't use
the THEOS file handles in our calls. We define our own table of open
files and use an integer index into this table as the "file handle"
for all our calls. In this table, all we really need to keep is the
actual THEOS file handle, but we keep lots of other stuff too. For
an indexed file, we store record size and key size; for all files we
store an additional flag that is normally set to zero. We'll see this
flag used in a later chapter.
One more use for call wrappers: ever need to trace your programs? Just
turn on tracing in one or all wrappers and let them do the work. You
get a log file of every (or selected) system calls with a few minutes
of work.
char *hgetdate(char *buffer, int whichway)
{
if(!whichway) return(getdate(buffer));
/* if not standard call, do weird stuff here */
}
Have any questions?
E-mail us at info@hsix.com