Dec 102017
 
C to dBase Interface files.
File C2DBASE1.ZIP from The Programmer’s Corner in
Category C Source Code
C to dBase Interface files.
File Name File Size Zip Size Zip Type
C2DBASE.DOC 72265 22171 deflated
CDBUTIL.C 12999 3619 deflated
CDBUTIL.EXE 35918 17472 deflated
CDBUTIL.PRC 1848 700 deflated
DBASE.H 3227 1004 deflated
DBASE.LIB 20992 8020 deflated

Download File C2DBASE1.ZIP Here

Contents of the C2DBASE.DOC file















THE C2DBASE FUNCTIONS
version 1.0
11/28/85

by


COMPUSCAN SOFTWARE

INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . 1
OVERVIEW . . . . . . . . . . . . . . . . . . . . . . . . . . 2
FILES IN PACKAGE . . . . . . . . . . . . . . . . . . . . 2
MODIFICATIONS & REVISIONS . . . . . . . . . . . . . . . . 2
THE DBASE FILE STRUCTURE . . . . . . . . . . . . . . . . 2
THE DBINFO STRUCTURE . . . . . . . . . . . . . . . . . . 3
IMMEDIATE ERROR EXIT POINTS . . . . . . . . . . . . . . . 4
CDBUTIL - THE DBASE UTILITY PROGRAM . . . . . . . . . . . 4
KNOWN BUGS . . . . . . . . . . . . . . . . . . . . . . . 5
REGISTRATION . . . . . . . . . . . . . . . . . . . . . . . . 5
WHY REGISTER . . . . . . . . . . . . . . . . . . . . . . 5
HOW TO REGISTER . . . . . . . . . . . . . . . . . . . . . 6
FUNCTION DESCRIPTIONS . . . . . . . . . . . . . . . . . . . 6
INTRO . . . . . . . . . . . . . . . . . . . . . . . . . . 6
DBHEADER . . . . . . . . . . . . . . . . . . . . . . . . 7
DBSTAT . . . . . . . . . . . . . . . . . . . . . . . . . 7
RECREAD . . . . . . . . . . . . . . . . . . . . . . . . 8
RECLIST . . . . . . . . . . . . . . . . . . . . . . . . 8
RECWRITE . . . . . . . . . . . . . . . . . . . . . . . . 9
NDXREAD . . . . . . . . . . . . . . . . . . . . . . . . 10
NDXSTAT . . . . . . . . . . . . . . . . . . . . . . . . 10
MEMOREAD . . . . . . . . . . . . . . . . . . . . . . . . 11
TEXTFIND . . . . . . . . . . . . . . . . . . . . . . . . 11
MEMOADD . . . . . . . . . . . . . . . . . . . . . . . . 12
ONOFFDBT . . . . . . . . . . . . . . . . . . . . . . . . 13
DBTPACK . . . . . . . . . . . . . . . . . . . . . . . . . 14
PASS . . . . . . . . . . . . . . . . . . . . . . . . . . 15
DBCLOSE . . . . . . . . . . . . . . . . . . . . . . . . 15
CDBUTIL . . . . . . . . . . . . . . . . . . . . . . . . . . 16
CDBUTIL MODES . . . . . . . . . . . . . . . . . . . . . . 16
GENERAL . . . . . . . . . . . . . . . . . . . . . . . 16
FUNCTION CALLING PROCEDURE . . . . . . . . . . . . . . 16
DISPLAY FILE INFORMATION . . . . . . . . . . . . . . . 17
UNFILTERED RECORD COUNT . . . . . . . . . . . . . . . 17
UNFILTERED COUNT TO MEMORY VARIABLE . . . . . . . . . 17
RECORD LISTING . . . . . . . . . . . . . . . . . . . . 18
MEMO FIELD DISPLAY . . . . . . . . . . . . . . . . . . 19
KEY PHRASE SEARCH THROUGH MEMO FIELD . . . . . . . . . 20
PROGRAMM-CONTROLLED MEMO WRITING . . . . . . . . . . . 21
SEPARATE .DBT FROM .DBF . . . . . . . . . . . . . . . 21
PACK MEMO FILE . . . . . . . . . . . . . . . . . . . . 22
SOURCE . . . . . . . . . . . . . . . . . . . . . . . . . 22
MAIN . . . . . . . . . . . . . . . . . . . . . . . . . 22
FUNCTION 1 . . . . . . . . . . . . . . . . . . . . . . 24
FUNCTION 2 . . . . . . . . . . . . . . . . . . . . . . 25
FUNCTION 3 . . . . . . . . . . . . . . . . . . . . . . 25
FUNCTION 4 . . . . . . . . . . . . . . . . . . . . . . 25
FUNCTION 5 . . . . . . . . . . . . . . . . . . . . . . 26
FUNCTION 6 . . . . . . . . . . . . . . . . . . . . . . 27
FUNCTION 7 . . . . . . . . . . . . . . . . . . . . . . 29
FUNCTION 8 . . . . . . . . . . . . . . . . . . . . . . 29
FUNCTION 9 . . . . . . . . . . . . . . . . . . . . . . 30
CDBUTIL.PRC FOR DBASE III . . . . . . . . . . . . . . . . 30
EXPLANATION . . . . . . . . . . . . . . . . . . . . . 30
PROGRAM . . . . . . . . . . . . . . . . . . . . . . . 31
INTRODUCTION

ASHTON-TATE's DBASE III has brought some of the power of
large-scale dbms to the PC. The C2DBASE functions add a little more
power and flexibility to this modern micro-dbms. C2dDBASE is meant for
those who are familiar with the C language, and can write auxillary
programs for specific purposes. With the C2DBASE functions, a C
programmer can:

-Use the files created by DBASE III outside of the DBASE
environment.

-Extract file statistics without DBASE (i.e. record cound,
field names, index fields, etc.).

-Write C programs that bring information into the DBASE
environment (i.e. mathematical functions, peripheral
status,etc.).

-Display memo fields as you meant them to be displayed, without
being limited by DBASE's limited formatting.

-Perform very fast keyphrase searching through memo fields in a
database. This capability brings to life the power of the memo
field.

-Separate a .DBT file from its associated .DBF file. This is
very useful where the .DBT file has been corrupted. DBASE will
not use a .DBF when it cannot find or read the .DBT.

-Squeeze out the wasted disk space inside a .DBT file. For those
who edit memo fields frequently, the amount of wasted space
inside the .DBT file would surprise you.

These are a few of the more obvious advantages to the C2DBASE
functions. Once you understand what these functions are, your own
creatively will provide you will many more advanatages and uses.

C2DBASE may be used inside or outside of DBASE. When used
inside, the DBASE command RUN is used to evoke the C program containing
the C2DBASE functions required to perform the task.
Used outside of DBASE, these functions can productively access
all of the files created and used by DBASE. With this version, the
information that can be extracted from an .NDX file is limited, but all
other file type are supported completely.

The C2DBASE functions are distributed under the Shareware
concept. The author assumes no responsibility for the damage a reckless
programmer can do to his client's database. Indeed, such a programmer
does not need these function to perform such damage.


OVERVIEW

FILES IN PACKAGE

The files distributed with this package are listed below. If you
are missing any of these files, the package you received is incomplete.
Upon registration, you will be sent a complete up-to-date program disk,
and printed documentation.

DBASE.LIB - This is the compiled library of C2DBASE functions.
It has been compiled using Lattice version 2.14 with the S-memory model.
Obtaining the source code for these functions will allow you to
re-compile using another memory model.

