Contents of the README.DOC file
General documentation for Richard McConnell's "Advanced C Goodies."
extor.h C header file with "Extor System" function prototypes.
extor.obj Object module containing "Extor System" functions.
extor.doc Documentation for "Extor System" functions.
sysinfo.h C header file with "sysinfo" function prototypes.
sysinfo.obj Object module containing "sysinfo" functions.
sysinfo.doc Documentation for "sysinfo" functions.
nsupport.h C header file with numeric support prototypes.
nsupport.c C source file with numeric support equivalents.
nremove.scr LIB script file for removing standard numeric support.
nsupport.doc Documentation for numeric support files.
readme.doc File list, general notes, etc. (this file).
This material was originally introduced and discussed in my "Advanced C
Programming" talk at the Clipper Developer's Conference in June of 1988.
As this suggests, the information is primarily of use to accomplished C
or assembler programmers. At the top of each doc file you will find a
short list of terms. They are included only to avoid misunderstandings
due to nomenclature! In general, I have assumed that you already have
a working knowledge of these topics, as well as a good grasp of both
Clipper and C programming. If this is not the case, the material may
confuse you (or worse).
(Conference attendees will note that the information presented here
differs somewhat from that distributed at the conference. Where
differences exist, this information supercedes.)
Creative users of any of these systems will want to keep an eye on the
issue of future compatibility. I highly recommended that you isolate
any code that deals with Clipper internal concepts (for an example of
one way to do this, see the description of the 'NUM_INLINE' flag in
"nsupport.doc"). Isolation of parameter handling (both Extend and
Extor) is also advisable if you plan to take maximum advantage of any
future improvements to Clipper's Extend interface.
Below are a few comments concerning the design of Clipper-callable
functions. These are not hard and fast rules, of course, but they are
worthy of consideration when designing new functions:
1) Avoid variably typed parameters.
Variably typed parameters (used so flagrantly in some Clipper
EXTEND.LIB functions) are difficult to support efficiently.
Sometimes it's hard to pass up the ability to communicate extra
information to your function via the type of the parameters, but
it's usually not a good idea (many procedural languages don't even
allow it), and it may prevent you from taking maximum advantage of
future versions of Clipper.
2) Avoid optional parameters.
Same thing here. Sometimes it's hard to resist, but it's not a
tendency you should encourage. As with variably typed parameters,
it makes your code less understandable, and more difficult to error-
check (for both you and the compiler).
3) Isolate parameter handling.
The best way to prepare for a newer more efficient Extend interface
is to make your Clipper callable function gather up it's parameters
(via the "par" functions) and then call a normal C function to do
the real work. Same thing with the return value. If a better
Extend interface comes along, only the Clipper-callable part will
4) Avoid modifying parameters passed by reference.
In general, the simplest architecture for a procedural function (in
Clipper or elsewhere) is to take one or more values as input, and to
return a single result value. The simplest is usually the best.
5) Avoid directly modifying parameters via the _parc() pointer.
The _parc() Extend function returns a character pointer to the
actual parameter passed from Clipper. Nothing prevents you from
modifying the characters that it points to, but you should never do
this unless you have first checked to see that the parameter was a
character type memory variable passed by reference. (Note also that
the length of the variable cannot be changed via this method.)
6) Never "hold onto" parameter pointers.
If you get a pointer to a memory variable's contents (via _parc(),
for example) you should never store it somewhere and assume that it
will be valid during a subsequent function call. The contents of
memory variables can be moved at any time; your pointer is only
guaranteed for the duration of the function call in which you
initially obtained it.
7) Use Clipper for I/O (and whatever else you can).
For a variety of reasons, your life will be more pleasant if you
leave input and output to the Clipper runtime system, rather than
calling C support routines such as printf(). In general, you're
best off doing everything you can at the Clipper level, calling
foreign functions only when you need extra processing speed or
access to information that is only available externally.
If some of you experts out there think these guidelines are obvious (or
high handed), well... humor me, OK?
As a final note, let me warn you that the software supplied here has not
undergone extensive beta testing. I have tested it, and it appears to
work. Nonetheless, prudence dictates that you carefully test any code
that uses these facilities.