v15i049: cardfile - part 1 of 3

Dave Lampe dplace!djl at PacBell.COM
Mon Oct 15 11:32:56 AEST 1990


Posting-number: Volume 15, Issue 49
Submitted-by: Dave Lampe <dplace!djl at PacBell.COM>
Archive-name: cardfile/part01

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is cardfile, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 10/06/1990 19:30 UTC by djl at dplace
# Source directory /usr/src/cmd/cardfile.d
#
# existing files WILL be overwritten
# This format requires very little intelligence at unshar time.
# "echo", "true", and "sed" may be needed.
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   1485 -rw-r--r-- README
#   8576 -r--r--r-- cardfile.man
#   4564 -r--r--r-- Makefile
#   5422 -r--r--r-- cardfile.c
#   2555 -r--r--r-- add.c
#   4552 -r--r--r-- change.c
#   1842 -r--r--r-- common.c
#   1145 -r--r--r-- compress.c
#   8363 -r--r--r-- define.c
#   2755 -r--r--r-- delete.c
#   2934 -r--r--r-- dumpdb.c
#   1445 -r--r--r-- extract.c
#   2549 -r--r--r-- find.c
#   5897 -r--r--r-- findrcds.c
#   1467 -r--r--r-- fmt_chk.c
#    902 -r--r--r-- getkey.c
#   3043 -r--r--r-- keymatch.c
#   1387 -r--r--r-- maint.c
#    930 -r--r--r-- menu.c
#   5999 -r--r--r-- printdb.c
#   5962 -r--r--r-- putrcd.c
#    522 -r--r--r-- rawio.c
#   1397 -r--r--r-- rbuildak.c
#  16416 -r--r--r-- screen.c
#  11302 -r--r--r-- setupkeys.c
#   2834 -r--r--r-- updak.c
#    975 -rw-r--r-- ascii.h
#   2160 -rw-r--r-- cardfile.h
#    252 -rw-r--r-- library.def
#  29494 -rw-r--r-- library.db
#   6271 -rw-r--r-- library.ak0
#   3351 -rw-r--r-- library.ak1
#   5248 -rw-r--r-- library.ak2
#   7266 -rw-r--r-- library.ak3
#
# ============= README ==============
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
XThis program is a simple screen oriented database manager. It does have
Xsome rudimentary file formatting and printing capabilities. I use it as a
Xlibrary catalog. The metaphor is a stack of index cards with fields and
Xsubfields on them. To explain subfields, think of a book with multiple
Xauthors. Each author must be treated equally and there may be many authors.
XIf you search for any book written by "John Smith" you want to find it
Xwhether he is the only author or the fifteenth author.
X
XThere are parameters in the Makefile to configure it for System V, Sun OS,
Xor BSD. I do not have access to a BSD system so the ioctl calls are from
Xthe book. If you have problems and make changes to screen.c, please send 
Xthe patches to me.
X
XSome of the source may look a little strange because I wrote it originally
Xto run under CPM. I still have the CPM version if anyone wants it.
X
XOne thing that needs to be done yet.  The indexing needs to be converted
Xfrom a sequential search to something faster such as a B tree. Even with
Xa sequential search, the speed is acceptable on a database of about 500K.
X
XIncluded in the package is a piece of the catalog file for my library so
Xthat you can get the feeling for what it does. After you make it,
Xexecute "cardfile library" and then play.
X
XIf anyone finds any bugs (What? Bugs in MY code? :-) ), or makes any
Ximprovements, please let me know.
X
XDave Lampe
X{ames | lll-tis | sun | pyramid}!pacbell!dplace!djl
X(415) 455-1571 (H)
X(408) 986-9770 (W)
SHAR_EOF
true || echo 'restore of README failed'
# ============= cardfile.man ==============
echo 'x - extracting cardfile.man (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cardfile.man' &&
X.\ "@(#)cardfile.man	3.1 Delta Date 8/3/90  ExtrDate 10/6/90 ";
X.if t .po 1i
X.TH CARDFILE 1 djl
X.SH NAME
Xcardfile \- simple index card database
X.SH SYNOPSIS
X\fBcardfile [-r] file\fP
X.SH DESCRIPTION
X.I Cardfile
Xis a simple screen oriented index card database program.
XIf
X.I file
Xdoes not exist,
X.I cardfile
Xwill prompt for a definition of the fields to appear in each record.
XEach field has:
X.IP \(bu
Xa name
X.IP \(bu
Xthe maximum length of the field
X.IP \(bu
Xa flag to determine if it is required or not
X.IP \(bu
Xa flag to determine if the field is indexed
X(whether or not it can be searched for)
X.IP \(bu
Xif multiple values may appear in the field,
Xwhat character will separate the values,
Xfor example a book may have multiple authors separated by semicolons
X.IP \(bu
Xwhat screen page this field will appear on
X.IP \(bu
Xwhat position on the screen (line and column) the field title will appear in
X.IP \(bu
Xwhat position the field data will start in
X#ifndef NO_RE
X.IP \(bu
Xa regular expression defining the
Xrequired format of the data in the field.
X#endif
X.PP
XThe position fields are not required and \fIcardfile\fP does
Xnot check for overlap.
XWhen all fields have been defined,
Xreturn a blank screen and
X.I cardfile
Xwill create all necessary files and exit.
XReenter
X.I cardfile
Xwith the same filename and you will be able to start adding the data.
X.P
XThe \fB-r\fP flag tells \fIcardfile\fP to open the database readonly.
XYou must use this flag to retrieve data from a database on which
Xyou do not have write permission.
XWhen \fIcardfile\fP starts, the main menu is the first screen presented.
XYou may use the cursor keys or the tab keys to move.
XWhen the cursor is next to the option desired the return key
Xwill select it.
XThe options on the main menu are:
X.SS Find
XThe \fIFIND\fP option is used to retrieve data from the file.
XYou will be presented with a screen containing all the fields flagged
Xas index fields.
XEnter the value for which you wish to search.
X#ifdef NO_RE
XIf the value is enclosed in quotes (\fB"\fP) it must match exactly.
XOtherwise, case is ignored and asterisk (\fB*\fP) can be used at the
Xend of a string to match anything,
Xi.e. \fIFarmer*\fP will match "Farmer,P.J." or "farmer,philip",
Xor "FARMER9999".
X#else
XIf the value is enclosed in quotes, case is significant,
Xotherwise it is ignored.
XIt is a real regular expression match, \fIlog\fP will match
X"Archaeology", "Logistics" and "analog circuits" for example.
XThe full regular expression syntax of ed is supported.
X#endif
XSearch values within a field may be connected by "\fB&\fP" for
X\fBand\fP or "\fB|\fP" for \fBor\fP,
Xi.e. if you enter "1986|1987" any record with a value of 1986
Xor 1987 will be selected
X("and" only makes sense if multiple values are allowed in the field).
XIf values are entered in multiple fields, a record must satisfy
Xboth criteria to be selected.
X.P
XWhen all values have been input,
Xhit return and the database will be searched.
XThe selected records will be displayed on the screen one at a time.
XReturn will display the next record,
XCtrl-B will move backwards through the list,
Xand Esc will abort the display.
X.if t .bp
X.SS Add
XThe \fIADD\fP option is used to add a new record to the database.
XYou will be presented with a screen with all the fields defined
Xon the record.
XThe maximum size of each field will appear after the field name.
XWhen all the data has been entered for a record,
Xreturn will save the data and blank the fields.
XThe data is not actually written to the file until
Xyou leave the \fIadd\fP screen.
XTo leave the \fIADD\fP screen simply return a blank screen.
X.SS Change
XThe \fICHANGE\fP option starts out like \fIFIND\fP but
Xwhen the selected records are displayed,
XCtrl-C will display an \fIADD\fP screen with the data from
Xthe selected record as the initial value of each field.
XChange the data as desired and then hit return to write the data
Xand display the next selected record.
X.SS Delete
XThe \fIDELETE\fP option starts out like \fIFIND\fP but
Xwhen the selected records are displayed,
XCtrl-D will delete the record from the database.
XThe record is not physically deleted from the file until
X\fICOMPRESS\fP is run, the record is only marked and ignored.
X.SS Print
XThe \fIPRINT\fP option is used to format and print the database
Xor a subset of the database.
XThe first screen asks for the output format, the extracted file
Xif any (see \fIExtract\fP on the \fIMaintenance\fP menu),
Xthe output file, and the output width.
X.if n .P
XAny character in the output format will be printed as entered
Xexcept for \fB%\fP sequences.
XThe recognized sequences are:
X.nf
X.ta 0.5i,1.5i
X	%N	The contents of field N
X	%N(form)	The contents of field N in \fIprintf\fP(3) 
X		"%form" format, i.e. "%1(%-20s)" will print
X		field 1 left justified in a 20 character field.
X	%n	Print a new-line.
X	%t	Output a tab character.
X	%f	Output a form feed.
X	%t(NN)	Advance to column NN.
X	%%	Print a %.
X.fi
XIf the extract name field is left blank, the entire database will be dumped.
XThe output file may be an ordinary file,
Xor it may be specified as "| \fIcommand\fP" in which case
X\fIcommand\fP will be started and the print piped to it.
XIf the output width is missing, it defaults to 80.
X.SS Exit
XThe \fIEXIT\fP option will return to UNIX.
X.SS Maintenance
XThe \fIMAINTENANCE\fP option will generate a submenu of infrequently used actions.
XThe actions available from the maintenance menu are:
X.br
X.RS 0.25i
X.B Dump
X.br
X.RS 0.25i
XThe \fIDUMP\fP option of the maintenance menu
Xis used to dump all records in the database and in the index files
Xto the printer.
XThe records are not formated, they are printed exactly as in the database.
X.RE
X.B Compress
X.br
X.RS 0.25i
XThe \fICOMPRESS\fP option of the maintenance menu
Xwill reclaim the space taken by records marked as deleted
Xand then will rebuild the index files.
XAfter \fICOMPRESS\fP has been run a record can no longer be recovered.
X.RE
X.B "Rebuild AK's"
X.br
X.RS 0.25i
XThe \fIREBUILD AK's\fP option of the maintenance menu
Xwill recreate the index files from the main database file.
XThis is necessary if the main database has been changed by any means
Xother than this program.
X.RE
X.B Extract
X.br
X.RS 0.25i
XThe \fIEXTRACT\fP option of the maintenance menu
Xis used to write selected records from the
Xdatabase to another file.
XYou are first asked for the name of the output file and then
Xpresented with a screen like \fIFIND\fP to select the records to
Xbe extracted.
X.RE
X.B Exit
X.br
X.RS 0.25i
XThe \fIEXIT\fP option of the maintenance menu will return to the main menu.
X.RE
X.br
X.SH "CONTROL KEYS"
XThe keys used to control the screens are defined in \fItermcap\fP(4).
X.sp
X.nf
X.ta 0.5i,1.5i,3i
X	TERMCAP	UNIX-PC	ACTION
X	CAP-NAME	KEY
X.sp
X	kcuf1	\(->	move right or to next field if at
X			end of field
X.if t .sp 0.5
X	kcub1	\(<-	move left or to previous field if
X			at start of field
X.if t .sp 0.5
X	kbs	Back	same as kcub1
X		Space
X.if t .sp 0.5
X	ht	Tab	move to start of next field
X.if t .sp 0.5
X	kcud1	Down	same as ht
X		Arrow
X.if t .sp 0.5
X	kcbt	shift-	move to start of this field or previous
X		Tab	field if at start
X.if t .sp 0.5
X	kcuu1	Up	same as kcbt
X		Arrow
X.if t .sp 0.5
X	kel	Clear	clear to end of field
X		Line
X.if t .sp 0.5
X	kf4	Funct	same as kel
X		Key 4
X.if t .sp 0.5
X	kdch1	Dlete	delete character under cursor
X		Char
X.if t .sp 0.5
X	kf3	Funct	same as kdch1
X		Key 3
X.if t .sp 0.5
X	kich1	Input	insert a blank under the cursor
X		Mode
X.if t .sp 0.5
X	kf2	Funct	same as kich1
X		Key 2
X.if t .sp 0.5
X	kf5	Funct	go to the next page of a multi-page form
X		Key 5
X.if t .sp 0.5
X	kf6	Funct	go to the previous page of a multi-page form
X		Key 6
X.fi
X.SH FILES
X.ta 1.5i
X\fIfile\fP.def	The file of field and file definitions
X.br
X\fIfile\fP.db	The database records
X.br
X\fIfile\fP.ak\fBN\fP	The index files for searches
X.SH NOTE
XNo field may contain a colon "\fB:\fP" as it is used as a field
Xseparator in the database.
X.if t .sp 0.5v
X.if n .br
XThe maximum size of a field is 255 characters
Xand of the total record is 1024 characters.
XThe maximum number of fields in a record is 15.
XThese are arbitrary numbers and are easy to change at compile time.
X.if t .sp 0.5v
X.if n .br
XAt least one field must be defined as an index field.
X.if t .sp 0.5v
X.if n .br
XThe regular expressions used as formats and search fields are those supported
Xby the library functions.
XRemember that if a field is supposed to be numeric,
X\&'[0-9]*' will not work, '^[0-9]*$' is necessary.
X.if t .sp 0.5v
X.if n .br
XThe termcap name
X.I kcbt
Xmay not be defined in some versions of UNIX.
XJust use the up arrow instead.
X.if t .sp 0.5v
X.if n .br
XThere is no concurrency control in \fIcardfile\fP.
SHAR_EOF
true || echo 'restore of cardfile.man failed'
# ============= Makefile ==============
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
X# @(#)Makefile	3.2  DeltaDate 8/11/90   ExtrDate 10/6/90
X
X# Variables to define your environment:
X#   Define what kind of regular expression routines you have
X#	BSD_RE		use re_comp()/re_exec()
X#	SYSV_RE		use recmp()/regex()
X#	PD_RE		use Henry Spencer's public domain routines
X#			regcomp()/regexec()
X#	NO_RE		no regular expressions
X#
X#   Define what flavor of curses you have
X#	TERMCAP		use the original (BSD) curses
X#	TERMINFO	use the SYSV rewrite of curses
X#
X#   Define what tty driver you have
X#	SYSV_TTY
X#	BSD_TTY
X#
X#   Define which string library you have
X#	BSD_STRING	unprotected tolower(), index()
X#	SYSV_STRING	safe tolower(), strchr()
X#
X#   Define which signal library you have
X#	BSD_SIG		system calls are continued after interrupt
X#	SYSV_SIG	system call returns error if interrupted
X#
X# Pick one from each of the five lists above.
X#
X# SIGRTN defines the return type of the signal functions, normally
X#	an integer prior to SysV.3, void in SysV.3 and after
X# DEBUG defines the level of debug output, normally not defined
X
X# These are for compiling on the Sun 4.0
X#CC	=	cc
X#CCP	=	ccp
X#LINT	=	lint
X#DEFINES =	-DTERMCAP -DBSD_RE -DBSD_STRING -DSYSV_TTY -DSIGRTN=void -DBSD_SIG
X#CC	=	/usr/5bin/cc
X#CCP	=	/usr/5bin/ccp
X#LINT	=	/usr/5bin/lint
X#DEFINES =	-DTERMINFO -DBSD_RE -DBSD_STRING -DSYSV_TTY -DSIGRTN=void -DSYSV_SIG
X
X# These are for System V
XCC	=	cc
XCPP	=	/lib/cpp
XLINT	=	lint
XDEFINES	=	-DTERMINFO -DSYSV_RE -DSYSV_STRING -DSYSV_TTY -DSIGRTN=int -DSYSV_SIG
X
X
X# The PW library is where the regular expression subroutines regcmp, and
X#	regex are kept. If you use -DNO_RE or if your libraries are
X#	different change it.
XLIBS	=	-lPW -lcurses
X#LIBS	=	-lcurses -ltermcap
X
XBINDIR	=	/usr/local/bin/
XMANDIR	=	/usr/man/man1/
X
X#CFLAGS	=	-g -DDEBUG $(DEFINES)
XCFLAGS	=	-g $(DEFINES)
X
X#
X# Nothing past here should need changing
X#
X
X.SUFFIXES:	.1 .1~ .man .man~
X.c~.c:
X		$(GET) $(GFLAGS) $<
X
X.man~.man:
X		$(GET) $(GFLAGS) $<
X
X
XSHAR	=	shar
XSHARFLAGS =	-c -V -l62 -n cardfile -a -x -o cardfile
X
XDOC	=	cardfile.1
XDOCS	=	cardfile.man
X
XHDRS	=	ascii.h cardfile.h
X
XSRC	=	\
X		cardfile.c \
X		add.c \
X		change.c \
X		common.c \
X		compress.c \
X		define.c \
X		delete.c \
X		dumpdb.c \
X		extract.c \
X		find.c \
X		findrcds.c \
X		fmt_chk.c \
X		getkey.c \
X		keymatch.c \
X		maint.c \
X		menu.c \
X		printdb.c \
X		putrcd.c \
X		rawio.c \
X		rbuildak.c \
X		screen.c \
X		setupkeys.c \
X		updak.c \
X		$(NULL)
X
XOBJ	=	\
X		cardfile.o \
X		add.o \
X		change.o \
X		common.o \
X		compress.o \
X		define.o \
X		delete.o \
X		dumpdb.o \
X		extract.o \
X		find.o \
X		findrcds.o \
X		fmt_chk.o \
X		getkey.o \
X		keymatch.o \
X		maint.o \
X		menu.o \
X		printdb.o \
X		putrcd.o \
X		rawio.o \
X		rbuildak.o \
X		screen.o \
X		setupkeys.o \
X		updak.o \
X		$(NULL)
X
XTESTDB	=	\
X		library.def \
X		library.db \
X		library.ak0 \
X		library.ak1 \
X		library.ak2 \
X		library.ak3 \
X		$(NULL)
X
X###############################################################################
X#
X#	Make targets
X#
X###############################################################################
X
Xall:		cardfile cardfile.1
X
Xcardfile:	$(OBJ)
X		$(CC) -o cardfile $(OBJ) $(LIBS)
X
Xinstall:	all
X		cp cardfile $(BINDIR)cardfile
X		strip $(BINDIR)cardfile
X		cp cardfile.1 $(MANDIR)cardfile.1
X
Xclean:
X		rm -f *.o cardfile cardfile.1
X		for f in $(DOCS) $(SRC) $(HDRS) Makefile ; \
X		do \
X			if [ -f $$f -a -f s.$$f -a ! -f p.$$f ] ; \
X			then \
X				rm -f $$f ; \
X			fi ; \
X		done
X
X
Xprint:		prt_src prt_docs
X
Xprt_src:	$(HDRS) $(SRC) Makefile
X		cpr -w96 -l88 $(HDRS) $(SRC) Makefile |  \
X		lp -o-v8 -o-t -o-h12
X
Xprt_docs:	$(DOC)
X		nroff -man cardfile.1 | lp -o-qc
X
Xcardfile.1:	cardfile.man
X		$(CPP) -C -P cardfile.man | sed -e '/^$$/d' >cardfile.1
X
Xshar:		$(HDRS) $(SRC) $(DOCS) Makefile $(TESTDB)
X		$(SHAR) $(SHARFLAGS) README $(DOCS) Makefile \
X			$(SRC) $(HDRS) $(TESTDB)
X
Xlint:		$(HDRS) $(SRC)
X		$(LINT) $(DEFINES) $(SRC)
X
X###############################################################################
X#
X#	Object dependencies
X#
X###############################################################################
X
Xadd.o:		cardfile.h ascii.h
Xcardfile.o:	cardfile.h ascii.h
Xchange.o:	cardfile.h ascii.h
Xcommon.o:	cardfile.h ascii.h
Xcompress.o:	cardfile.h
Xdefine.o:	cardfile.h ascii.h
Xdelete.o:	cardfile.h ascii.h
Xdumpdb.o:	cardfile.h ascii.h
Xextract.o:	cardfile.h ascii.h
Xfind.o:		cardfile.h ascii.h
Xfindrcds.o:	cardfile.h ascii.h
Xgetkey.o:	cardfile.h
Xkeymatch.o:	cardfile.h
Xmaint.o:	cardfile.h
Xmenu.o:		cardfile.h
Xprintdb.o:	cardfile.h ascii.h
Xputrcd.o:	cardfile.h
Xrbuildak.o:	cardfile.h
Xscreen.o:	cardfile.h ascii.h
Xsetupkeys.o:	cardfile.h ascii.h
Xupdak.o:	cardfile.h ascii.h
SHAR_EOF
true || echo 'restore of Makefile failed'
# ============= cardfile.c ==============
echo 'x - extracting cardfile.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cardfile.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)cardfile.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      CARDFILE.C      */
X/*      This is the main routine for cardfile
X*/
X#include	"ascii.h"
X#include	"stdio.h"
X#include	"cardfile.h"
X#include	<signal.h>
X
X#define FIND    0
X#define ADD     1
X#define CHANGE  2
X#define DELETE  3
X#define PRINT   4
X#define MAINT   5
X#define EXIT    6
X
XFILE    *def_fp;
Xint	readonly;
Xchar    fname[FNSIZE];
Xextern  char *getfield();
Xchar    *functs[]    = {"FIND       ",
X			"ADD        ",
X			"CHANGE     ",
X			"DELETE     ",
X			"PRINT      ",
X			"MAINTENANCE",
X			"EXIT       ",
X			0
X			};
X
Xchar	datadir[FNSIZE];
Xchar	*dbname;
Xvoid	setupscr();
Xvoid	exit();
Xunsigned sleep();
Xstatic	usage();
X
Xmain(argc, argv)
Xint     argc;
Xchar    **argv;
X{
X    int 	num_flds, i;
X    char	line_buf[133];
X    struct      Fdata fields[MAXFLDS+1], *fp;
X    int 	num_ak;
X    struct      AKdata ak_data[MAXAK+1];
X    int		fn;
X    int 	func;
X    char	*cp;
X    extern char *optarg;
X    extern int optind, opterr;
X    
X    opterr = 0;
X    while ((i = getopt(argc, argv, "r")) != EOF) {
X	switch (i) {
X	case 'r':
X	    ++readonly;
X	    break;
X	case '?':
X	    usage(argv[0]);
X	    exit(1);
X	}
X    }
X    if (optind != argc-1) {
X	usage(argv[0]);
X	exit(1);
X    }
X    signal(SIGINT, getout);
X    signal(SIGQUIT, getout);
X    signal(SIGTERM, getout);
X    setupscr();		/* from here on use getout, not exit to reset screen */
X    if ((cp = strrchr(argv[optind], '/')) != NULL) {
X	*cp = '\0';
X	sprintf(datadir, "%s/", argv[optind]);
X	dbname = cp + 1;
X    } else {
X	*datadir = '\0';
X	dbname = argv[optind];
X    }
X    if (strlen(dbname) > 10) {
X	printf("Database name cannot be longer than 10 characters.\n");
X	sleep(5);
X	getout();
X    }
X    /* build definition file name */
X    sprintf(fname, "%s%s.def", datadir, dbname);
X    if ((def_fp = fopen(fname,"r")) == NULL) {
X	db_define(dbname);
X	getout();
X    }
X    /* The format of the definition file is:
X     * Num_of_fields
X     * Field1_Name:Key:Sub_Seps:Req:Data_Len
X     * ...
X     * Num_of_Alt_Keys
X     * Field_Num:AK1_File_Name
X     * ...
X     * %%
X     * Field_Num:Label_Row:Label_Col:Data_Row:Data_Col:Data_Fmt
X     * ...
X     */
X    if (fgets(line_buf, 132, def_fp) == NULL) {
X	printf("Unable to read DEF file\n");
X	sleep(5);
X	getout();
X    }
X    if (! readonly && access(fname, 06) != 0) {
X	printf("You can not write to the database, try\n%s -r %s%s\n",
X	    argv[0], datadir, dbname);
X	sleep(5);
X	getout();
X    }
X    strcpy(fname, getfield(line_buf, ":"));
X    num_flds = atoi(getfield(0, ":"));
X
X    for (i=0, fp=&fields[0]; i<num_flds; i++, fp++) {	/* get definition of each field */
X	if (fgets(line_buf, 132, def_fp) == NULL) {
X	    printf("DEF file syntax error, field defs\n");
X	    sleep(5);
X	    getout();
X	}
X	strcpy(fp->F_title, getfield(line_buf, ":"));
X	fp->F_key = *getfield(0, ":");
X	strcpy(fp->F_seps, getfield(0, ":"));
X	fp->F_required = *getfield(0, ":");
X	fp->F_length = atoi(getfield(0, ":"));
X	/* set defaults */
X	fp->F_page = -1;
X	fp->F_Lrow = -1;
X	fp->F_Lcol = -1;
X	fp->F_Drow = -1;
X	fp->F_Dcol = -1;
X	fp->F_Dfmt[0] = '\0';
X    }
X    fp->F_title[0] = '\0';
X
X    fgets(line_buf, 10, def_fp);
X    num_ak = atoi(line_buf);
X    for (i=0; i<num_ak; i++) {          /* get definition of each AK file */
X	if (fgets(line_buf, 132, def_fp) == NULL) {
X	    printf("DEF file syntax error, AK files\n");
X	    sleep(5);
X	    getout();
X	}
X	line_buf[strlen(line_buf)-1] = '\0';	/* truncate newline */
X	ak_data[i].A_fldnum = atoi(getfield(line_buf, ":"));
X	strcpy(ak_data[i].A_akname, getfield(0, ":"));
X    }
X    ak_data[i].A_fldnum = -1;
X
X    fgets(line_buf, 10, def_fp);
X    if (strcmp(line_buf, "%%\n") == 0) {
X	for (i=0; i<num_flds; i++) {	/* Get screen layout for each field */
X	    if (fgets(line_buf, 132, def_fp) == NULL) {
X		break;
X	    }
X	    line_buf[strlen(line_buf)-1] = '\0';	/* truncate newline */
X	    fn = atoi(getfield(line_buf, ":"));
X	    if (fn < 0 || fn >= num_flds) {
X		printf("DEF file syntax error, screen layout\n");
X		sleep(5);
X		getout();
X	    }
X	    if ((cp = getfield(0, ":")) != NULL && *cp != '\0')
X		fields[fn].F_page = atoi(cp);
X	    if ((cp = getfield(0, ":")) != NULL && *cp != '\0')
X		fields[fn].F_Lrow = atoi(cp);
X	    if ((cp = getfield(0, ":")) != NULL && *cp != '\0')
X		fields[fn].F_Lcol = atoi(cp);
X	    if ((cp = getfield(0, ":")) != NULL && *cp != '\0')
X		fields[fn].F_Drow = atoi(cp);
X	    if ((cp = getfield(0, ":")) != NULL && *cp != '\0')
X		fields[fn].F_Dcol = atoi(cp);
X	    if ((cp = getfield(0, ":")) != NULL) {
X		strcpy(fields[fn].F_Dfmt, cp);
X	    }
X	}
X    }
X    fclose(def_fp);
X#ifdef DEBUG
X    fprintf(stderr, "%d fields in the %s database\n", num_flds, dbname);
X    for (i=0; i<num_flds; ++i) {
X	fprintf(stderr, "%8d  %s\n", i, fields[i].F_title);
X    }
X#endif
X    
X    /* get function to be performed */
X    while ((func = menu(dbname, functs)) != EXIT) {
X	switch (func) {
X	case FIND:
X	    find(fields, dbname);
X	    continue;
X	case ADD:
X	    add(fields, dbname);
X	    continue;
X	case CHANGE:
X	    change(fields, dbname);
X	    continue;
X	case DELETE:
X	    delete(fields, dbname);
X	    continue;
X	case PRINT:
X	    printdb(fields, dbname);
X	    continue;
X	case MAINT:
X	    maint(fields, dbname, ak_data);
X	    continue;
X	default:
X	    msg("Illegal function chosen");
X	    getout();
X	}
X    }
X    getout();
X/*NOTREACHED*/
X}
X
X
Xstatic
Xusage(prog)
Xchar	*prog;
X{
X    printf("Usage: %s [-r] file\n", prog);
X}
SHAR_EOF
true || echo 'restore of cardfile.c failed'
# ============= add.c ==============
echo 'x - extracting add.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'add.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)add.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      ADD.C   */
X/*      This subroutine is used to add a new record to the
X**	data base. It also requests the updating of the
X**	alternate key files.
X*/
X
X#include <stdio.h>
X#include <errno.h>
X#include "ascii.h"
X#include "cardfile.h"
X
Xlong    ftell();
Xchar    *malloc();
Xextern  int     errno;
Xextern	int	readonly;
X
Xadd(fields, dbname)
Xstruct  Fdata   fields[];
Xchar    *dbname;
X{
X    struct      Fdata   *fp;
X    struct      Sdata   add_screen[MAXFLDS+1], *sp;
X    int 	err;
X    char	first[SWIDTH+1];
X    char	out_line[DBSIZE+1];
X    FILE	*filep;
X    char	filename[FNSIZE];
X    long	offset;
X    char	*buffer;
X    
X    if (readonly) {
X	msg("Database is readonly");
X	return(1);
X    }
X    sprintf(first, "Add Records to %s Data Base", dbname);
X    buffer = malloc(BUFSIZE+1);
X    buffer[0] = '\0';
X    sprintf(filename, "%s%s.db", datadir, dbname);
X    if((filep = fopen(filename, "a")) == NULL) {
X	if (errno == EACCES) {
X	    strcpy(out_line, "You do not have permission to modify this database");
X	} else {
X	    sprintf(out_line, "Unable to open %s, errno=%d\n", filename, errno);
X	}
X	msg(out_line);
X	return(1);
X    }
X    for (fp = fields, sp = add_screen ; fp->F_title[0] != 0; ++fp, ++sp) {
X	sp->S_title = fp->F_title;
X	sp->S_length = fp->F_length;
X	sp->S_result = malloc((unsigned)fp->F_length+1);
X	sp->S_dfault = 0;
X	sp->S_page = fp->F_page;
X	sp->S_Lrow = fp->F_Lrow;
X	sp->S_Lcol = fp->F_Lcol;
X	sp->S_Drow = fp->F_Drow;
X	sp->S_Dcol = fp->F_Dcol;
X	sp->S_Dfmt = fp->F_Dfmt;
X    }
X    sp->S_title = 0;
X    while (screen(first, add_screen, 0, 0, FALSE) != 0) {
X	out_line[0] = '\0';
X	err = 0;
X	fp = fields;
X	sp = add_screen;
X	while (sp->S_title) {
X	    if (sp->S_result[0] == '\0' && fp->F_required == 'Y') {
X		sprintf(out_line, "Required field %s missing", fp->F_title);
X		msg(out_line);
X		++err;
X	    }
X	    if (strchr(sp->S_result, ':')) {
X		msg("A ':' is not allowed in any field");
X		++err;
X	    }
X	    if (strlen(out_line) + strlen(sp->S_result) >= DBSIZE) {
X		msg("Record too long");
X		++err;
X		break;
X	    }
X	    strcat(out_line, sp->S_result);
X	    strcat(out_line, ":");
X	    ++fp;
X	    ++sp;
X	}
X	if (err)
X	    continue;
X	out_line[strlen(out_line)-1] = '\0';
X	offset = ftell(filep);
X	fprintf(filep, " :%s\n", out_line);
X	buildak(dbname, out_line, offset, fields, buffer);
X    }
X    sp = add_screen;
X    while (sp->S_title) {
X	free(sp->S_result);
X	++sp;
X    }
X    fclose(filep);
X    writeak(dbname, buffer);
X    free(buffer); 
X    return(0);
X}
SHAR_EOF
true || echo 'restore of add.c failed'
# ============= change.c ==============
echo 'x - extracting change.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'change.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)change.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      CHANGE.C		*/
X/*      This module is used to find and change records
X**	in the data base matching the selection criteria.
X**	The user may select multiple values of one field
X**	which will be or'd and/or multiple fields which will
X**	be and'd. In other words, if field 1 is specified
X**	as value1:value2 and field3 is specified as value3.
X**	Records with field1==(value1 || value2) && field3==value3
X**	will be selected for changing.
X**	It calls findrcds.c to do all the work of finding them.
X**	It does not actually change records, the flag(first)
X**	field is set to 'D' in the current record and a new
X**	record is added. To physically delete the old record,
X**	the data base must be compressed.
X*/
X
X#include <stdio.h>
X#include <errno.h>
X#include "ascii.h"
X#include "cardfile.h"
X
Xchar	*malloc(), *getfield();
Xextern	int	readonly;
X
X
Xstatic struct Sdata disp_screen[MAXFLDS+1];
X
Xchange(fields, dbname)
Xstruct  Fdata   fields[];
Xchar    *dbname;
X{
X    char	first[SWIDTH];
X    struct Fdata *fp;
X    struct Sdata *sp;
X    int 	processc();
X
X    if (readonly) {
X	msg("Database is readonly");
X	return(1);
X    }
X    sprintf(first, "Select Records from the %s Data Base to be Changed",
X	dbname);
X    for (fp = fields, sp = disp_screen ; fp->F_title[0] != 0; ++fp, ++sp) {
X	sp->S_title = fp->F_title;
X	sp->S_length = fp->F_length;
X	sp->S_result = (char*)malloc((unsigned)fp->F_length+1);
X	sp->S_page = fp->F_page;
X	sp->S_Lrow = fp->F_Lrow;
X	sp->S_Lcol = fp->F_Lcol;
X	sp->S_Drow = fp->F_Drow;
X	sp->S_Dcol = fp->F_Dcol;
X	sp->S_Dfmt = fp->F_Dfmt;
X    }
X    sp->S_title = 0;
X
X    findrcds(fields, dbname, processc, first);
X    for (sp = disp_screen ; sp->S_title != 0; ++sp) {
X	free(sp->S_result);
X    }
X    return(0);
X}
X
X
Xprocessc(fields, rcd, dbfile, dbname)
Xstruct  Fdata   *fields;
Xchar    *rcd;
XFILE    *dbfile;
Xchar    *dbname;
X{
X    char	c, save[DBSIZE+1];
X    long	offset, ftell();
X    char	*strchr();
X    int 	fn;
X    struct      Fdata   *fp;
X    struct      Sdata   *sp;
X    char	*first = "Record to be CHANGED";
X    char	*last = "RETURN for next, ESC to abort, Ctrl-C to Change, Ctrl-B to reverse";
X    extern char	lastchar;
X    
X    strcpy(save, rcd);
X    *strchr(save, '\n') = '\0';          /* truncate \n */
X    getfield(save, ":");
X    for (sp = disp_screen; sp->S_title != 0; ++sp) {
X	sp->S_dfault = getfield(NULL, ":");
X    }
X    screen(first, disp_screen, last, NULL, TRUE);
X    noecho();
X    c = lastchar;
X    do {
X	if (c == LF || c == CR)
X	    break;
X	if (c == ETX) {         /* CTL-C entered */
X	    offset = ftell(dbfile) - strlen(rcd);
X	    *strchr(rcd, '\n') = '\0';          /* truncate \n */
X	    if (doadd(dbname, fields, rcd, dbfile) == 0) {
X		fseek(dbfile, offset, 0);
X		putc('D', dbfile);
X	    }
X	    break;
X	}
X	if (c == ESC) {
X	    echo();
X	    return(1);
X	}
X	if (c == STX) {			/* CTRL-B */
X	    echo();
X	    return(-1);
X	}
X	rawputchar(BEL);
X    } while (c=rawgetchar());
X    echo();
X    return(0);
X}
X
Xdoadd(dbname, fields, rcd, filep)
Xchar    *dbname;
Xstruct  Fdata   *fields;
Xchar    *rcd;
XFILE    *filep;
X{
X    struct      Sdata   *sp;
X    struct      Fdata   *fp;
X    int 	err;
X    char	buffer[BUFSIZE+1];
X    char	outline[DBSIZE+1];
X    long	offset, ftell();
X
X    fseek(filep, 0L, 2);     /* end of file */
X    fp = fields;
X    getfield(rcd, ":");         /* step past flag */
X    sp = disp_screen;
X    while(fp->F_title[0]) {
X	sp->S_dfault = getfield(0, ":");
X	++fp;
X	++sp;
X    }
X    outline[0] = '\0';
X    while (screen("Enter changes", disp_screen, 0, 0, FALSE) > 0) {
X	err = 0;
X	fp = fields;
X	sp = disp_screen;
X	while(fp->F_title[0]) {
X	    if (sp->S_result[0] == '\0' && fp->F_required == 'Y') {
X		sprintf(outline, "Required field %s missing", fp->F_title);
X		msg(outline);
X		err++;
X	    }
X	    if (strchr(sp->S_result, ':')) {
X		msg("A : is not allowed in any field");
X		++err;
X	    }
X	    if (strlen(outline) + strlen(sp->S_result) >= DBSIZE) {
X		msg("Record too long");
X		++err;
X		break;
X	    }
X	    strcat(outline, sp->S_result);
X	    strcat(outline, ":");
X	    ++fp;
X	    ++sp;
X	}
X	if (err == 0)
X	    break;
X	outline[0] = '\0';
X    }
X    if (err > 0 || outline[0] == '\0') {
X	return(1);
X    }
X    outline[strlen(outline)-1] = '\0';  /* truncate trailing : */
X    offset = ftell(filep);
X    if (fprintf(filep, " :%s\n", outline) == EOF) {
X	msg("Error writing DB file");
X	getout();
X    }
X    buffer[0] = '\0';
X    buildak(dbname, outline, offset, fields, buffer);
X    writeak(dbname, buffer);
X    return(0);
X}
SHAR_EOF
true || echo 'restore of change.c failed'
# ============= common.c ==============
echo 'x - extracting common.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'common.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)common.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      COMMON.C        */
X#include "stdio.h"
X#include "ascii.h"
X#include "cardfile.h"
X#ifdef TERMCAP
X#define tparm(a, line, col)	tgoto(a, col, line)
X#define	putp(a)		tputs(a, 12, mputc)
X#else	/* TERMINFO */
X#include <curses.h>
X#include <term.h>
X#endif
X
X#ifdef TERMCAP
Xextern char
X	*clear_screen,
X	*clr_eol,
X	*enter_dim_mode,
X	*enter_blink_mode,
X	*exit_attribute_mode,
X	*keypad_xmit,
X	*keypad_local,
X	*cursor_address,
X	*cursor_left,
X	*cursor_right;
Xint	mputc();
X#endif
X
Xmsg(str)        /* put a blinking message on the 23'th line of the crt */
Xchar    *str;
X{
X    putp(tparm(cursor_address, MSGLINE, 9));
X    putp(clr_eol);			/* erase line */
X    if (str != NULL && *str != '\0') {
X	putp(enter_blink_mode);		/* blink */
X	fputs(str, stdout);
X	putp(exit_attribute_mode);		/* back to normal */
X	sleep(4);
X    }
X}
X
X
Xchar *
Xgetfield(string, sepset)        /* like strtok except contiguous seps */
Xchar    *string, *sepset;       /* result in a null field */
X{
X    register char *p, *r;
X    static char *savept;
X    char	*strpbrk();
X    
X    p = (string == NULL)? savept : string;
X    if (p == 0)
X        return(NULL);
X    if (*p == '\0')
X        return(NULL);
X    if ((r = strpbrk(p, sepset)) == NULL)       /* move past token */
X        savept = 0;     /* indicate this is the last token */
X    else {
X        *r = '\0';
X        savept = ++r;
X    }
X    return(p);
X}
X
X
Xhelp(help_msg)
Xchar    *help_msg;
X{
X    putp(clear_screen);              /* clear screen */
X    puts("\n");
X    fputs(help_msg, stdout);
X    putp(tparm(cursor_address, MSGLINE, 9));
X    fputs("Enter any character to continue.", stdout);
X    rawgetchar();
X    putp(clear_screen);              /* clear screen */
X}
X
X
X#ifdef TERMCAP
Xmputc(c)
Xchar	c;
X{
X    putchar(c);
X}
X#endif
SHAR_EOF
true || echo 'restore of common.c failed'
# ============= compress.c ==============
echo 'x - extracting compress.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'compress.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)compress.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      COMPRESS.C      */
X/*	This function will remove all records with a flag
X**	byte of 'D' from the data base.  The alternate key
X**	files MUST be rebuilt after it finishes.
X*/
X
X#include "stdio.h"
X#include "cardfile.h"
X
Xcompress(dbname)
Xchar    *dbname;
X{
X    FILE	*in, *out;
X    char	fname[FNSIZE];
X    char	tempname[FNSIZE];
X    char	rcd[DBSIZE+1];
X    
X    sprintf(tempname, "%snewdb.$$$", datadir);
X    if ((out = fopen(tempname, "w")) == NULL) {
X	msg("Unable to create temporary file");
X	getout();
X    }
X    sprintf(fname, "%s%s.db", datadir, dbname);
X    if ((in = fopen(fname, "r")) == NULL) {
X	unlink(tempname);
X	msg("Unable to read DB file");
X	getout();
X    }
X    while (fgets(rcd, DBSIZE, in) != NULL) {
X	if (feof(in))
X	    break;
X	if (*rcd == 'D')        /* record to be deleted */
X	    continue;
X	if(fputs(rcd, out) == EOF) {
X	    unlink(tempname);
X	    msg("Unable to write to temporary file");
X	    getout();
X	}
X    }
X    fclose(in);
X    fclose(out);
X    unlink(fname);
X    link(tempname, fname);
X    unlink(tempname);
X}
SHAR_EOF
true || echo 'restore of compress.c failed'
# ============= define.c ==============
echo 'x - extracting define.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'define.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)define.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      DEFINE.C	*/
X/*      This subroutine is used to define a new data-base.
X**	It expects as input the base name (10 characters or less)
X**	of all files.
X**
X**	It will create the definition file  -  name.def
X**	the primary file		    -  name.db
X**	and the alternate key files         -  name.akN
X*/
X
X#include "cardfile.h"
X#include "stdio.h"
X#include "ascii.h"
X#include <ctype.h>
X
X#define	FNAME	0
X#define	MAXL	1
X#define	REQD	2
X#define	SRCH	3
X#define	SUBF	4
X#define	PAGE	5
X#define	LLINE	6
X#define	LCOL	7
X#define	DLINE	8
X#define	DCOL	9
X#define	FMT	10
X
Xstatic int	page_def = 1;
Xstatic int	lline_def = 2;
Xstatic int	col_def = 4;
X
Xstatic char	name_res[TSIZE+1];
Xstatic char	mlen_res[3+1];
Xstatic char	req_res[1+1];
Xstatic char	skey_res[1+1];
Xstatic char	sep_res[5+1];
Xstatic char	page_res[1+1];
Xstatic char	lline_res[2+1];
Xstatic char	lcol_res[2+1];
Xstatic char	dline_res[2+1];
Xstatic char	dcol_res[2+1];
X#ifndef NO_RE
Xstatic char	fmt_res[MAXFMT+1];
X#endif
X
Xstatic struct	Sdata	def_screen[] = {
X			{"FIELD NAME", TSIZE, name_res, 0,
X			    -1, -1, -1, -1, -1, "^[^:]*$"},
X			{"MAXIMUM LENGTH", 3, mlen_res, 0,
X			    -1, -1, -1, -1, -1, "^[0-9]*$"},
X			{"REQUIRED?", 1, req_res, "N",
X			    -1, -1, -1, -1, -1, "[nyNY]"},
X			{"SEARCH KEY", 1, skey_res, "Y",
X			    -1, 6, 35, -1, -1, "[nyNY]"},
X			{"SUBFIELD SEPARATORS", 5, sep_res, 0,
X			    -1, -1, -1, -1, -1, "^[^:]$"},
X			{"FIELD PAGE", 1, page_res, " ",
X			    -1, -1, -1, -1, -1, "^[-0-9]$"},
X			{"LABEL LINE", 2, lline_res, "  ",
X			    -1, -1, -1, -1, -1, "^[-0-9]$"},
X			{"LABEL COLUMN", 2, lcol_res, "  ",
X			    -1, 12, 35, -1, -1, "^[-0-9]$"},
X			{"DATA FIELD LINE", 2, dline_res, "  ",
X			    -1, -1, -1, -1, -1, "^[-0-9]$"},
X			{"DATA FIELD COLUMN", 2, dcol_res, 0,
X			    -1, 14, 35, -1, -1, "^[-0-9]$"},
X#ifdef RE
X			{"FORMAT", MAXFMT, fmt_res, 0,
X			    -1, -1, -1, -1, -1, ""},
X#endif
X			{0, 0, 0, 0, -1, -1, -1, -1, -1, ""}
X		};
X
Xstatic struct  Fdata   fields[MAXFLDS];
X
Xdb_define(basename)
Xchar    *basename;
X{
X    int 	i;
X    char	first[SWIDTH];
X    char	*last = "RETURN to exit";
X    struct      Fdata   *fp;
X    int 	num_fields, num_ak;
X    char	fname[FNSIZE];
X    FILE	*filep, *filep2;
X    int 	err;
X    int 	tsize;
X    int		opt_out;
X
X    sprintf(first,"DEFINING %s DATA BASE", basename);
X    if (access((*datadir ? datadir : "."), 06) != 0) {
X	printf("Cannot write into %s\n", (*datadir ? datadir : "."));
X	sleep(5);
X	return(1);
X    }
X    
X    /*
X     *	Read each field entered
X     */
X    num_fields = 0;
X    fp = &fields[0];
X    tsize = 0;
X    sprintf(def_screen[PAGE].S_dfault, "%d", page_def);
X    sprintf(def_screen[LLINE].S_dfault, "%d", lline_def);
X    sprintf(def_screen[LCOL].S_dfault, "%d", col_def);
X    sprintf(def_screen[DLINE].S_dfault, "%d", lline_def);
X    while (screen(first, def_screen, last, 0, FALSE)) {
X	err = 0;
X	strcpy(fp->F_title, def_screen[FNAME].S_result);
X	if (fp->F_title[0] == '\0') {
X	    msg("TITLE field must be specified");
X	    ++err;
X	}
X	if (strchr(fp->F_title, ':') != NULL) {
X	    msg("TITLE field must not include :");
X	    ++err;
X	}
X
X	fp->F_length = atoi(def_screen[MAXL].S_result);
X	if (fp->F_length <= 0 || fp->F_length >= FLDLEN) {
X	    msg("LENGTH field must be less than 256");
X	    ++err;
X	}
X	if ((tsize += fp->F_length) > DBSIZE) {
X	    msg("Total record length too large");
X	    ++err;
X	}
X
X#ifdef BSD_STRING
X	if (islower(def_screen[REQD].S_result[0]))
X	    fp->F_required = toupper(def_screen[REQD].S_result[0]);
X#else
X	fp->F_required = toupper(def_screen[REQD].S_result[0]);
X#endif
X	if (fp->F_required != 'Y' && fp->F_required != 'N') {
X	    msg("REQUIRED must be Y or N");
X	    ++err;
X	}
X
X#ifdef BSD_STRING
X	if (islower(def_screen[SRCH].S_result[0]))
X	    fp->F_key = toupper(def_screen[SRCH].S_result[0]);
X#else
X	fp->F_key = toupper(def_screen[SRCH].S_result[0]);
X#endif
X	if (fp->F_key != 'Y' && fp->F_key != 'N') {
X	    msg("KEY must be Y or N");
X	    ++err;
X	}
X
X	strcpy(fp->F_seps, def_screen[SUBF].S_result);
X	if (strchr(fp->F_seps, ':') != NULL) {
X	    msg("SEPARATORS must not include :");
X	    ++err;
X	}
X
X#ifndef NO_RE
X	strcpy(fp->F_Dfmt, def_screen[FMT].S_result);
X#else
X	fp->F_Dfmt[0] = '\0';
X#endif
X
X	fp->F_page = atoi(def_screen[PAGE].S_result);
X	if (fp->F_page == 0) {
X	    fp->F_page = -1;
X	}
X
X	if (def_screen[LLINE].S_result[0] == '\0') {
X	    fp->F_Lrow = -1;
X	} else {
X	    fp->F_Lrow = atoi(def_screen[LLINE].S_result);
X	    if (fp->F_Lrow < 2 || fp->F_Lrow >= MSGLINE) {
X		msg("LABEL ROW field must be less than 22");
X		++err;
X	    }
X	}
X
X	if (def_screen[LCOL].S_result[0] == '\0') {
X	    fp->F_Lcol = -1;
X	} else {
X	    fp->F_Lcol = atoi(def_screen[LCOL].S_result);
X	    if (fp->F_Lcol < 0 || fp->F_Lcol >= SWIDTH) {
X		msg("LABEL COLUMN field must be less than 80");
X		++err;
X	    }
X	}
X
X	if (def_screen[DLINE].S_result[0] == '\0') {
X	    fp->F_Drow = -1;
X	} else {
X	    fp->F_Drow = atoi(def_screen[DLINE].S_result);
X	    if (fp->F_Drow < 2 || fp->F_Drow >= MSGLINE) {
X		msg("DATA ROW field must be less than 22");
X		++err;
X	    }
X	}
X
X	if (def_screen[DCOL].S_result[0] == '\0') {
X	    fp->F_Dcol = -1;
X	} else {
X	    fp->F_Dcol = atoi(def_screen[DCOL].S_result);
X	    if (fp->F_Dcol < 0 || fp->F_Dcol >= SWIDTH) {
X		msg("DATA COLUMN field must be less than 80");
X		++err;
X	    }
X	}
X
X	for (i=0; i<num_fields; i++) {
X	    if (strcmp(fields[i].F_title, fp->F_title) == 0) {
X		msg("Field already defined");
X		err++;
X		break;
X	    }
X	}
X	if (err)
X	    continue;
X	/*
X	 * Valid field, update defaults
X	 */
X	lline_def = (fp->F_Lrow > fp->F_Drow ? fp->F_Lrow : fp->F_Drow) + 2;
X	if (fp->F_Dcol == -1) {
X	    lline_def += ((fp->F_Lcol == -1 ? 4 : fp->F_Lcol) +
X			    strlen(fp->F_title) + (fp->F_length > 99 ? 7 : 6) +
X			    fp->F_length) / SWIDTH;
X	} else {
X	    lline_def += (fp->F_Dcol + fp->F_length) / SWIDTH;
X	}
X	if (lline_def > SLENGTH - 4) {
X	    page_def++;
X	    lline_def = 2;
X	}
X	sprintf(def_screen[PAGE].S_dfault, "%d", page_def);
X	sprintf(def_screen[LLINE].S_dfault, "%d", lline_def);
X	sprintf(def_screen[LCOL].S_dfault, "%d", col_def);
X	sprintf(def_screen[DLINE].S_dfault, "%d", lline_def);
X	++fp;
X	if (++num_fields > MAXFLDS) {
X	    msg("Too many fields defined, aborting");
X	    return(1);
X	}
X    }
X#ifdef DEBUG
X    fprintf(stderr, "%d fields in the %s database\n", num_fields, basename);
X    for (i=0; i<num_fields; ++i) {
X	fprintf(stderr, "%8d  %s\n", i, fields[i].F_title);
X    }
X#endif
X
X    if (num_fields == 0) {
X	msg("No fields defined, aborting");
X	return(1);
X    }
X    sprintf(fname,"%s%s.def", datadir, basename);
X    if ((filep = fopen(fname,"w")) == NULL) {
X	msg("Unable to create DEF file");
X	return(1);
X    }
X    sprintf(fname,"%s%s.db", datadir, basename);
X    if ((filep2 = fopen(fname,"w")) == NULL) {
X	msg("Unable to create DB file");
X	sprintf(fname, "%s.def", basename);
X	unlink(fname);
X	return(1);
X    }
X    fclose(filep2);
X    fprintf(filep, "%s:%d\n", fname, num_fields);
X    num_ak = 0;
X    for (i=0; i<num_fields; i++) {
X	fp = &fields[i];
X	if (fp->F_key == 'Y')
X	    fp->F_key = '0' + num_ak++;
X	fprintf(filep, "%s:%c:%s:%c:%d\n", fp->F_title, fp->F_key,
X	    fp->F_seps, fp->F_required, fp->F_length);
X    }
X    if (num_ak == 0) {
X	msg("At least 1 key field must be defined");
X	unlink(fname);          /* DB file */
X	sprintf(fname, "%s.def", basename);
X	unlink(fname);
X	return(1);
X    }
X    fprintf(filep, "%d\n", num_ak);
X    num_ak = 0;
X    for (i=0; i<num_fields; i++) {
X	fp = &fields[i];
X	if (fp->F_key != 'N') {         /* Alternate key file required */
X	    sprintf(fname,"%s%s.ak%d", datadir, basename, num_ak++);
X	    if ((filep2 = fopen(fname,"w")) == NULL) {
X		msg("Unable to create AK file\n");
X		sprintf(fname, "%s.def", basename);
X		unlink(fname);
X		return(1);
X	    }
X	    fclose(filep2);
X	    fprintf(filep, "%d:%s\n", i, fname);
X	}
X    }
X
X    /*
X     * Output optional fields if necessary (position and format)
X     */
X    for (i=0, opt_out=1, fp = &fields[0]; i<num_fields; i++, fp++) {
X	if (fp->F_page == -1 && fp->F_Lrow == -1 && fp->F_Lcol == -1 &&
X		fp->F_Drow == -1 && fp->F_Dcol == -1 && fp->F_Dfmt[0] == '\0') {
X	    continue;
X	}
X	if (opt_out) {
X	    fprintf(filep, "%%%%\n");
X	    opt_out = 0;
X	}
X	fprintf(filep, "%d:%d:%d:%d:%d:%d:%s\n", i, fp->F_page, fp->F_Lrow,
X	    fp->F_Lcol, fp->F_Drow, fp->F_Dcol, fp->F_Dfmt);
X    }
X    fclose(filep);
X    return(0);
X}
SHAR_EOF
true || echo 'restore of define.c failed'
# ============= delete.c ==============
echo 'x - extracting delete.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'delete.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)delete.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*	DELETE.C		*/
X/*	This module is used to find and delete records
X**	in the data base matching the selection criteria.
X**	The user may select multiple values of one field
X**	which will be or'd and/or multiple fields which will
X**	be and'd. In other words, if field 1 is specified
X**	as value1:value2 and field3 is specified as value3.
X**	Records with field1==(value1 || value2) && field3==value3
X**	will be selected for deletion.
X**	It calls findrcds.c to do all the work.
X**	It does not actually delete records, the flag(first)
X**	field is set to 'D'. To physically delete them, the data
X**	base must be compressed.
X*/
X
X#include "stdio.h"
X#include "ascii.h"
X#include "cardfile.h"
X
X
Xstatic struct Sdata disp_screen[MAXFLDS+1];
X
Xextern	int	readonly;
Xchar	*malloc(), *getfield();
X
Xdelete(fields, dbname)
Xstruct  Fdata   fields[];
Xchar    *dbname;
X{
X    char	first[SWIDTH];
X    struct Fdata *fp;
X    struct Sdata *sp;
X    int 	processd();
X    
X    if (readonly) {
X	msg("Database is readonly");
X	return(1);
X    }
X    sprintf(first, "Select Records from the %s Data Base to be DELETED",
X	dbname);
X    for (fp = fields, sp = disp_screen ; fp->F_title[0] != 0; ++fp, ++sp) {
X	sp->S_title = fp->F_title;
X	sp->S_length = fp->F_length;
X	sp->S_result = (char*)malloc((unsigned)fp->F_length+1);
X	sp->S_page = fp->F_page;
X	sp->S_Lrow = fp->F_Lrow;
X	sp->S_Lcol = fp->F_Lcol;
X	sp->S_Drow = fp->F_Drow;
X	sp->S_Dcol = fp->F_Dcol;
X	sp->S_Dfmt = fp->F_Dfmt;
X    }
X    sp->S_title = 0;
X
X    findrcds(fields, dbname, processd, first);
X    for (sp = disp_screen ; sp->S_title != 0; ++sp) {
X	free(sp->S_result);
X    }
X    return(0);
X}
X
X
X/*ARGSUSED*/
Xprocessd(fields, rcd, dbfile, dummy)
Xstruct  Fdata   *fields;
Xchar    *rcd;
XFILE    *dbfile;
Xchar	*dummy;
X{
X    char	c, save[DBSIZE+1];
X    static      char    fmt[256];
X    int 	fn;
X    struct      Fdata   *fp;
X    struct      Sdata   *sp;
X    char	*first = "Record to be DELETED";
X    char	*last = "RETURN for next, ESC to abort, CTL-D to DELETE, CTL-B to reverse";
X    extern char	lastchar;
X
X    strcpy(save, rcd);
X    *strchr(save, '\n') = '\0';          /* truncate \n */
X    getfield(save, ":");
X    for (sp = disp_screen; sp->S_title != 0; ++sp) {
X	sp->S_dfault = getfield(NULL, ":");
X    }
X    screen(first, disp_screen, last, NULL, TRUE);
X    noecho();
X    c = lastchar;
X    do {
X	if (c == LF || c == CR)
X	    break;
X	if (c == EOT) {		/* CTL-D entered */
X	    fseek(dbfile, (long)(-strlen(rcd)), 1);
X	    putc('D', dbfile);
X	    break;
X	}
X	if (c == ESC) {
X	    echo();
X	    return(1);
X	}
X	if (c == STX) {
X	    echo();
X	    return(-1);
X	}
X	rawputchar(BEL);
X    } while (c=rawgetchar());
X    echo();
X    return(0);
X}
SHAR_EOF
true || echo 'restore of delete.c failed'
# ============= dumpdb.c ==============
echo 'x - extracting dumpdb.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dumpdb.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)dumpdb.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      DUMPDB.C        */
X/*      This subroutine is used to dump all records from
X        the data base and the alternate key files, including
X        deleted records.
X*/
X
X#include "stdio.h"
X#include "ascii.h"
X#include "cardfile.h"
X#include <signal.h>
X
Xstatic	FILE	*in, *out;
Xstatic	int	quit = 0;
Xstatic	SIGRTN	abort();
Xstatic	SIGRTN	(*old_sig)();
X
Xdumpdb(dbname, ak_data, fields)
Xchar    *dbname;
Xstruct  AKdata  *ak_data;
Xstruct  Fdata   *fields;
X{
X    char        ptitle[PWIDTH+1];
X    int         pnum, lnum;
X    char        fname[FNSIZE];
X    char        rcd[DBSIZE+1];
X    
X    if ((out = popen("lp", "w")) == NULL) {
X        msg("Unable to open printer");
X        return(1);
X    }
X    sprintf(fname, "%s%s.db", datadir, dbname);
X    if ((in = fopen(fname, "r")) == NULL) {
X	pclose(out);
X        msg("Unable to open DB file");
X        return(1);
X    }
X    /* msg() will leave the cursor at the bottom */
X    msg("");
X    fputs("DEL to abort dump", stdout);
X    old_sig = signal(SIGINT, abort);
X    lnum = PLENGTH + 1;                 /* force top-of-page */
X    pnum = 1;
X    sprintf(ptitle, "Records in %s.db", dbname);
X    while( !quit && (fgets(rcd, DBSIZE, in)) != NULL) {   /* print DB file */
X        rcd[strlen(rcd)-1] = '\0';      /* truncate \n */
X        if (lnum + 3 + (strlen(rcd)+PWIDTH-1)/PWIDTH >= PLENGTH) {
X            newpage(&pnum, ptitle);
X            lnum = 3;
X        }
X        fputs(rcd, out);
X        putc('\n', out);
X        lnum += (strlen(rcd)+PWIDTH-1)/PWIDTH;
X    }
X    if (quit)
X	return(1);
X    fclose(in);
X    while (ak_data->A_fldnum >= 0) {
X	strcpy(fname, datadir);
X        strcat(fname, ak_data->A_akname);
X        if ((in = fopen(fname, "r")) == NULL) {
X            sprintf(ptitle, "Unable to open %s", fname);
X            msg(ptitle);
X            return(1);
X        }
X        lnum = PLENGTH + 1;
X        pnum = 1;
X        sprintf(ptitle, "Records in %s sorted on %s",
X            fname, fields[ak_data->A_fldnum].F_title);
X	/* print AK file */
X        while( !quit && (fgets(rcd, DBSIZE, in)) != NULL) {
X            rcd[strlen(rcd)-1] = '\0';  /* truncate \n */
X            if (lnum + 3 + (strlen(rcd)+PWIDTH-1)/PWIDTH >= PLENGTH) {
X                newpage(&pnum, ptitle);
X                lnum = 3;
X            }
X            fputs(rcd, out);
X            putc('\n', out);
X            lnum += (strlen(rcd)+PWIDTH-1)/PWIDTH;
X        }
X	if (quit)
X	    return(1);
X        fclose(in);
X        ++ak_data;
X    }
X    pclose(out);
X    signal(SIGINT, old_sig);
X    return(0);
X}
X
Xnewpage(pnum, title)
Xint     *pnum;
Xchar    *title;
X{
X
X    putc(FF, out);
X    fprintf(out, "%-69sPAGE %4d\n\n\n", title, *pnum);
X    *pnum += 1;
X}
X
X
Xstatic SIGRTN
Xabort()
X{
X
X    signal(SIGINT, old_sig);
X    fputs("\n\nOUTPUT ABORTED!\n", out);
X    pclose(out);
X    fclose(in);
X    msg("Dump aborted");
X    quit = 1;
X}
SHAR_EOF
true || echo 'restore of dumpdb.c failed'
# ============= extract.c ==============
echo 'x - extracting extract.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'extract.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)extract.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      EXTRACT.C       */
X/*      This subroutine is used to write selected records from the
X *      database on to another disk file.
X */
X
X#include "stdio.h"
X#include "cardfile.h"
X#include "ascii.h"
X
XFILE    *ext_fp;
Xchar    ext_fname[FNSIZE];
Xint     rec_cnt;
Xstruct Sdata    fn_screen[] = {
X		    {"File Name", FNSIZE, ext_fname, NULL},
X		    {0, 0, 0, 0}
X		};
X
Xextract(fields, dbname)
Xstruct  Fdata   *fields;
Xchar    *dbname;
X{
X    char	first[SWIDTH+1];
X    int 	write_rcd();
X
X    sprintf(first, "Select records from the %s Data Base to be extracted",
X	dbname);
X    screen(first, fn_screen, "Enter File Name of Extract File", NULL, FALSE);
X    if (ext_fname[0] == '\0') {
X	msg("No file name entered, using temp.ext");
X	strcpy(ext_fname, "temp.ext");
X    }
X    if ((ext_fp = fopen(ext_fname, "w")) == NULL) {
X	sprintf(first, "Unable to open file %s for output", ext_fname);
X	msg(first);
X	return(1);
X    }
X    rec_cnt = 0;
X    findrcds(fields, dbname, write_rcd, first);
X    fclose(ext_fp);
X    sprintf(first, "%d records written to %s", rec_cnt, ext_fname);
X    msg("");
X    fputs(first, stdout);	/* this works because msg() leaves the cursor */
X    sleep(5);
X    return(0);
X}
X
X
X/*ARGSUSED*/
Xint
Xwrite_rcd(dummy1, rcd, dummy2, dummy3)
Xchar    *rcd;
Xchar    *dummy1, *dummy2, *dummy3;
X{
X    ++rec_cnt;
X    return(fputs(rcd, ext_fp));
X}
SHAR_EOF
true || echo 'restore of extract.c failed'
# ============= find.c ==============
echo 'x - extracting find.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'find.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)find.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*      FIND.C  	*/
X/*      This module is used to find and display records
X**	in the data base matching the selection criteria.
X**	The user may select multiple values of one field
X**	which will be or'd and/or multiple fields which will
X**	be and'd. In other words, if field 1 is specified
X**	as value1:value2 and field3 is specified as value3.
X**	Records with field1==(value1 || value2) && field3==value3
X**	will be displayed.
X**	It calls findrcds.c to do all the work.
X*/
X
X#include "stdio.h"
X#include "ascii.h"
X#include "cardfile.h"
X
Xstatic struct Sdata disp_screen[MAXFLDS+1];
X
Xfind(fields, dbname)
Xstruct  Fdata   *fields;
Xchar    *dbname;
X{
X    struct Fdata *fp;
X    struct Sdata *sp;
X    char	first[SWIDTH];
X    int 	display();
X    
X    sprintf(first, "Display Records from the %s Data Base", dbname);
X    for (fp = fields, sp = disp_screen ; fp->F_title[0] != 0; ++fp, ++sp) {
X	sp->S_title = fp->F_title;
X	sp->S_length = fp->F_length;
X	sp->S_result = (char*)malloc((unsigned)fp->F_length+1);
X	sp->S_page = fp->F_page;
X	sp->S_Lrow = fp->F_Lrow;
X	sp->S_Lcol = fp->F_Lcol;
X	sp->S_Drow = fp->F_Drow;
X	sp->S_Dcol = fp->F_Dcol;
X	sp->S_Dfmt = fp->F_Dfmt;
X    }
X    sp->S_title = 0;
X
X    findrcds(fields, dbname, display, first);
X    for (sp = disp_screen ; sp->S_title != 0; ++sp) {
X	free(sp->S_result);
X    }
X    return(0);
X}
X
X
X/*ARGSUSED*/
Xdisplay(fields, rcd, dummy1, dummy2)
Xstruct  Fdata   *fields;
Xchar    *rcd;
XFILE	*dummy1;
Xchar    *dummy2;
X{
X    char	c, save[DBSIZE+1];
X    FILE	*filep;
X    char	*first = "Selected Records";
X    char	*last = "RETURN for next, ESC to abort, CTL-P to print, CTL-B to reverse";
X    static      char    fmt[256];
X    struct      Sdata   *sp;
X    char	*getfield();
X    extern char	lastchar;
X    
X    strcpy(save, rcd);
X    getfield(rcd, ":");
X    for (sp = disp_screen; sp->S_title != 0; ++sp) {
X	sp->S_dfault = getfield(NULL, ":");
X    }
X    screen(first, disp_screen, last, NULL, TRUE);
X    noecho();
X    c = lastchar;
X    do {
X	if (c == LF || c == CR)
X	    break;
X	if (c == DLE) {		/* CTL-P entered */
X	    if ((filep=popen("lp", "w")) == NULL) {
X		msg("Unable to open printer");
X		continue;
X	    }
X	    strcpy(rcd, save);
X	    putrcd(first, rcd, filep, fmt, PWIDTH, 1);
X	    pclose(filep);
X	    continue;
X	}
X	if (c == ESC) {
X	    echo();
X	    return(1);
X	}
X	if (c == STX) {		/* CTL-B entered */
X	    echo();
X	    return(-1);
X	}
X	rawputchar(BEL);
X    } while (c=rawgetchar());
X    echo();
X    return(0);
X}
SHAR_EOF
true || echo 'restore of find.c failed'
# ============= findrcds.c ==============
echo 'x - extracting findrcds.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'findrcds.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)findrcds.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*	FINDRCDS.C	*/
X/*	This module is used to find records in the data base
X**	matching the selection criteria.
X**	The user may select multiple values of one field
X**	connected by '&' or '|' which will be or'd and/or
X**	multiple fields which will be and'd.
X**	In other words, if field 1 is specified
X**	as value1|value2 and field3 is specified as value3.
X**	Records with field1==(value1 || value2) && field3==value3
X**	will be selected. An external routine 'display', passed
X**	as a parameter will be called to process the selected records.
X*/
X
X#include <stdio.h>
X#include <errno.h>
X#include "ascii.h"
X#include "cardfile.h"
X
Xextern	int	readonly;
X
Xstruct Keys {
X    char	K_flag;
X    long	K_offset;
X};
X/*
X * Possible values of the K_flag field
X */
X#define	GOOD	0	/* good record */
X#define	MATCH	1	/* found on this search argument */
X#define	END	32	/* physical end of key array */
X#define	FREE	64	/* first free key block */
X
X
Xfindrcds(fields, dbname, display, first)
Xstruct  Fdata	*fields;
Xchar    *dbname;
Xint	(*display)();
Xchar    *first;
X{
X    struct	Fdata	*fp;
X    struct	Sdata	find_screen[MAXFLDS+1], *sp;
X    int 	found;
X    FILE	*filep;
X    char	filename[FNSIZE];
X    diskptr	offset;
X    char	*last =
X		"Separate alternate values with a | for 'or' or a & for 'and'";
X    int		knum, firstflag;
X    long	getkey();
X    char	*keyval, *cp;
X    char	*rcd;
X    char	operator, nextop;
X    char	out_line[SWIDTH+1];
X    struct	Keys	keys[MAXKEYS+1], *kp;
X    int		i;
X    int 	rc;
X    char	*getslct(), *malloc();
X    
X    fp = fields;
X    sp = find_screen;
X    while (fp->F_title[0] != '\0') {
X	if (fp->F_key == 'N') {
X	    ++fp;
X	    continue;
X	}
X	sp->S_title = fp->F_title;
X	sp->S_length = 2 * fp->F_length;
X	sp->S_page = -1;
X	sp->S_Lrow = -1;
X	sp->S_Lcol = -1;
X	sp->S_Drow = -1;
X	sp->S_Dcol = -1;
X	sp->S_Dfmt = "";
X	sp->S_result = malloc((unsigned)sp->S_length+1);
X	sp->S_dfault = 0;
X	++fp;
X	++sp;
X    }
X    sp->S_title = 0;
X    while (screen(first, find_screen, last, 0, FALSE) != 0) {
X	firstflag = 1;
X	knum = -1;
X	keys[0].K_flag = FREE;
X	for (i=1; i<MAXKEYS; ++i)
X	    keys[i].K_flag = GOOD;
X	keys[MAXKEYS].K_flag = END;
X	sp = find_screen;
X	while (sp->S_title) {		/* loop on key field */
X	    ++knum;
X	    if (*(sp->S_result) == '\0') {	/* was key entered */
X		++sp;
X		continue;
X	    }
X	    sprintf(filename, "%s%s.ak%d", datadir, dbname, knum);
X	    if ((filep = fopen(filename, "r")) == NULL) {
X		msg("Unable to open alternate key file");
X		getout();
X	    }
X	    operator = '&';
X	    if (firstflag) {
X		firstflag = 0;
X		operator = '|';
X	    }
X	    cp = sp->S_result;
X	    /* loop for each key for this field */
X	    while ((keyval = getslct(cp, "&|", &nextop)) != NULL) {
X		cp = NULL;
X		/* loop getting offsets for this value */
X		while ((offset = getkey(filep, keyval)) >= 0L) {
X		    keyval = 0;
X		    if (operator == '|') {
X			if (orkey(offset, keys) == -1)
X			    break;
X		    }
X		    if (operator == '&') {
X			andkey(offset, keys);
X		    }
X		}
X		if (operator == '&') {
X		    purgekey(keys);
X		}
X		operator = nextop;
X	    }
X	    fclose(filep);
X	    ++sp;
X	}
X	sprintf(filename, "%s%s.db", datadir, dbname);
X	if (readonly) {
X	    if ((filep = fopen(filename, "r")) == NULL) {
X		sprintf(out_line, "Unable to open %s, errno=%d\n", filename, errno);
X		msg(out_line);
X		return(1);
X	    }
X	} else {
X	    if ((filep = fopen(filename, "r+")) == NULL) {
X		if (errno == EACCES) {
X		    strcpy(out_line, "You do not have permission to modify this database");
X		} else {
X		    sprintf(out_line, "Unable to open %s, errno=%d\n", filename, errno);
X		}
X		msg(out_line);
X		return(1);
X	    }
X	}
X	found = 0;
X	rcd = malloc(DBSIZE);
X	kp = keys;
X	while (kp->K_flag == GOOD) {
X	    if (kp->K_offset <0L) {
X		++kp;
X		continue;
X	    }
X	    fseek(filep, kp->K_offset, 0);
X	    if (fgets(rcd, DBSIZE, filep) == NULL) {
X		msg("Error reading DB file");
X		getout();
X	    }
X	    if (*rcd == 'D') {
X		kp->K_offset = -1L;
X		++kp;
X		continue;
X	    }
X	    ++found;
X	    if ((rc = (*display)(fields, rcd, filep, dbname)) == 1)
X		break;
X	    if (rc == -1) {	/* reverse */
X		while (kp > &keys[0]) {
X		    --kp;
X		    if (kp->K_offset >= 0L)
X			break;
X		}
X	    } else {
X		++kp;
X	    }
X	}
X	fclose(filep);
X	free(rcd);
X	if (found == 0) {
X	    msg("No records found");
X	}
X    }
X    sp = find_screen;
X    while (sp->S_title) {
X	free(sp->S_result);
X	++sp;
X    }
X    return(0);
X}
X
X
Xchar *
Xgetslct(string, seps, sepval)   /* identical to getfld except separator is */
Xchar    *string, *seps, *sepval;	/* returned thru sepval */
X{
X    register char	*p, *r;
X    static   char	*savept;
X    
X    p = (string == NULL)? savept : string;
X    if (p == 0)
X	return(NULL);
X    if (*p == '\0')
X	return(NULL);
X    if ((r = strpbrk(p, seps)) == NULL) {	/* move past token */
X	*sepval = '\0';
X	savept = 0;		/* indicate this is the last token */
X    } else {
X	*sepval = *r;
X	*r = '\0';
X	savept = ++r;
X    }
X    return(p);
X}
X
X
Xorkey(offset, keys)
Xdiskptr	offset;
Xstruct	Keys	*keys;
X{
X    struct Keys	*save;
X
X    save = NULL;
X    while (keys->K_flag == GOOD) {
X	if (offset == keys->K_offset) {
X	    return(0);
X	}
X	if (keys->K_offset < 0L && save == NULL) {
X	    save = keys;	/* found free point for insertion */
X	}
X	++keys;
X    }
X    if (save == NULL) {
X	if (keys->K_flag == END) {
X	    msg("Too many records selected");
X	    return(-1);
X	}
X	save = keys;
X	if ((++keys)->K_flag != END)
X	    keys->K_flag = FREE;
X    }
X    save->K_flag = GOOD;
X    save->K_offset = offset;
X    return(0);
X}
X
Xandkey(offset, keys)
Xdiskptr	offset;
Xstruct Keys	*keys;
X{
X
X    while(keys->K_flag < END) {
X	if (offset == keys->K_offset) {
X	    keys->K_flag = MATCH;
X	    break;
X	}
X	++keys;
X    }
X}
X
X
Xpurgekey(keys)
Xstruct Keys	*keys;
X{
X
X    while(keys->K_flag < END) {
X	if (keys->K_flag != MATCH) {
X	    keys->K_offset = -1L;
X	} else {
X	    keys->K_flag = GOOD;
X	}
X	++keys;
X    }
X}
SHAR_EOF
true || echo 'restore of findrcds.c failed'
# ============= fmt_chk.c ==============
echo 'x - extracting fmt_chk.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'fmt_chk.c' &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)fmt_chk.c	3.1    DeltaDate 8/3/90    ExtrDate 10/6/90";
X#endif
X
X/*
X**	FMT_CHK.C
X**
X** Return 0 if field matches fmt, 1 otherwise
X**
X**/
X
X#include	<stdio.h>
X#include	"cardfile.h"
X#ifdef BSD_RE
Xextern	char	*re_comp();
Xextern	int	re_exec();
X#endif
X#ifdef SYSV_RE
Xextern	char	*regcmp();
Xextern	char	*regex();
X#endif
X#ifdef PD_RE
X#include	<regexp.h>
Xextern	regexp	*regcomp();
Xextern	int	regexec();
X#endif
X
X
Xint
Xfmt_chk(field, fmt)
Xchar	*field, *fmt;
X{
X    static char	lastval[MAXFMT];
X#ifdef BSD_RE
X    int		rc;
X#endif
X#ifdef SYSV_RE
X    char	*rc;
X    static char	*cval;
X#endif
X#ifdef PD_RE
X    int		rc;
X    static regexp *cval;
X#endif
X#ifdef NO_RE
X    return(0);
X#endif
X
X    if (fmt == NULL || *fmt == '\0')
X	return(0);
X    
X    if (strcmp(fmt, lastval) != 0) {
X	strcpy(lastval, fmt);
X#ifdef BSD_RE
X	if (re_comp(fmt) != 0) {
X#else
X	if (cval)
X	    free(cval);
X# ifdef SYSV_RE
X	if ((cval = regcmp(fmt, 0)) == 0) {
X# else	/* PD_RE */
X	if ((cval = regcomp(fmt, 0)) == 0) {
X# endif
X#endif	/* BSD_RE */
X	    msg("Invalid format specification");
X	    return(-1);
X	}
X    }
X
X#ifdef BSD_RE
X    if ((rc = re_exec(field)) != 1) {
X	return(1);
X    }
X#endif
X#ifdef SYSV_RE
X    if ((rc = regex(cval, field)) == NULL) {
X	return(1);
X    }
X#endif
X#ifdef PD_RE
X    if ((rc = regexec(cval, field)) == NULL) {
X	return(1);
X    }
X#endif
X    return(0);
X}
X
X#ifdef PD_RE
X/* Let cardfile handle errors */
Xvoid
Xregerror(msg)
Xchar	*msg;
X{
X    return;
X}
X#endif
SHAR_EOF
true || echo 'restore of fmt_chk.c failed'
true || echo 'restore of getkey.c failed'
echo End of part 1, continue with part 2
exit 0



More information about the Comp.sources.misc mailing list