DBASE.H - This C header file must appear in any C program which
uses the C2DBASE functions. (i.e #include dbase.h). It contains the
definitions these functions require, including the important DBINFO
structure definition (see below for more information about this
structure).

CDBUTIL.C - The source code for the demonstration/utility
program.

CDBUTIL.EXE - The executible program using the C2DBASE
functions.

CDBUTIL.PRC - An illustrative DBASE procedure file showing how
the C2DBASE functions may be used inside of DBASE III.

C2DBASE.DOC - This documentation file

In addition to the above files, users of the registered package
will find the following files on the program diskette:

C2DBSORC.DOC - Source code for all C2DBASE functions

USER.HLP - Miscellaneous information, helpful tips and support
telephone numbers.


MODIFICATIONS & REVISIONS

NONE


THE DBASE FILE STRUCTURE

Although you do not need to know about the file structure of
DBASE, a few words may be in order. DBASE reserves several file
extensions for its specific use. The ones that are relevant to this
package are:

.DBF - a DBASE database file containing records of fixed length,
and predefined fields. A file header contains information about the
database.

.DBT - a file containing the text held in memo fields for a
given .DBF file. The .DBF and .DBT files will always have the same
filename. (i.e. DATA.DBF & DATA.DBT)

.NDX - an index file sorted on a key relevant to the .DBF file
to which it is associated. Each record in this file points to a record
in the .DBF file. The .DBF file will appear to be in the order of the
.NDX file.

.MEM - These files contain names and values of DBASE memory
variables. They may contain information for up to 256 memory variable.
The C2DBASE function "pass" writes a .MEM file to pass information to
DBASE. However, this version writes .MEM files holding a single
character variable. Later versions will have increased flexibility in
this area.

.PRG - these are program command files DBASE uses for
instruction.


THE DBINFO STRUCTURE

In order to efficiently use the C2DBASE functions, it is
necessary to become familiar with the structure used to hold all DBASE
information. This structure is more completely defined in the dbase.h
header file. (This header must be included in any program using the
C2DBASE functions.) Most of the ingredients of this structure are
automatically handled within the functions themselves, and should not be
touched by the programmer. The following is a list of those elements of
the structure that are relevant to the C programmer.

(Note:
static struct dbinfo dbase;
/*DBASE information structure-must be static*/ )

dbase.error - This variable will usually be zero if a called
C2DBASE function was successfully executed. If an error occurs, a
non-zero code will help to clarify what the error was. Each function has
its own set of error codes. Refer to the documentation of each function
for the list of error codes relevant to a particular function. The
dbase.error variable should be checked after each function call if there
is a posibility of an error. In all function documentation, this
variable is denoted as dbase->error.

dbase.ndxnum - This integer is equal to the number of index
files in use with the .DBF. C2DBASE assigns each index file a number
from one to ten. The first index specified receives a '1' assignment,
the second a '2', and so on. To refer to an index file inside of a
C2DBASE function it is only necessary to refer to its number. Of course
other ways to refer to index files are supported, but this particular
method proved convenient for me.

dbase.ndxfile[n] - This is an array of structures containing
information pertinent to index (.NDX) files that may have been
specified. Up to 10 index files may be specied for each .DBF file.
However, this version of the C2DBASE functions does not completely
support all aspects of the index files. The ndxfile structure includes
the following element -
dbase.ndxfile[n].name - 35 characters
dbase.ndxfile[n].fldnum - number of fields index in this .NDX
dbase.ndxfile[n].fields[10]-up to 10 field names, 11 bytes each

dbase.info - This is an array of miscellaneous information about
the .DBF file. Some of the relevant element of this structure are -
dbase.info.year - character\
dbase.info.month- character >last date of update
dbase.info.day - character/
dbase.info.quan -number of record in .DBF (long integer)
dbase.info.reclgth- bytes per record

dbase.fieldnum - An integer value equal to the number of fields
per record in the .DBF. The maximum number of fields is set by MAXFIELD
in the header file. (Presently 30)

dbase.field[n] - This is an array of structures containing .DBF
field information. The maximum legal value of n is the number of fields
per record for the .DBF file - dbase.fieldnum. Each structure contains
the following elements -
dbase.field[n].name - 11 characters
dbase.field[n].type - field type (C, D, N, or M)
dbase.field[n].length - field length (up to 255 bytes)
dbase.field[n].decimal- decimanl places if numeric


IMMEDIATE ERROR EXIT POINTS

N O T E:
The C2DBASE functions generally pass control back to the callin
function when they have completed, even in the case of an error. the
function reclist, onoffdbt, and pass have have error detection code that
result in an immediate program exit if particular types of errors occur.
Refer to the documentation for these functions for further information.


CDBUTIL - THE DBASE UTILITY PROGRAM

This package includes the C program CDBUTIL, which will
hopefully serve as example of how to program with the C2DBASE functions.
It uses many of the functions, and provides enough useful functionality
to whet the appetite of the non-programmer familiar with DBASE. It has
a somewhat cumbersome command line invocation structure, but the
documentation should be clear enough for most people familiar with
command line arguments. The program source is included and should be
examined by those wanting to use the functions.
Each mode of this utility program performs a specific task and
requires a specific argument list. This information is provided in a
help screen which is called up when CDBUTIL is executed without any
arguments. Examine this screen whenever you need to be refreshed on the
modes of the CDBUTIL program.


KNOWN BUGS

This version of C2DBASE (another is on the way) has a few
limitations, which may be considered bugs by some. If you are aware of
these limitations, you should have no trouble using these functions
reliably.

MEMO FIELDS:
The first limitation has to do with memo fields. Unless you
increase the value of MEMOMAX in the dbase.h header file, and re-compile
the code, the maximum length of any memo field should be less than 2048
bytes. Beyond this, trucation occurs, or searching is not performed
depending on the function.
More importantly perhap is the limitation of only one memo field
per record. If there are more than one memo field in a record, the
C2DBASE functions only process the first one. This oversight on my part
will be corrected in a later version.

INDEX FILE USAGE:
At present, .DBF files cannot be presented in indexed order.
For example, the reclist function cannot list records in indexed order.
In fact, the only thing you can do with index files, at this point, is
display information contained in their header (i.e. indexed fields,
index record length, etc.).

MULTI-TASKING ENVIRONMENTS:
I have had a few difficulties running these functions in some
MS-DOS multi-tasking environements. When I have enough time to sit down
and understand the problem, or if the problem causes enough of an
outcry, I will correct. I may be wrong, but not many of you are running
under such environments.


REGISTRATION

WHY REGISTER

My expectation is that this package will appeal to a unique few.
Those who know and delight in both the C language and DBASE III, are
rare enough. Of thoses people, this package will not interest all of
them. If you find yourself even marginally interested in the
capabilities that this package provides, consider yourself unique. One
of the responsibilities of this uniqueness is that you register this
package.
Registration gives you several tangible and intangible benefits.
Some of the intangibles include giving support to others like yourself,
and encouraging the Freeware concept of software development. By now
you are familiar with what that is, and why it is the only alternative
to high-priced software.
Some of the more tangible benefits of registration are:

-All the source code for the C2DBASE functions are sent to
registered users. Aside from giving you the power to modify
these functions, there is a lot to learn about DBASE III from
the examination of this source code.

-The unregistered documentation file is incomplete and not
paginated. Although the amount left out is not a lot, it could
prove helpful if you are attempting to modify the functions, or
recompile for any reason. The pages refered to in the table of
contents are not coordinated with the text of the file. This was
done for convenience. Registered users will receive the complete
documentation in printed form.

-During the evolution of the C2DBASE functions, registered users
will continue to receive free updates of newer versions. The
following improvements are planned for the not-too-distant
future:
-better support for .NDX files and indexing functions
-multiple variables returned with the 'pass' function
-support for multiple memo fields
-database recovery provisions
-improved CDBUTIL modes

-Only registered users may contact me for support of any kind.
I will be very happy to hear from those who are interested in
this package. I know you are interested if you register. If you
are having any trouble incorporating these functions in your
programs, or have any suggestions on improving them, please
write, or call the number listed in your registration package.
( I may even be convinced to provide customized functions for
registered users.)


HOW TO REGISTER

To register this package, send your name and mailing address,
along with $15 to:

COMPSCAN
60 East Water Street
North Andover, Mass 01845

You will receive the newest version of the C2DBASE package,
printed documentation, including source code for all the library
functions, additional tips helpful if you wish to modify the functions
in any way,and hotline telephone numbers for support.
If you intend to use this package, register it at your earliest
convenience so that support is available to you, if and when you should
need it.


FUNCTION DESCRIPTIONS

INTRO

What follows is a function description for each of the functions
found in DBASE.LIB. As you read them, let your creative juices flow,
and see how you may use each of them to solve some problem or other, or
otherwise make things more convenient for you.


DBHEADER

SYNOPSIS:
dbheader(dbfile,dbase)

char *dbfile; /*file to be examined*/
struct dbinfo *dbase; /*structure to be filled*/
----------------------------------------------------------------
This routine reads a dbase file header and determines the
database file information, which includes memo flag,date,number of
records,record length, file name, field names and type.
-filename (dbfile) may include directory paths.
-.DBF extension MUST be included in filename.
-Maximum record length is 512 bytes (dbase.h).
-Maximum fields per record is 30 (dbase.h).
The routine initializes a structure (dbase) containing the dbase
file information (see dbase.h - structure dbinfo) and returns the level
1 file number for further use. This routine should be the first routine
used to interface with a .DBF file, and it should be used only once
since it resets a number of variables in the structure. The dbinfo
structure error variable should be checked for a non-zero value
indicating an error was detected. The error code meanings are:
1 = no .DBF extension in filename
2 = cannot open dbfile
3=not recognized as a DBASE file, despite the .DBF
extension
4 = cannot open associated .DBT file
5 = not assigned yet
NOTE: .DBT file must be in same directory as the .DBF file
*/


DBSTAT

SYNOPSIS:
dbstat(info)
struct dbinfo *info;
----------------------------------------------------------------
This routine displays ( on stdout) the status information of the
.DBF file whose characteristics are passed in the struct info. The
information includes any index files that have been previously linked to
the .DBF file with the function NDXREAD.



RECREAD

SYNOPSIS:
char *recread(dbase,recnum)
struct dbinfo *dbase;/*file information structure*/
long recnum;/*record number to return*/
----------------------------------------------------------------
This routine reads the records of the file whose information
parameters are in the dbase structure. A pointer to the contents of
record number "recnum" (which must be a LONG integer) is returned. The

record contents are contained in a character buffer which must be parsed
for the record fields by the calling routine. If recnum specifies a
record that is not in the database, the returned pointer will be NULL,
and dbase->error will be non-zero. The meaning of the error codes are
as follows;
1 = record not in database
2 = code not yet assigned
Please note that this function returns a character
pointer and must be declared as such in the calling program.


RECLIST

SYNOPSIS:
reclist(dbase,start,end)
struct dbinfo *dbase;
long start,end; /*starting & ending records to list
---------------------------------------------------------------
This routine prints (on stdout) the unindexed records of a dbase
.DBF file described in the structure info. It takes three parameters,
the first being the ubiquitous DBINFO structure pointer, the second is
the record number (LONG) where the listing is to start, and the third is
the record number (also LONG) where the listing is to end. Ending
numbers larger than the number of records in the database are
interpreted as the largest record number. A starting record number of
zero will be interpreted as a 1.
This function does a complete program exit (with ERRORLEVEL set
to 1) if it is requested to list a record number that is not in the
database.


RECWRITE

SYNOPSIS:
recwrite(dbase,record,string)
struct dbinfo *dbase;
long record;/*record number to write*/
char *string;/*record string to write*/
----------------------------------------------------------------
This function writes a record to the .DBF file specified by the
DBASE structure pointer. If the record specified by the passed parameter
'record' (which is a LONG integer) is less than the total number of
records in the .DBF file, then record number 'record' is replaced by the
character string 'string'. If 'record' is larger than the number of
records in the database, then a new record is appended, and the record
number is incremented. Please note that this version does not support
index files, so this function should only be used on databases that are
not indexed, or where the indexed fields will not be changed and the
number of records will remain the same. It is the responsibility of the
programmer to make cetrtain that this is so. The programmer is also
responsible to make certain that 'record' is correct for the database
being used. Please be careful. You could screw up the .DBF file with
this one if these cautions are not observed.
Upon successful completion, the function returns a zero if the
record was replaced, and a one if the record was appended. In both
cases, the dbase->error variable will be zero. If an error has been
detected, a -1 will be returned and the error variable will be non-zero,
with the following error codes;
1 = Cannot reopen .DBF file.
2 =Premature end-of-file or file positioning error
3 =.DBF write error


NDXREAD

SYNOPSIS:
ndxread(dbase,ndxfile)
struct dbinfo *dbase;
char *ndxfile; /*.NDX filename*/
----------------------------------------------------------------
This routine opens a .NDX file, checks it for various errors,
and fills the "dbase" structure with the pertinent information
concerning the named .NDX file - "ndxfile",which must contain the full
path (default directory assumed if path is missing) of the file to be
read (including extension). The maximum number of indexed fields
allowed is presently 10 (MAXFIELD/3). The structure for the .NDX file
information will be found in the dbase.h header file. If successful,
the variable dbase.error will be equal to zero, the "dbase" structure
will be updated with the index file information and the order number
(from 1 to 10) of the index file will be returned. (NOTE: the subscript
number of the .NDX file in the 'dbase' structure will be the order
number minus 1.) If an error condition is detected the "dbase" structure
will not be updated and dbase.error will be non-zero. The meaning of
the various codes are;
1 = named file does not have .NDX extension
2 = cannot open named .NDX file
3 = .NDX file is indexed on fields that are not in the .DBF file
4 =
NOTE: The 'dbase' structure can contain up to 10 index files.

DBASE NOTE: DBASE allows indexing on complex keys -i.e. INDEX ON
LEN(TRIM(SUBSTR(character field))). This C2DBASE function
can only handle one DBASE modifier on the field - i.e. LEN(field) not
LEN(TRIM(field)). Fields with multiple function modifiers will be seen
as a mismatching field, and cause an error 3.


NDXSTAT

SYNOPSIS:
ndxstat(dbase,ndxorder)
struct dbinfo *dbase;
intndxorder;
----------------------------------------------------------------
This function displays (on stdout) information about the index
file associated with the index order number "ndxorder". This function
is called by "DBSTAT". If the function executes succesfully, the return
value will be zero, dbase->error will be zero, and the information will
be displayed. If it is not succesful, no information will be displayed,
the return value will be non-zero, and an error code will be placed in
dbase->error. The error codes are:
1=ndxorder exceeds the number of index files with the .DBF
2=error code not yet assigned


MEMOREAD

SYNOPSIS:
char *memoread(dbase,rec)
struct dbinfo *dbase;
long rec;/*record number to read*/
----------------------------------------------------------------
This routine returns a pointer to the .DBT memo text of the
record specified in the passed parameter "rec" (which must be a LONG).
The function must be declared as a character pointer in the calling
function. The record is assumed to have only one memo field. The
"dbase" parameter is the dbinfo structure of the .DBF file, which must
have been previously filled using the "dbheader" function. The largest
memo field which can be read is 2048 bytes, which should be good enough
for most applications. If a larger field is needed change the MEMOMAX
variable in "dbase.h". The routine returns a char pointer to the memo
field string, unless an error is detected. An error detection returns a
NULL pointer and sets "dbase->error" to one of several error codes.
These are;
1 = .DBF file does not have associated .DBT file
2 = record has no memo field (no .DBT)
3 = record has an empty memo field pointer
4 = error reading .DBT file
5 = memo text too long (valid pointer returned anyway)
6 = not assigned yet

NOTE: This function can only handle .DBT files which contain no
more than 65535 memos.

NOTE: This function also contains another function called
memptr, which returns the unsigned value of the memo field pointer.


TEXTFIND

SYNOPSIS:
textfind(dbase, record, string)
struct dbinfo*dbase;
longrecord;/*record number to search*/
char*string;/*string to search for*/
----------------------------------------------------------------
This function looks at the record content and memo text (if
applicable) for the specified record, given as a LONG integer, and
searches for 'string'. If found, the function returns a one (1). If
the search is unsucessful, a zero (0) is returned. Capitalization is
ignored ("abc" = "ABC"). If the function detects an error, a -1 is
returned, and dbase->error will be non-zero, with the following error
codes presently specified;
2 = search string is NULL
3 = error reading .DBT file

As is presently the case in all the C2DBASE functions that deal
with memo fields, only one such field per record is assumed. If more
than one exist, only the first memo field will be processed.


MEMOADD

SYNOPSIS:
memoadd(dbase,rec,text)
struct dbinfo *dbase;
long rec;/*record number*/
char *text;/*pointer to memo text*/
---------------------------------------------------------------
This function replaces the memo field of the record "rec", which
must be a LONG integer, with an ASCII text file, specified in "text".
The original memo field pointer is returned by this function (as an
unsigned integer) upon successful completion. If an error is detected,
a -1 is returned and the error variable - dbase->error- will be set to
one of the following error codes:
1=record does not have a memo field
2=cannot open specified text file
3=cannot re-open .DBT file
4=code not yet assigned

As is presently the case in all the C2DBASE functions that deal
with memo fields, only one such field per record is assumed. If more
than one exist, only the first memo field will be processed.

NOTE: The maximum file length that can be read into the .DBT
file is 2048 bytes for each record. Any text beyond this length will be
truncated and a warning message will be displayed on stdout. This
should be sufficient for most applications. If more than this is
required, increase MEMOMAX in the dbase.h header file.

NOTE: This function may be used to input memo field data under
program control (something DBASE presently has no provisions for). Using
the run command, your favorite editor can be evoked to create the text
file, then this function is used to bring that text file into the .DBT
file and set the memo pointer of the record. (see CDBUTIL)

NOTE: a -1 is the same as 65535, so a check should be made on
the error variable to see if it is non-zero (unless, of course, you are
sure their isn't 65535 memos in the .DBT).


ONOFFDBT

SYNOPSIS:
onoffdbt(dbase,mode)
struct dbinfo*dbase;
int mode; /* 0 removes .DBT, 1 attaches .DBT*/
----------------------------------------------------------------
This function is useful if a .DBT file becomes corrupted or
otherwise unuseable. DBASEIII will not allow a .DBF file that has an
associated .DBT file to be used if the .DBT file is not available or
otherwise unreadable. There may be occaisions where the .DBF file may
have to be used without the .DBT file as may be the case when the .DBT
file has become corrupted or damaged. This function will turn the
DBASE.DBT search function on and off. If the .DBF file is to be used
without its associated .DBT, the mode parameter should be zero. This
can be reversed ( if the .DBT latter becomes available, or something),
by running this function with a mode of one.
.DBF files that originally had no memo fields, cannot be
associated with a .DBT file, and running this function in mode one, will
leave these files unaffected.
In mode one, this function verifies the existence of the .DBT
file in the same directory as the .DBF file. If it is not found, and
error results and the .DBF is not changed.
A zero is returned upon successful completion, otherwise a -1 is
return with one of the following error codes in dbase->error;
1 = could not find .DBT file (mode one)
2 = database has no .DBT file (mode one)
3 = invalid mode number passed

NOTE: A write error on the .DBF file will cause an immediate
exit from the program with an dos ERRORLEVEL of 4.


DBTPACK

SYNOPSIS:
dbtpack(dbase)
struct dbinfo *dbase;
---------------------------------------------------------------
DBASEIII deal with memo files (.DBT) fairly inefficiently. Each
record in the .DBF file, if it has a memo field, points to a particular
offset into the .DBT file. When you change, delete, or otherwise modify
a memo field, the old one is still left intact, but a new one (your
modified memo) is appended to the bottom of the file, and the record
pointer updated. If you are in the habit of making a lot of changes to
your memo fields (which becomes a more reasonable thing to do since you
now have these functions), the .DBT file may contain a lot of wasted
disk space. This function writes a new .DBT file, copying only the
relevant text to it. The old .DBT file is left intact with a .BAK
extension. The only way you can accomplish with DBASE III is to copy
your database over entirely, which consumes more disk space since both
the .DBF and the .DBT gets duplicated. Try this function on a few of
your .DBT files and see the difference in disk size.

The only required parameter to this function is a pointer to the
dbinfo structure. If successful it returns a zero, otherwise a -1 is
returned, and 'dbase->error' will be one of the following error codes;
1 = database has no .DBT file
2 = Cannot open original .DBT file
3 = Cannot create new .DBT file
4 = Error writing to new .DBT file
5 = Error updating .DBF file
6 = TBDL

As is presently the case in all the C2DBASE functions that deal
with memo fields, only one such field per record is assumed. If more
than one exist, only the first memo field will be processed.

NOTE: Memo text fields longer than MEMOMAX (presently 2048)
bytes, with be truncated to that length. MEMOMAX, the #define in the
header file may be increased, if this poses a problem.

NOTE: Make sure there is enough disk space before performing
this function. The most free space that will be needed will be equal to
the size of the original .DBT file.

NOTE: If you feel a bit queasy about using this function on your
valuable database files, make a copy of them first, test out the new
files, then you can dispose of the originals. Always wise to be safe.


PASS

SYNOPSIS:
pass(param,dir)
char *param;/*string variable to pass to DBASE */
char *dir;/*directory to write RETURN.MEM file*/
----------------------------------------------------------------
This function, along with a few DBASE program statments, passes
one parameter to DBASE's memory variable area. This is done by writing
the variable 'param', which must be a character string pointer (numbers
must be converted to character strings), to a file in the directory
specified by the string pointer 'dir' (dir=NULL will default to the
current directory). This file will be called RETURN.MEM. The parameter
is recovered from DBASE by the program statement:
RESTORE FROM RETURN ADDITIVE
The parameter will be named RETPARAM, and will then be
accessible (privately) to the DBASE program that called the function.
To make the passed parameter generally available (global), the following
program statement should appear before the C function is called;
PUBLIC RETPARAM
If the creation of RETURN.MEM is successful, a zero is
returned by this function. Otherwise an error message is displayed and
the program exits immediately.

NOTE: Since the "\" character always gets interpreted as "ESC"
in 'C',the forward slash - "/" - must be substituted in its place when
specifying the directory for the 'dir' parameter.

NOTE: if this function is used repeatedly in a DBASE program,
either delete RETURN.MEM before each use, or SET SAFETY OFF to avoid the
overwrite message and prompt.

PROGRAMMER'S NOTE: This function uses the global structure cmem,
which is of type cmemvar. (see dbase.h for details)



DBCLOSE

SYNOPSIS:
dbclose(dbase)
struct dbinfo *dbase;
----------------------------------------------------------------
This function closes all the files associated with the C2DBASE
functions and the .DBF file that are currently open. It should always
be the last C2DBASE function called, so as to prevent accidents
happening (which open files are prone to have).The only passed parameter
to this function is the pointer to the dbinfo structure.


CDBUTIL

CDBUTIL MODES

GENERAL

The CDBUTIL program has been provided for two reasons. First and
foremost, as an example of how to use the C2DBASE functions - hence the
inclusion of the source code. No special programmig techniques were
used, nothing especially witty or stupendous. But it is a good place to
start learning how to use these functions. If you are serious about
DBASE III, but don't like it's limitations, and if you are familiar with
the 'C' language, then you can turn DBASE III into DBASE IV (enough
superlatives). The CDBUTIL program will also be very useful to those
who haven't the knowledge and/or the inclination (there are those, God
luv'em) to get into programming. The program, with its modes, extends
the capabilities of DBASE III enough to be appreciated, but to get the
full power of C2DBASE, you need to be able to write C programs. For
those of you who aren't already familiar with the language, this may be
some small incentive to learn.
The CDBUTIL program may be used inside or outside of DBASEIII.
If it is being used inside of DBASEIII, it is best to incorporate it
into .PRG and .PRC command files to extend the capabilities of DBASEIII.
An example of such a .PRC file is also included with this package.
Certain modes (such as packing a memo file) should only be used,
when not in DBASE. Other modes (such as listing record) make no sense
to use inside of DBASE. They are provided to give you access to your
databases without DBASE. Still other modes (such as keyword searchs,
programmed-controlled memo writing, count to memory variable, etc.) only
make sense when using them inside of DBASE. I have experienced some
small difficulty in running CDBUTIL in a multitasking environment. My
present guess is that the 20 file limit set for MS-DOS was exceeded.
These difficulties disappeared when I re-instated regular DOS.
The CDBUTIL program should reside in the directory you are
using, unless it is in your PATH, or you have a utility which allows you
to run programs from other directories.
Any time CDBUTIL performs an error exit, the DOS ERRORLEVEL will
be set to 1.
The CDBUTIL modes only scratch the surface of the possibilities
of C2DBASE. Creativity will extend the flexibility and power with which
you can manipulate your databases.


FUNCTION CALLING PROCEDURE

CDBUTIL is a collection of useful functions gathered into one
program. The modes are numbered, and each mode expects a specified
argument list. "CDBUTIL ?", "CDBUTIL HELP", or just plain "CDBUTIL"
will display a list of the modes available and the argument list
required. The included modes are discussed in more detail below.
Parameters indicated with < > are required, while parameters indicated
with [ ] are optional.The source code for the CDBUTIL program is also
included as an example of how to program with the C2DBASE functions.


DISPLAY FILE INFORMATION

MODE 1 - DISPLAY FILE INFORMATION
=====================================
CALLING STATEMENT- CDBUTIL 1 [NDXfile NDXfile...]

This mode displays the database information of the specified
file. The display is self-explanatory. NDXfiles (optional) may be
specified in the calling statement. The complete pathname may be used
to examine files in foreign directories. If NDXfiles are also
specified, their extensions are assumed to be .NDX if they are not
present. They are also assumed to be in the same directory as the .DBF
file, and their PATH should not be specified. If one of the index files
cannot be found, the mode aborts and no display is given.
This mode should be used outside of DBASE III.


UNFILTERED RECORD COUNT

MODE 2 - UNFILTERED RECORD COUNT
================================
CALLING STATEMENT - CDBUTIL 2

If there are large databases in your work, and periodically you
need to know how many records are contained therein, you can use DBASE's
COUNT command, which could take awhile (minutes with databases in excess
of 1000 records). Or you could use mode 2 or 3 of CDBUTIL. mode 2
displays the unfiltered record count on the terminal screen. This count
will include all records, including thosed marked for deletion, or
filtered out-of-sight. Pathnames are allowed, and the .DBF extension is
assumed.
This mode may be used inside or outside of DBASE III.


UNFILTERED COUNT TO MEMORY VARIABLE

MODE 3 - UNFILTERED COUNT TO MEMORY VARIABLE
============================================
CALLING STATEMENT - CDBUTIL 3

This mode is the same as mode 2 except that the count result is
placed in a .MEM file, in the same directory as the .DBF file, so that
it may be RESTORED (ADDITIVE), and made available to DBASE III. For
further details please examine the CDBUTIL.PRC program, the
documentation on the C2DBASE "pass" function, and the DBASE manual on
.MEM files.Although the "pass" function is a bit limited in this version
of C2DBASE, this CDBUTIL mode is an example of how external programs may
brings results and answers into DBASE III for processing. If you would
like to extend the mathematical capability of DBASE, and can code up
what you want in 'C', then DBASE is mathmatically limited only by your
creativety and knowledge.

NOTE: The maximum number of records that can be processed with
this CDBUTIL mode is 65535. This is a limitation of CDBUTIL, not
C2DBASE.


RECORD LISTING

MODE 4 - RECORD LISTING
========================
CALLING STATEMENT - CDBUTIL 4 [rec. range]

This mode lists the records of a database file. All the records
contained in the file will be listed unless the optional [rec. range]
is given, in which case only those records (inclusively) will be listed.
The records are listed in numerical order.
The .DBF extension is assumed if not present, and a pathname may
be given for the .DBF file.
As presently programmed, records longer than 80 bytes will wrap
around the screen, similar to DBASE III. I find this annoying, and will
probably program some formatting options, or specific field request
capabilities into CDBUTIL in the next version. Since the source for
CDBUTIL is given, you may do the same if you don't feel like waiting for
me.
DBASE gives a better listing of .DBF records, so this mode need
only be used when outside of DBASE to view database records.


MEMO FIELD DISPLAY

MODE 5 - MEMO FIELD DISPLAY
===============================
CALLING STATEMENT - CDBUTIL 5 [[+],[-],[-rec#]]

This mode simply illustrates the use of the 'memoread' C2DBASE
function. With this, and a few other C2DBASE functions, the memo fields
in DBASE III can really be put to use. This memo field display CDBUTIL
mode only begins to tap the power, and is provided as much for example
as for usefulness.
CDBUTIL mode 5 displays the memo field for the record specified.
If the .DBF specified does not have a memo field, an exit with
ERRORLEVEL 1 is performed. If the record specified has no memo text in
its field, a message is displayed saying so.
If a '+' appears after the record number (i.e. 1745+), then all
records starting with the one specified will have their memo field
displayed. If a '-' appears after the record number (i.e. 135-), then
all records starting with the first and ending with the one specified
will have their memo field displayed.If a starting and ending record
number is given (i.e. 657-700), then the memo fields for those records,
inclusive, will be displayed. Of course, starting number must be lower
than ending number, or else...
DBASE III gives very little control over how the memo text is
displayed. Unless the report generator is used, you are limited to a
display of 50 columns with an unjustified right edge. This is so no
matter how the text is actually formatted. If you use another word
processor to write the text, and format it as you desire, you are still
limited to DBASE's format. The report generator gives a bit more
flexibility, but not much. With this mode of CDBUTIL, the display will
appear formatted as you typed it.
Please read the documentation for 'memoread' for other
restrictions and limitations on using this mode. Refer to CDBUTIL.PRC
on how to use this mode inside of DBASE III.

NOTE: DBASE III version 1.2 allows much greater flexibility over
the formatting of displayed memo fields. If you have this version,
check out this capability before you use this mode. you may like it
better.


KEY PHRASE SEARCH THROUGH MEMO FIELD

MODE 6 - KEY PHRASE SEARCH THROUGH MEMO FIELDS
==============================================
CALLING STATEMENT - CDBUTIL 6 [rec. range]

Here's where we begin to see what we can do with some of the
C2DBASE functions. DBASE III provides no capability to use the memo
field beyond simple text holders. With DBASE III, you cannot search the
memo field for keywords, and you cannot do a listing based on the
contents of the memo field.
This mode of CDBUTIL searches the memo fields of a database, and
lists (on stdout) all records whose memo field contains the keyword
. If a record range is provided (optional), it is given in the
form xxx-xxx (i.e 546-601). In this case only those records specified
in the range will be searched for the keyword. For each record examied
that does not contain the keyword or keyphrase, a dot is printed to give
the user some feedback that the program is proceeding.
The keyword search is not case specific. It will find a match
on both upper and lower case.
Since a space between words on the command line will be
interpreted as a different argument, spaces are designated by the
underscore character '_'. In other words, in order to find "the phrase"
it must be written as "the_phrase". To find "one two three" it is
necessary to specify it as "one_two_three". This inconvenience comes
about from DOS's commandline parsing. In a latter version, I expect the
calling statement for this mode to be made more convenient.
With a little imagination and creativity, the memo field can be
made to perform some very useful work.


PROGRAMM-CONTROLLED MEMO WRITING

MODE 7 - PROGRAMM-CONTROLLED MEMO WRITING
=========================================
CALLING STATMENT - CDBUTIL 7 [del]

Presently DBASEIII provides no way to write in the memo field
under program control. To edit the memo field, you must be in record
edit mode (possible under program control), manaully place the cursor on
the field, then press ctrl-pgdn. When writing applications for
end-users, this may be cumbersome, or inconvenient. This CDBUTIL mode,
along with the appropriate statements in a .PRG or .PRC file (see
CDBUTIL.PRC), and an external word-processor, provides the capability of
writing memo fields under program control.
This capability is a two-step process. First a textfile must be
created on disk keeping in mind any size restrictions coming from the
'memoadd' C2DBASE function. This may be done by using the RUN command
to invoke your wordprocessor (i.e. RUN ED file.txt). Once the file is
on disk, CDBUTIL mode 7 will bring it neatly into the .DBT file, and
update the specified record. Refer to the CDBUTIL.PRC documentation for
further clarification.
To use mode 7, the required parameters are as shown above.
Pathnames for both the DBFfile and the textfile is permitted. The
DBFfile extension may be ommitted, but the textfile must have an
extension. The record number must exist in the database. If "del" is
specified (optional), the textfile is deleted after successful
incorporation into the .DBT file.
You now have a choice in how you create your memo fields. DBASE
III's ^Kr, when you are in its word processor, will also read in a text
file from disk, but first you have to be in the word processor. This may
not be much of an inconvenience at all. It is probably better to use
DBASE's own facilities when it does not interferre with what you want to
do or the convenience with which you do it.


SEPARATE .DBT FROM .DBF

MODE 8 - DISCONNECT/CONNECT .DBT FILE
=====================================
CALLING STATEMENT -

This mode implements the C2DBASE 'onoffdbt' function. Please
read the documentation for this function in order to understand how to
use this DBUTIL mode. The submode is zero when you want to divorce the
.DBT file from the .DBF file. The submode is one when you want to
establish that connection again. If this sound fuzzy, refer to the text
on the 'onoffdbt' function.
This mode should only be used outside of DBASE III.


PACK MEMO FILE

MODE 9 - PACKING .DBT FILE
==========================
CALLING STATEMENT -

This mode implements the C2DBASE 'dbtpack' function. Please
refer to the documentation on this function to understand what this mode
is doing, when to use it, and the limitations which must be observed.
This mode should only be used outside of DBASE III.


#include "\lattice\h\glfstdio.h"/*greenleaf header*/
#include "\lattice\h\dbase.h"
#include "\lattice\h\fcntl.h"/*Lattice Header*/
#include "\lattice\h\ctype.h"/*Lattice header*/
#include "\lattice\h\disk.h"/*Greenleaf header file*/
/*modify the above PATHs for your own system*/

static char *help[]={
"DBASE UTILITIES PROGRAM version 1.0 Lee Mowatt - 10/85",
" To perform a particular function, the command line or the RUN string",
"takes the following generalized form;",
"CDBUTIL <.DBF file> [argument list]",
" (from DOS)",
"or",
"RUN CDBUTIL <.DBF file> [argument list]",
"(from inside DBASE III)",
"\n",
"FUNC. #FUNCTIONARGUMENT LIST",
"======================================================================",
" 1 Database information [NDXfile NDXfile...]",
" 2 Unfiltered record count ",
" 3 Count to memory variable ",
" 4 Record listing [rec.range]",
" 5 Memo field display [[+],[-],[-rec#]]",
" 6 memo field searching [rec. range]",
" 7 memo field from textfile [del]",
" 8 disconnect/connect .DBT <0 or 1> ",
" (0=disconnect, 1=connect)",
" 9 Pack a .DBT file ",
" NOTE: [rec. range] is given in the form start#-end# (i.e. 12-234)",
NULL
};

struct commlist
{
int argnum;/*# of args on commandline excluding CDBUTIL*/
char *args[20];/*in-program argument string pointers*/
};

/*the following defines help in reading the function source code*/
#defineFUNCfiles->args[0]
#defineDBFILEfiles->args[1]
#define NDXFILE(x)files->args[x+1]
#define RECNUMfiles->args[2]
#define PHRASEfiles->args[2]
#define RANGEfiles->args[3]
#define SUBMODEfiles->args[2]
#define TXTfiles->args[3]

main(argc,argv)

int argc;/*number of arguments*/
char *argv[];/*argument string pointers*/

{
struct commlist arglist;/*argument structure*/
int loop,count;/*general purpose integer variables*/
int function;/*C2DBASE function number*/
int fnum;/*DBF file number*/
static struct dbinfo db;/*DBASE information structure-must be static*/
char *ext=".dbf";/*DBF file extension*/
char *path;/*file path name*/
char *stpchr();/*Lattice function*/

if ((argc==1) || (isdigit(argv[1][0]) == 0))
{
for (loop=0;help[loop] != NULL;loop++)
printf("%s\n",help[loop]);
exit(0);
}
for (loop=0;looparglist.args[loop]=argv[loop+1];
arglist.argnum=argc-1; /*program name not included in argument list*/

path[0]=NULL;
strcat(path,argv[2]);
if (stpchr(argv[2],'.') == NULL)/*add DBF extension if not present*/
strcat(path,ext);
fnum=dbheader(path, &db); /*fill information structure*/
if (db.error != 0) /*check for error*/
{
switch (db.error)
{
case 1:
printf("\7Filename MUST have .DBF extension\n");
exit(1); break;
case 2:
printf("\7Cannot open %s\n",path);
exit(1); break;
case 3:
printf("\7Not a DBASE .DBF file\n");
exit(1); break;
case 4:
printf("\7Cannot open associated .DBT file.\n");
exit(1);break;
default:
printf("Unknown error code - %d\n",db.error);
exit(1); break;
}
}

stcd_i(argv[1],&function);/*convert decimal string to integer*/
switch (function)
{
case 1:
func1(&db,&arglist);break;
case 2:
func2(&db,&arglist);break;
case 3:
func3(&db,&arglist);break;
case 4:
func4(&db,&arglist);break;
case 5:
func5(&db,&arglist);break;
case 6:
func6(&db,&arglist);break;
case 7:
func7(&db,&arglist);break;
case 8:
func8(&db,&arglist);break;
case 9:
func9(&db,&arglist);break;
default:
printf("\7Unknown CDBUTIL function number\n");break;
}
dbclose(&db);
}


/**********************************************************************/
func1(dbase,files)/*display file information*/

struct dbinfo *dbase;
struct commlist *files;

{
int loop;
char *stpchr();/*Lattice function*/
char *string,*temp;/*general purpose caharacter pointer*/
char *path;/*pathname*/
char c=0x5c;/*ascii number for '\'*/
char *ext=".ndx";/*index extensionto be appended if not present*/

for (loop=3;loop<=files->argnum;loop++)/*process index files*/
{
if ((string=stpchr(DBFILE,c)) != NULL)/*PATH processing*/
{
while ((temp=stpchr(string,c)) != NULL)
string=temp+1; /*find last '\'*/
stccpy(path,DBFILE,(string-DBFILE+1));
}
strcat(path,NDXFILE(loop-2));
if (stpchr(path,'.') == NULL)
strcat(path,ext);
ndxread(dbase,path);
/*test for errors*/
if (dbase->error !=0)
{
switch (dbase->error)
{
case 1:
printf("\7Index file must have .NDX extension\n");
exit(1);break;
case 2:
printf("\7Cannot open %s\n",path);
exit(1);break;
case 3:
printf("\7Wrong index file for database being used\n");
exit(1);break;
default:
printf("\7Unknown ndxread error code-%d\n",dbase->error);
exit(1);break;
}
}
}
dbstat(dbase);/*display files information*/
}


/**********************************************************************/
func2(dbase,files)/*unfiltered record count to screen*/

struct dbinfo *dbase;
struct commlist *files;

{
printf("%ld records in %s\n",dbase->info.quan,dbase->filname);
}


/**********************************************************************/
func3(dbase,files)

struct dbinfo *dbase;
struct commlist *files;

{
char count[10];/*string of record count*/
char c=0x5c;/*ascii number for '\'*/
char *string,*temp;/*general purpose string variables*/
char path[35];/*directory to write .MEM file*/
char *stpchr();/*Lattice function*/

stci_d(count,(int)(dbase->info.quan),10);/*convert record number to string*/

if ((string=stpchr(DBFILE,c)) != NULL)/*PATH processing*/
{
while ((temp=stpchr(string,c)) != NULL)
string=temp+1; /*find last '\'*/
stccpy(path,DBFILE,(string-DBFILE));
}

pass(count,path);
}


/**********************************************************************/
func4(dbase,files)/* record listing*/

struct dbinfo *dbase;
struct commlist *files;

{
char *range;
long start,end,strtol();
char *string,*record,*stpchr();
char *temp;

if ((files->argnum < 3) || (isdigit(files->args[2][0]) == 0))
{start=1L;end=dbase->info.quan;}/*no range specified,do all records*/
else
{
range=files->args[2];
string=stpchr(range,'-');
strxlf(record,range,(string-range));
start=strtol(record,&temp,10);
strxrt(record,range,strlen(range)-(string-range+1));
end=strtol(record,&temp,10);
}

reclist(dbase,start,end);
}


/**********************************************************************/
func5(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
char *memoread();/*C2DBASE function*/
char *memotext;/*text pointer*/
char *memoname;/*name of memo field*/
char *stpchr();/*Lattice function*/
long rec,start,end;/*record numbers*/
int fieldspace;/*length of memo text*/
int count;/*general purpose integer variable*/
long strtol();/*Lattice function*/
char *temp,*record;

for (count=0; countfieldnum; count++) /*check that there is a memo field*/
{
if (dbase->field[count].type == 'M')
memoname=dbase->field[count].name;
}
memoread(dbase,1L); /*see if this function returns an error*/
if ( (dbase->error == 1) || (dbase->error == 2) ) /*no memo fields to be read*/
{
printf("No memo field in this database\n");
exit(1);
}
if (stpchr(RECNUM,'+') !=NULL)
{
start=strtol(RECNUM,&memotext,10);/*record specified*/
end=dbase->info.quan;
}
else
{
if ((temp=stpchr(RECNUM,'-')) != NULL)
{
if (strlen(RECNUM) > (temp-RECNUM+1))/*range specified*/
{
strxlf(record,RECNUM,(RECNUM - temp));
start=strtol(record,&memotext,10);
strxrt(record,RECNUM,strlen(RECNUM)-(temp-RECNUM+1));
end=strtol(record,&memotext,10);
}
else
{
start=0L;
end=strtol(RECNUM,&memotext,10);
}
}
else
{
start=strtol(RECNUM,&memotext,10);
end=start;
}
}
for (rec=start;rec<=end;rec++)
{
memotext=memoread(dbase,rec);
if ((dbase->error == 0) || (dbase->error == 5))
{
printf("\n***%s for record %ld***\n",memoname,rec);
fieldspace=strlen(memotext);
for (count=0;countbdos(6,memotext[count]);
printf("\n");
if (dbase->error == 5)
printf("Display truncated.Memo text longer than 2048 characters\n");
}
else
{
switch (dbase->error)
{
case 3:
printf("no memo text for record %ld\n",rec);break;
case 4:
printf("error reading .DBT file\n");break;
default:
printf("Unknown memoread error -#%d\n",dbase->error);
break;
}
}
}
}


/**********************************************************************/
func6(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
char *memoread();
long rec,start,end;/*record numbers*/
char *temp,*string,*record;/*general purpose string variable*/
char *stpchr();
long strtol();/*Lattice function*/
int find,found=FALSE;/*find status of textfind function*/
int loop,count;

memoread(dbase,1L); /*see if this function returns an error*/
if ( (dbase->error == 1) || (dbase->error == 2) ) /*no memo fields to be read*/
{
printf("No memo field in this database\n");
exit(1);
}

count=strlen(PHRASE);
for (loop=0;loop{
if (PHRASE[loop] == '_')
PHRASE[loop] = 0x20;
}

if ((files->argnum < 4) || (isdigit(RANGE[0]) == 0)) /*no range specified*/
{start=1L;end=dbase->info.quan;}
else
{/*range given*/
string=stpchr(RANGE,'-');
strxlf(record,RANGE,(string-RANGE));
start=strtol(record,&temp,10);
strxrt(record,RANGE,strlen(RANGE)-(string-RANGE+1));
end=strtol(record,&temp,10);
}

printf("search for %s\n",PHRASE);
for (rec=start;rec<=end;rec++)
{
find=textfind(dbase,rec,PHRASE);
switch (find)
{
case 1:
found=TRUE;
printf("\nRecord %ld ",rec);
break;
case 0:
printf(".");break;
case -1:
if (dbase->error == 2)
{
printf("Error- search string is NULL\n");
exit(1);
}
else
{
if (dbase->error == 3)
printf("Error reading .DBT file.\n");
}
break;
default:
printf("Unknown error\n"); break;
}
}
printf("\n");
}


/**********************************************************************/
func7(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
unsigned memoadd();/*C2DBASE function*/
static long rec;/*record number*/
long strtol();/*Lattice function*/
char *stpchr();/*Lattice function*/
struct DISKTABLE text;/*structure for Greenleaf function 'dos2delete*/
/*found in disk.h header*/

rec=strtol(RECNUM);
if (stpchr(TXT,'.') ==NULL)/* test for proper arguments*/
{printf("\7Command line error\n");exit(1);}

if (memoadd(dbase,rec,TXT) == -1)
{
switch (dbase->error)
{
case 0:
break;
case 1:
printf("\7Record does not have a memo field.\n");break;
case 2:
printf("\7Cannot open %s\n",TXT);break;
case 3:
printf("\7Cannot re-open .DBT file\n");break;
default:
printf("\7Unknown error\n");break;
}
}
else
{
if ((files->args[4] == "del") || (files->args[4]=="DEL"))
{
text.string=TXT;
dos2delete(&text);/*delete text file*/
}
}
}


/**********************************************************************/
func8(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
onoffdbt(dbase,SUBMODE);
}


/**********************************************************************/
func9(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
if (dbtpack(dbase) != 0)
{
switch (dbase->error)
{
case 1:
printf("\7Database has no .DBT file\n");break;
case 2:
printf("\7Cannot open original .DBT file\n");break;
case 3:
printf("\7Cannot create new .DBT file\n");break;
case 4:
Printf("\7Error writing to new .DBT file\n");break;
case 5:
printf("\7Error updating .DBF file\n");break;
default:
printf("\7Unknown DBTPACK error code\n");break;
}
}
}



CDBUTIL.PRC FOR DBASE III

EXPLANATION

This .PRC illustrates how to make DBASE III sub-programs that
make the C2DBASE functions available to DBASE. To use this file you
must use the SET PROCEDURE TO command to tell DBASE to search it for
called procedures, and the CDBUTIL.EXE program must be in the current
directory or in one of the directories specified by the PATH. Once this
is done, the procedures in this file may be called just as if the were
.PRG files on disk.
This set of sub-programs are only meant for illustration
purposes only, although you may find them superficially useful. They
demonstrate one way the C programs you create using the C2DBASE
functions may interface to DBASE III.
Examine the file listings of both CDBUTIL.PRC and CDBUTIL.C to
get a better idea as to how to interface to the C2DBASE functions from
both inside and outside of DBASE III. (The .PRC may only be used inside
DBASE and is only used to evok the real proogram, CDBUTIL.EXE, which may
also be used outside of DBASE.) Please note that if you are going to
recompile the source code for CDBUTIL.C, the directory references in the
.PRC and .C files are specific to the COMPUSCAN hard disk. They should
be changed to reflect your system. Also, since the source for both the
CDBUTIL.C and CDBUTIL.PRC are available to you, you may modify the
programs to suit your specific needs. One thing you must not change is
the credits. All references to Lee Mowatt and COMPUSCAN must remain
untouched.

The best way to use CDBUTIL.PRC is to reserve a few memory
variables devoted to the arguments required by the procedures. Each
procedure requires certain arguments, which may be easily specified
using memory variables. The arguments required mimick the CDBUTIL.C
modes, so if you reserve memory variables called DBFFILE, RECRANGE,
PHRASE, etc, it becomes very easy to say DO RECCOUNT WITH DBFFILE, or DO
STRFIND WITH DBFFILE,PHRASE,RECRANGE. Of course, you must assign these
variables to the proper text before you use them in this way. It will be
necessary to read the DBASE III manual if what is being said here is a
little confusing to you. Also being familiar with the CDBUTIL.EXE modes
with help a lot in using this functions inside of DBASE III. Further
insight into the arguments passed will be had by understanding the
calling statements for that program.

From inside of DBASE the following procedures are available
after the SET PROCEDURE TO statement is executed;

RECCOUNT - This procedure simply displays the unfiltered record
count of the specified database. It must be passed a parameter
containing a valid .DBF filename. (i.e. DO RECCOUNT WITH "\direct\file"
or DO RECCOUNT WITH DBFFILE).
MEMCOUNT - This procedure puts the unfiltered record count in a
memory variable called MEMCOUNT. Its arguments are the .DBF filename
(see RECCOUNT) and the memory variable that will be used to store the
count. (i.e. DO MEMCOUNT WITH DBFFILE, , where is a
memory variable of the user's choice.)
MEMDISP - Displays the memo field for the specified records.
Its first argument is DBFFILE, while its second argument must be a
string representing a valid record number, record range,or starting or
ending record number. This procedure is particularly useful if you wish
to view the memo field in a format that is not supported by DBASE
III.See the documentation on CDBUTIL.C mode 5 for a more complete
description of these arguments.
STRFIND - This procedure duplicates CDBUTIL.C mode 6. It
requires 3 parameters, DBFFILE, PHRASE, and RECRANGE.

WARNING: When CDBUTIL performs an operation on a file, the file
it is operating on the is file that is presently stored on disk, NOT THE
FILE STORED IN MEMORY. If you have made changes or additions to the
file in memory, write it out to disk using the USE or COPY commands
before using a CDBUTIL function.


PROGRAM

*****************
PROCEDURE RECOUNT
*****************
*THIS PROCEDURE PROVIDES A FAST ALTERNATIVE TO DBASE'S COUNT COMMAND. iT GIVES
*AN UNFILTERED COUNT OF THE NUMBER OF RECORD IN A .DBF FILE. (NORMALLY, YOU CAN
*HIDE CERTAIN RECORDS FROM DBASE BY USING THE 'SET FILTER TO' COMMAND. THIS
*WOULD CHANGE THE RECORD COUNT. THIS PROCEDURE INCLUDES THOSE HIDDEN RECORDS.)
PARAMETERS FILE
RUN CDBUTIL.EXE 2 &FILE
RETURN

******************
PROCEDURE MEMCOUNT
******************
*THIS PROCEDURE IS THE SAME AS RECOUNT, EXCEPT THAT THE RECORD COUNT IS PASSED
*TO A USER SPECIFIED MEMORY VARIABLE.
PARAMETERS FILE,RCOUNT
RUN CDBUTIL.EXE 3 &FILE
*ESTABLISH FULL PATHNAME OF .MEM FILE
TEMP=SUBSTR(FILE,1)
SLASH=AT("\",TEMP)
POSITION=0
DO WHILE SLASH > 0
POSITION=POSITION+SLASH
TEMP=SUBSTR(FILE,1+POSITION)
SLASH=AT("\",TEMP)
ENDDO
MEMFILE=SUBSTR(FILE,1,POSITION)+'RETURN'
RESTORE FROM &MEMFILE ADDITIVE
RCOUNT=VAL(RETPARAM)
*RETPARAM IS ALWAYS RESTORED AS A STRING
RETURN

*****************
PROCEDURE MEMDISP
*****************
*THIS PROCEDURE DISPLAYS THE MEMO FIELD(S) SPECIFIED IN THE VARIABLE RECRANGE
*RECRANGE MUST BE A STRING REPRESENTING A RECORD NUMBER, RECORD RANGE, OR
*STARTING OR ENDING RECORD NUMBER.
PARAMETERS FILE,RECRANGE
RUN CDBUTIL.EXE 5 &FILE &RECRANGE
RETURN

******************
PROCEDURE STRFIND
******************
*THIS PROCEDURE SEARCHES THROUGH RECORDS TO FIND A KEYPHRASE. THE RECORDS
*SEARCHED ARE SPECIFIED IN THE THIRD VARIABLE RECRANGE AND MUST BE A STRING
*OR STRING VARIABLE REPRESENTING THE RECORD OR RECORD RANGE. THE KEYPHRASE
*IS GIVEN IN THE SECOND VARIABLE, AND THE FILE TO BE SEARCHED IS GIVEN IN
*THE FIRST VARIABLE.
PARAMETERS FILE, PHRASE, RECRANGE
RUN CDBUTIL.EXE 6 &FILE &PHRASE &RECRANGE
RETURN


 December 10, 2017  Add comments

Leave a Reply