Dec 172017
Extract Elements from Clipper NTX index and create index.
File SUBNTX50.ZIP from The Programmer’s Corner in
Category Dbase Source Code
Extract Elements from Clipper NTX index and create index.
File Name File Size Zip Size Zip Type
ORDER.FRM 2513 805 deflated
SUBDEMO.DBF 2895 794 deflated
SUBDEMO.PRG 8411 2650 deflated
SUBNTX.DOC 21379 7758 deflated
SUBNTXD.LIB 8215 3944 deflated
XTR_LIB.EXE 19227 13904 deflated
XTR_SRC.EXE 45314 27333 deflated

Download File SUBNTX50.ZIP Here

Contents of the SUBNTX.DOC file


Version 5.0 - 9/28/90

Copyright 1989, 1990 Moon Microsystems


Subntx() is a C function called from a Clipper program to quickly
extract index elements from an existing index file, and create a
"subset" index matching some key.

Typical uses for SubNtx() include implementing a 'WHILE' clause for
dbedit, replacing or deleting groups of records, or reporting for a
certain condition. Any of these processes can be made to perform
significantly faster with SubNtx().


result_code = subntx(
[, [, [, [,

- is a character string (including the ".ntx" extension) or
character variable which contains the name of the existing index
from which keys are to be extracted. It will be opened in SHARED
mode if on a network. (To be sure that buffers are flushed to disk,
index should be closed via the SET INDEX TO command. (I
have heard that when a file is opened in SHARED mode, it is flushed
to disk after each write. Be careful though and check this out
yourself if you decide to not SET INDEX TO).

- is also a character string (with the ".ntx" extension) or
variable which contains the name of the 'SUB' index to be created.
It will overwrite any file with the same name.

- is a character string or character variable which contains the
string that is compared to the keys of the
index. SubNtx()
is like a SEEK key with SET EXACT OFF in that it will include
partial matches in the new sub index. Example: "Moo" will match

is the lower range when an optional upper range key
(discussed next) is used.

If contains the single character '*', it will match any key
up to and including the , if an upper key exists, otherwise it
will attempt to match everything.

Note: The '*' character in is converted to a "" which will
match anything just as SEEK would normally. You may just use "" if
you wish but this option is added to be consistent with the same
feature of the which MUST contain '*' to be infinite.

- is an optional parameter which, if not an empty string "", will
be used as the upper boundary for a range. Again, partial matches
are included in the new subset index, so a range of: lkey="Loon",
ukey="Mo" will match a
index key of "Moon".

can consist of the empty string "" if you don't want an upper
range but you want to use one of the other optional parameters.

can also contain the single character '*' to indicate that
there is an infinite upper bound. This will attempt to cause a
match of the and all keys above it. If you attempt to place
other characters after a '*' in either the or , they
will just be ignored.

- is an optional character string or variable which may consist
of a combination of literal characters and spaces, zero or more
occurrences of '?', and zero or more occurrences of '*'.
is similar to the DOS wildcard expressions with some exceptions.

is tested against each key which matches or falls in the
range of to . Note that it does not waste time
comparing keys which fall outside the range, but of course an
infinite range could be specified which would then compare all keys
to the wildcard pattern.

Just as in DOS, a literal character will match itself, and '?' will
match ANY single character in that key position. Also as in DOS,
'*' will match zero or more of ANY combination of characters.

One difference with the SubNtx() is that the pattern will
enable an exact match (as opposed to a partial match in the
and ) unless the '*' is the last character in the pattern. A
list of examples follow:

---------------- ----------- ------
"Color of Money " "Col*" TRUE
"Color of Money " "*Col*" TRUE
"Color of Money " "*ey " TRUE
"Color of Money " "*ey" FALSE
"Color of Money " "* *" TRUE
"Color of Money " "Color" FALSE
"Color of Money " "*of*" TRUE
"Color of Money " "*OF*" FALSE
"Color of Money " "?ol*" TRUE
"Color of Money " "*?ol*" TRUE
"Color of Money " "??lor M*" TRUE
"Color of Money " "*Mo?ey??" FALSE
"Color of Money " "*Mo?ey*" TRUE
"Color of Money " "*Mo?ey" FALSE

- In SubNtx() VERSION 5 this paramter now allows a
string containing a valid Clipper function name to be used IN
CLIPPER 5.0 ONLY. It will also receive a logical value to remain
backwards compatible with SubNtx() version 2.

If a logical TRUE value is passed to passed to SubNtx(), it signals
for SubNtx() to call a Clipper procedure called _subeval(). If a
string is passed, it will attemp to call that function.

If is called when an index key matches or is in the range of
to . It then will be used to determine if the key
is extracted into the sub index or not.

If the developer uses this feature, he/she must have the procedure
return a logical value back by using a SubNtx() internal function:
reteval( ). If .T. is returned, the current key in
the index will be included in the new sub index.

(The value returned with reteval is actually stored in a C static
variable so that when _subeval returns to SubNtx() the result can be
evaluated. If reteval() isn't called before _subeval is finished,
an undetermined random value will mistakenly be used in the

Two other SunNtx() internal functions which are available to
_subeval are: subrec() and subkey(). They return the current index
record number and key value, respectively. A typical example of
creating _subeval follows:

condition = "rec > 100 .and. inv_date > [04/22/90]"

* Note no parameters
rec = subrec()
key = subkey() && Not used in this example
GOTO rec
reteval( &condition )

...OR...Use a CodeBlock for the condition in Clipper 5.0

Note: To prevent an unresolved external error when not using the
_subeval procedure, there is a C function with the same name in the
SubNtx() library which just returns true. For this reason you may
get a warning about duplicate symbols, but this can be ignored. The
procedure in your code will take precedence.

Also note that using the _subeval procedure may slow down SubNtx()
considerably, due to the overhead of reading in the actual DBF
record. If only the subkey() is evaluated, it is much faster.
Either way it is probably much faster than reindexing or using a
conditional index since the sorting process has already been done
when the main index was created.

- is an optional paramter which indicates the number
of times SubNtx() should try to lock the main index file for
reading. If no value is passed, the default is to try 3 times, once
per second. (This is the default value which the DOS file lock
function uses, but can be changed by the DOS IOCTL function). The
length of "per second" is actually the time it takes to execute a
loop 65536 times, so the time representing one second, in this case,
will vary depending on the speed of the machine.

The value -1 will instruct SubNtx() to retry an infinite number of
times to lock the file. This is the way that Clipper does it.

Any other positive number will cause a timeout after that many
attempts. A value of -7 is returned by SubNtx() to indicate that
the file could not be locked.

- is the value returned by SubNtx() which should be a
positive number of keys which were copied into the new index. A
negative value indicates an error.

If there was an error, will equal one of the following
error codes:

-1 Bad number or type of parameters
-2 Could not open main index
-3 Could not read main index
-4 Could not create sub index
-5 Could not allocate memory
-6 Could not write file
-7 Could not lock file.
-8 Exceeded demo limitation executions. (subntxd.lib only)
-9 Parameter key size is too large.



Be sure to issue COMMIT before executing SubNtx() since SET INDEX TO
doesn't always flush the buffers on a netork. SKIP 0 (for lower dos
versions) may also work but I haven't varified it yet.

Single User:

Be sure to issue SET INDEX TO (to close the main index from which
you will be extracting) since SubNtx() will attemp to open that
index internally and will fail if it is already open.


SubNtx() presently doesn't respect SET UNIQUE ON when building the
index. It will choose every key which matches the conditions you
have specified. However, it seems it would be easy to incorporate a
method to do this using _subeval(). Compare the current key
(subkey()) to the previous key and then store the current key to
comare next time its called. Each time they are equal, return a
false so the duplicate won't be included in the new sub index.

Make sure any UDFs or Clipper functions which the main index used
when it was built is either already being used by that portion of
the program, or is explicitly delcared extern so it will be linked

Although SubNtx() matches character strings with and ,
Clipper stores numeric index keys as char strings with prepended
zeros instead of spaces. It is usually the same len as the field
but may be unpredictable when its the result of an expression. I
suggest indexing on STR( num_field, num_places ).


SUBNTX.DOC.....This file
SUBDEMO.PRG....Demo of dbedit() using features of subntx().
SUBNTXD.LIB....Limited version of SUBNTX.LIB which allows only
five calls per program execution.

(The two files below require passwords,
and will self-extract into the full

XTR_SRC.EXE....Self extracts to C source files: SUBNTX5.C
XTR_LIB.EXE....Self extracts to library file: SUBNTX.LIB
ORDER.FRM......Print this order form and send in.
READ.ME........Possible late breaking news.

HOW TO REGISTER (and recieve password)

To extract the unlimited file SUBNTX.LIB from xtr_lib.exe, you must
obtain a password.

(1) The first step is to print the file ORDER.FRM filling in all
required information. Pay special attention to the ID# and User
Defined Password Number. Write them down somewhere. These can be
used when calling our Voice Mail system to get the extraction
password after we receive your payment. (Whenever I get that voice
mail system working!)

(2) Enclose a check, money order, cash, or Visa/MasterCard information.
BE SURE TO MARK IT US DOLLARS (If from another country). Please
forgive the extra handling and shipping charges but sometimes I can
easily spend an extra thirty minutes to an hour just mailing an
invoice or disk, etc. since I'm not really set up for order

(3) After allowing time for you payment to arrive, call my Voice Mail
System from a touch tone phone and follow the instruction on
obtaining the extraction password.

The system will give you various choices and ask you to respond to
the appropriate choice by pressing a number on your phone. Choose
to receive the password.

NOTE: As of the date this doc was released, the Voice Mail System
is still in development. I thought it better to not delay the
release while it is developed. IF it is not working when I receive
your order, I will mail you or eplex the password at no extra

Compiling and Linking Example


Of course, substitute subntx.lib (full library) for subntxd.lib
(demo code) when linking if you call in for the password for the
real code.

Recompiling C Source with MS C 6.0 Only (because of _asm{}):

CL /c /AL /Zl /Oalt /FPa /Gs SUBNTX5.C

(Note SUBEVALC.C is merged with SUBNTX5.C and may need to be
compiled and libed seperately with some linkers).

It has been reported that SubNtx() will link and dynamically overlay
using BLINKER. Be sure to explicitly declare extern, any functions
which may be included in your condition filters in _subeval() or in
the index expression.

DinnerWare (R)

GET TO KNOW ME! (From Saturday Night Live). Take me (and/or my wife)
out to dinner! BUT.....If you don't live in the Chattanooga area, you
can still treat me by sending me the cost of one dinner.

The menu and selection is proportional to the work I put into a
particular program being released under the DinnerWare concept. For the
SUBNTX() function I would like to have Linguini with Red Clam Sauce, and
a bottle of wine from Provino's Restaurant. With tax and tip, that comes
to $49. (OK, I agree......this increased price is more like
BanquetteWare. What can I say? )

Now wouldn't you want to take a fellow programmer out to dinner in return
for the hours spent creating a useful function for you.....

I'm not trying to be "different" or "silly" by coming up with the
DinnerWare concept. I think it just puts spending money for a useful
function, into perspective.


(But then if your reading this, you must already have it!?)

SUBNTX.COM Version 2.0 is located on Compuserve's NANFORUM in Lib 5 (Demo
Lib or possibly the new download Lib 17), as well as several popular
Bulletin Boards listed below. Note: Compuserve has a max file name of 6
chars plus extension, so BBSs with longer file names may have the most
current version listed as SUBNTX5.COM or possibly use the .ZIP extension.
(SUBNTX.COM is a self extracting LZH archive file.)

Starfire Command...........................615-875-4131 9600 HST N-8-1

( Sysop - Shawn Stoddard. FidoNet 1:362/101.0
I will frequently log on here to the Clipper Message Area #38
which supports the FidoNet National Clipper Conference.
Keyword: CLIPPER.
SUBNTX.COM will be kept both in the Clipper File Area #38,
as well as my own Area #39.)


You will need a password to extract the real thing, SUBNTXC.LIB and
SUBNTX5.C, in XTR_LIB.EXE and XTR_SRC.EXE. Once you get the password, do
not give it, or subntxc.* to anyone else! Please?! If you do, you will
make me mad, you will have been a bad person, and your programming skills
will be cursed.

Once you get the password so that you can extract it like this for


Remember you will be expected to send $49 immediately to this address.
If we don't receive it within 15 days, we will add a $10 service charge
and invoice you.

Note: Please try to correspond any problems or question via Compuserve's
Easyplex or Starfire Command BBS (above). If you must leave a message on
Voice Mail and need me to call you, please state that I can call you
COLLECT and tell me the best time (Eastern Standard) to call. (I'm still
not sure the best time to call Holland. )


I've done my best to test these functions and have had no problems with
extracting any number of keys. There can always be some limit or problem
of which I'm not aware though. By using SubNtx(), you agree not to hold
me responsible for any loss of data, or problems it may cause in your
program or your client's program.


After the release of Clipper 5.0, I will be working on various things
including a possible set of index routines that have additional
capablility. One example may be tagging individual records for
processing by adding individual keys to the index.

I have some other C functions in the works or finished:

MAKERR - A makefile/linkefile generator. Use a popup menu
and modifiable templates to quickly manage your

Feel free to give me your comments. I hope this function will be


Thanks to all the people who helped give ideas, do beta testing, and help
write subroutines. Here are the ones I had marked down, but I think I'm
leaving some out. (Bad memory. Let me know about it and I'll mention you
in the docs next time!)

Larry Bauder Don Bayne Jeff Bryant Don Caton
Jud Cole Scott Finchler Rob Hannah Jeff Hofstettler
Dave Irwin Michael Jacquot *Steve Larsen Kirk Lipscomb
Tom Loveland Jeff Morris Pete Polakoff Jordon Powell
Mike Rottler Tom Sparks Rick Spence John Stolte
Del Texley Pat Vandersluis

* Thanks Steve, for writing the preliminary ASM wildcard search routine!


Enhancements to version 2.0

- Added multiuser capability, by changing main index _topen() mode to
sharable and using automatic Clipper compatible index locking.

- Added unlimited extraction capability. (as far as I know)

- Added upper range.

- Added pattern matching parameter.

- Added Clipper callable function.

Fixed in 2.1

- Fixed problem which caused SubNtx(), in certain situations, to
search to end of index when the lower key match was not found.

Enhancements to version 5.0

- is now able to use Clipper function name in "quotes"
to indicate a user defined function to call for further evaluation.

Fixed in 5.0

- Lkey, Ukey, and Pattern parameters are now copied to a buffer
instead of relying on the pointer to its location in Clipper's
memory. This is so Clipper's new garbage collection routines
won't move it.



Skip Moon
Moon Microsystems
P.O. Box 23727
Chattanooga, TN 37422
Compuserve Id: 73377,710
615-899-1285 - ORDERS ONLY PLEASE

 December 17, 2017  Add comments

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>