cardfile part 1 of 2
Dave Lampe
djl at dplace.UUCP
Mon Apr 17 08:25:49 AEST 1989
This is the first release of my index card database program. It is only
usable on Sys V since it requires terminfo, not termcap.
Dave Lampe
{ames | lll-tis | sun | pyramid}!pacbell!dplace!djl
(415) 455-1571 (H)
(408) 986-1820 (W)
---- Cut Here and unpack ----
#!/bin/sh
# shar: Shell Archiver (v1.22)
#
# This is part 1 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
# Run the following text with /bin/sh to create:
# README
# cardfile.1
# Makefile
# cardfile.c
# add.c
# change.c
# common.c
# compress.c
# define.c
# delete.c
# dumpdb.c
# extract.c
# find.c
# findrcds.c
# getkey.c
# keymatch.c
# maint.c
# menu.c
# printdb.c
# putrcd.c
# rawio.c
# rbuildak.c
# screen.c
# setupkeys.c
# updak.c
# ascii.h
# cardfile.h
# library.def
# library.db
# library.ak0
# library.ak1
# library.ak2
# library.ak3
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
exit 1; fi
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
XIt runs only on System V because it uses the terminfo capabilities. Some
Xof the source may look a little strange because I wrote it originally to
Xrun under CPM. I still have the CPM version if anyone wants it.
X
XThere are two things that need to be done yet. It needs to be converted
Xto run under BSD and the indexing needs to be converted from a sequential
Xsearch to something faster such as a B tree. Even with a sequential search,
Xthe speed is acceptable on a database of about a 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-1820 (W)
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
echo "x - extracting cardfile.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > cardfile.1 &&
X.\ "@(#)cardfile.1 2.2 Delta Date 4/16/89 ExtrDate 4/16/89 ";
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 a name, a maximum length,
Xa flag to determine if it is required or not,
Xa flag to determine if it is an index field
X(whether or not it can be searched for),
Xand if multiple values may appear in the field,
Xwhat character will separate the values.
XFor example a book may have multiple authors separated by semicolons.
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 thje 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.
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".
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.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 \fIMaint\fP menu),
Xthe output file, and the output width.
X.if n .P
X.if t .bp
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 Maint
XThe \fIMAINT\fP option will generate a submenu of infrequently used actions.
XThe actions available from the maintenance menu are:
X.br
X.po +0.5i
X.ll -0.5i
X.SS Dump
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.SS Compress
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.SS "Rebuild AK's"
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.SS Extract
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.SS Exit
XThe \fIEXIT\fP option of the maintenance menu will return to the main menu.
X.br
X.po -0.5i
X.ll +0.5i
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.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 11.
XThese are arbitrary numbers and are easy to change.
X.br
XAt least one field must be defined as an index field.
X.br
XThe termcap name
X.I kcbt
Xmay not be defined in some versions of UNIX.
XJust use the up arrow instead.
X.br
XThere is no concurrency control in \fIcardfile\fP.
SHAR_EOF
chmod 0444 cardfile.1 || echo "restore of cardfile.1 fails"
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# @(#)Makefile 2.3 DeltaDate 4/16/89 ExtrDate 4/16/89
X
X# These are for compiling on the Sun
X#CC = /usr/5bin/cc
X#LINT = /usr/5bin/lint
X#DEFINES = -DBSD -DRE
X
X
X# -DRE get full regular expression matches for doing searches
XDEFINES = -DRE
XLINT = lint
X
XBINDIR = /usr/local/bin/
XMANDIR = /usr/man/man1/
X
X#
X# Nothing past here should need changing
X#
X
X.SUFFIXES: .1 .1~
X.c~.c:
X $(GET) $(GFLAGS) $<
X
X.1~.1:
X $(GET) $(GFLAGS) $<
X
X
XSHAR = shar
XSHARFLAGS = -v -c -l60 -o cardfile.shr
X
X#CFLAGS = -g -DDEBUG $(DEFINES)
XCFLAGS = -g $(DEFINES)
X
XDOCS = cardfile.1
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 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 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) -lPW -lcurses
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 $(SRC) $(HDRS) Makefile
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: $(DOCS)
X nroff -man cardfile.1 | lp -o-qc
X
Xshar: $(HDRS) $(SRC) $(DOCS) Makefile $(TESTDB)
X $(SHAR) $(SHARFLAGS) README $(DOCS) Makefile \
X $(SRC) $(HDRS) $(TESTDB)
X
Xlint: $(HDRS) $(SRC)
X $(LINT) $(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
chmod 0444 Makefile || echo "restore of Makefile fails"
echo "x - extracting cardfile.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > cardfile.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)cardfile.c 2.2 DeltaDate 4/16/89 ExtrDate 4/16/89";
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 <curses.h>
X#include <term.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;
Xstruct termio instty, outstty;
Xvoid setupscr();
Xvoid exit();
Xunsigned sleep();
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 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 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 for (i=0; i<num_flds; i++) { /* get definition of each field */
X fgets(line_buf, 132, def_fp);
X fp = &fields[i];
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 }
X fp = &fields[i];
X fp->F_title[0] = '\0';
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 fgets(line_buf, 132, def_fp);
X line_buf[strlen(line_buf)-1] = '\0';
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 fclose(def_fp);
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
Xvoid
Xsetupscr()
X{
X
X setbuf(stdout, NULL);
X setbuf(stdin, NULL);
X ioctl(0, TCGETA, &outstty);
X instty.c_iflag = outstty.c_iflag;
X instty.c_oflag = outstty.c_oflag;
X instty.c_cflag = outstty.c_cflag;
X instty.c_lflag = 0;
X instty.c_line = outstty.c_line;
X instty.c_cc[VINTR] = outstty.c_cc[VINTR];
X instty.c_cc[VQUIT] = outstty.c_cc[VQUIT];
X instty.c_cc[VERASE] = outstty.c_cc[VERASE];
X instty.c_cc[VKILL] = outstty.c_cc[VKILL];
X instty.c_cc[VMIN] = 1;
X instty.c_cc[VTIME] = 0;
X instty.c_cc[6] = outstty.c_cc[6];
X instty.c_cc[7] = outstty.c_cc[7];
X ioctl(0, TCSETAW, &instty);
X setupterm((char*)0, 1, (int*)0);
X setupkeys();
X putp(keypad_xmit);
X}
X
Xgetout()
X{
X
X putp(keypad_local);
X putp(clear_screen);
X ioctl(0, TCSETAW, &outstty);
X exit(0);
X}
X
Xstatic
Xusage(prog)
Xchar *prog;
X{
X printf("Usage: %s [-r] file\n", prog);
X}
SHAR_EOF
chmod 0644 cardfile.c || echo "restore of cardfile.c fails"
echo "x - extracting add.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > add.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)add.c 2.3 DeltaDate 4/16/89 ExtrDate 4/16/89";
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 fp = fields;
X sp = add_screen;
X while (fp->F_title[0] != 0) {
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 ++fp;
X ++sp;
X }
X sp->S_title = 0;
X while (screen(first, add_screen, 0, 0) != 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 }
X if (err > 0)
X break;
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
chmod 0444 add.c || echo "restore of add.c fails"
echo "x - extracting change.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > change.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)change.c 2.3 DeltaDate 4/16/89 ExtrDate 4/16/89";
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#include <curses.h>
X#include <term.h>
X
Xchar *malloc(), *getfield();
Xextern int readonly;
X
X
Xchange(fields, dbname)
Xstruct Fdata *fields;
Xchar *dbname;
X{
X char first[SWIDTH];
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 findrcds(fields, dbname, processc, first);
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 static char fmt[256];
X int fn;
X struct Fdata *fp;
X
X strcpy(save, rcd);
X putp(clear_screen); /* clear screen */
X if (*fmt == '\0') { /* first time */
X fp = fields;
X fn = 1;
X while (fp->F_title[0]) {
X sprintf(&fmt[strlen(fmt)], "%s: %%%d%%n", fp->F_title, fn);
X ++fn;
X ++fp;
X }
X }
X putrcd("Record to be CHANGED", save, stdout, fmt, SWIDTH, 2);
X putp(tparm(cursor_address, MSGLINE, 9));
X fputs("RETURN for next, ESC to abort, Ctrl-C to Change, Ctrl-B to reverse",
X stdout);
X noecho();
X while ((c=rawgetchar()) != LF && c != CR) {
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 }
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 add_screen[MAXFLDS+1], *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 = add_screen;
X while(fp->F_title[0]) {
X sp->S_title = fp->F_title;
X sp->S_length = fp->F_length;
X sp->S_result = malloc((unsigned)fp->F_length);
X sp->S_dfault = getfield(0, ":");
X ++fp;
X ++sp;
X }
X sp->S_title = 0;
X outline[0] = '\0';
X while (screen("Enter changes", add_screen, 0, 0) > 0) {
X err = 0;
X fp = fields;
X sp = add_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 sp = add_screen;
X while(sp->S_title)
X free((sp++)->S_result);
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 sp = add_screen;
X while(sp->S_title)
X free((sp++)->S_result);
X return(0);
X}
SHAR_EOF
chmod 0444 change.c || echo "restore of change.c fails"
echo "x - extracting common.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > common.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)common.c 2.1 DeltaDate 2/13/89 ExtrDate 2/13/89";
X#endif
X
X/* COMMON.C */
X#include "stdio.h"
X#include "ascii.h"
X#include "cardfile.h"
X#include <curses.h>
X#include <term.h>
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 putp(enter_blink_mode); /* blink */
X fputs(str, stdout);
X putp(exit_attribute_mode); /* back to normal */
X sleep(5);
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}
SHAR_EOF
chmod 0644 common.c || echo "restore of common.c fails"
echo "x - extracting compress.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > compress.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)compress.c 2.2 DeltaDate 4/16/89 ExtrDate 4/16/89";
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
chmod 0644 compress.c || echo "restore of compress.c fails"
echo "x - extracting define.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > define.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)define.c 2.2 DeltaDate 4/16/89 ExtrDate 4/16/89";
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 (8 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 <curses.h>
X#include <term.h>
X
Xstruct Sdata def_screen[] = {
X {"FIELD NAME",TSIZE," ",0},
X {"MAXIMUM LENGTH",3," ",0},
X {"REQUIRED?",1," ","N"},
X {"SEARCH KEY",1," ","Y"},
X {"SUBFIELD SEPARATORS",5," ",0},
X {0,0,0,0}
X };
X
Xstruct 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
X sprintf(first,"DEFINING %s DATA BASE", basename);
X num_fields = 0;
X fp = fields;
X tsize = 0;
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 while (screen(first, def_screen, last, 0)) {
X err = 0;
X strcpy(fp->F_title, def_screen[0].S_result);
X if (strchr(fp->F_title, ':') != NULL) {
X msg("TITLE field must not include :");
X ++err;
X }
X fp->F_length = atoi(def_screen[1].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 fp->F_required = toupper(def_screen[2].S_result[0]);
X if (fp->F_required != 'Y' && fp->F_required != 'N') {
X msg("REQUIRED must be Y or N");
X ++err;
X }
X fp->F_key = toupper(def_screen[3].S_result[0]);
X if (fp->F_key != 'Y' && fp->F_key != 'N') {
X msg("KEY must be Y or N");
X ++err;
X }
X strcpy(fp->F_seps, def_screen[4].S_result);
X if (strchr(fp->F_seps, ':') != NULL) {
X msg("SEPARATORS must not include :");
X ++err;
X }
X if (err) {
X continue;
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 ++fp;
X if (++num_fields > MAXFLDS) {
X msg("Too many fields defined, aborting");
X return(1);
X }
X }
X
X putp(clear_screen); /* clear screen */
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 fclose(filep);
X return(0);
X}
SHAR_EOF
chmod 0644 define.c || echo "restore of define.c fails"
echo "x - extracting delete.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > delete.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)delete.c 2.3 DeltaDate 4/16/89 ExtrDate 4/16/89";
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#include <curses.h>
X#include <term.h>
X
X
Xextern int readonly;
X
Xdelete(fields, dbname)
Xstruct Fdata *fields;
Xchar *dbname;
X{
X char first[SWIDTH];
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 findrcds(fields, dbname, processd, first);
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
X strcpy(save, rcd);
X putp(clear_screen); /* clear screen */
X if (*fmt == '\0') { /* first time */
X fp = fields;
X fn = 1;
X while (fp->F_title[0]) {
X sprintf(&fmt[strlen(fmt)], "%s: %%%d%%n", fp->F_title, fn);
X ++fn;
X ++fp;
X }
X }
X putrcd("Record to be DELETED", save, stdout, fmt, SWIDTH, 2);
X putp(tparm(cursor_address, MSGLINE, 9));
X fputs("RETURN for next, ESC to abort, CTL-D to DELETE, CTL-B to reverse",
X stdout);
X noecho();
X while ((c=rawgetchar()) != LF && c != CR) {
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 }
X echo();
X return(0);
X}
SHAR_EOF
chmod 0444 delete.c || echo "restore of delete.c fails"
echo "x - extracting dumpdb.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dumpdb.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)dumpdb.c 2.1 DeltaDate 2/13/89 ExtrDate 2/13/89";
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 <curses.h>
X#include <term.h>
X#include <signal.h>
X
Xstatic FILE *in, *out;
Xstatic int quit = 0;
Xstatic int abort();
Xstatic int (*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 putp(tparm(cursor_address, MSGLINE, 9));
X putp(clr_eol);
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
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
chmod 0644 dumpdb.c || echo "restore of dumpdb.c fails"
echo "x - extracting extract.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > extract.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)extract.c 2.2 DeltaDate 4/16/89 ExtrDate 4/16/89";
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#include <curses.h>
X#include <term.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);
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 putp(tparm(cursor_address, MSGLINE, 9));
X putp(clr_eol);
X fputs(first, stdout);
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
chmod 0444 extract.c || echo "restore of extract.c fails"
echo "x - extracting find.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > find.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)find.c 2.2 DeltaDate 4/16/89 ExtrDate 4/16/89";
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#include <curses.h>
X#include <term.h>
X
X
Xfind(fields, dbname)
Xstruct Fdata *fields;
Xchar *dbname;
X{
X char first[SWIDTH];
X int display();
X
X sprintf(first, "Display Records from the %s Data Base", dbname);
X findrcds(fields, dbname, display, first);
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 static char fmt[256];
X int fn;
X struct Fdata *fp;
X
X strcpy(save, rcd);
X putp(clear_screen); /* clear screen */
X if (*fmt == '\0') { /* first time */
X fp = fields;
X fn = 1;
X while (fp->F_title[0]) {
X sprintf(&fmt[strlen(fmt)], "%s: %%%d%%n", fp->F_title, fn);
X ++fn;
X ++fp;
X }
X }
X putrcd(first, rcd, stdout, fmt, SWIDTH, 2);
X putp(tparm(cursor_address, MSGLINE, 9));
X fputs("RETURN for next, ESC to abort, CTL-P to print, CTL-B to reverse",
X stdout);
X noecho();
X while ((c=rawgetchar()) != LF && c != CR) {
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) {
X echo();
X return(-1);
X }
X rawputchar(BEL);
X }
X echo();
X return(0);
X}
SHAR_EOF
chmod 0444 find.c || echo "restore of find.c fails"
echo "x - extracting findrcds.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > findrcds.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)findrcds.c 2.3 DeltaDate 4/16/89 ExtrDate 4/16/89";
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; /* 0 = good record
X * 1 = found on this search argument
X * 64 = physical end of key array
X * 128 = first free key block */
X long K_offset;
X};
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_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) != 0) {
X firstflag = 1;
X knum = -1;
X keys[0].K_flag = 128;
X for (i=1; i<MAXKEYS; ++i)
X keys[i].K_flag = 0;
X keys[MAXKEYS].K_flag = 64;
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 == 0) {
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 == 0) {
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 == 64) {
X msg("Too many records selected");
X return(-1);
X }
X save = keys;
X if ((++keys)->K_flag != 64)
X keys->K_flag = 128;
X }
X save->K_flag = 0;
X save->K_offset = offset;
X return(0);
X}
X
X#define MATCH 1
X
Xandkey(offset, keys)
Xdiskptr offset;
Xstruct Keys *keys;
X{
X
X while(keys->K_flag < 64) {
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 < 64) {
X if (keys->K_flag != MATCH) {
X keys->K_offset = -1L;
X } else {
X keys->K_flag = 0;
X }
X ++keys;
X }
X}
SHAR_EOF
chmod 0444 findrcds.c || echo "restore of findrcds.c fails"
echo "x - extracting getkey.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > getkey.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)getkey.c 2.1 DeltaDate 2/13/89 ExtrDate 2/13/89";
X#endif
X
X/* GETKEY.C */
X/* This subroutine is used to search an alternate key file
X to find records matching the input value. It returns the
X offset of the record in the DB file if found, or -1 if
X no match was found.
X*/
X#include "stdio.h"
X#include "cardfile.h"
X#include "ascii.h"
X
Xdiskptr
Xgetkey(file, val)
XFILE *file;
Xchar *val;
X{
X static char *match;
X char rcd[AKSIZE];
X long atol();
X char *fgets();
X int rc;
X
X if (val != 0) { /* first time */
X match = val;
X fseek(file, 0L, 0);
X }
X while (fgets(rcd, AKSIZE, file) != NULL) {
X if ((rc = keymatch(rcd, match)) == -1) {
X break;
X } else if (rc == 1) {
X return (atol(strchr(rcd, ':')+1));
X }
X }
X return (-1L);
X}
SHAR_EOF
chmod 0644 getkey.c || echo "restore of getkey.c fails"
echo "x - extracting keymatch.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > keymatch.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)keymatch.c 2.1 DeltaDate 2/13/89 ExtrDate 2/13/89";
X#endif
X
X/* KEYMATCH.C */
X/* This subroutine is used to test if the key in the AK file
X** record matches the input value. Two options are supported,
X** UNIX style regular expressions or simple matches. If 'RE'
X** is defined regular expressions are allowed.
X** If the input value is enclosed in quotes an exact match is
X** required, otherwise upper/lower case is ignored. If simple
X** matching is being done, an '*' at the end of an unquoted
X** string matches everything.
X**/
X#include "cardfile.h"
X
X#ifdef RE
X# ifdef BSD
Xextern char *re_comp();
Xextern int re_exec();
X# else
Xextern char *regcmp(), *regex();
X# endif
X#endif
X
Xkeymatch(akrcd, val)
Xchar *akrcd, *val;
X{
X register int vlen;
X char convert[256];
X char key[256];
X static int lower;
X#ifdef RE
X static char lastval[256];
X# ifndef BSD
X static char *cval;
X# endif
X#else
X register char *cp = convert,
X *kp = key;
X#endif
X
X#ifdef RE
X if (strcmp(val, lastval) != 0) { /* new pattern */
X vlen = strlen(val);
X# ifndef BSD
X if (cval) /* free last pattern if any */
X free (cval);
X# endif
X strcpy(lastval, val);
X#else
X vlen = strlen(val);
X#endif
X strcpy(convert, val);
X if ((*convert == '"' && convert[vlen-1] == '"')
X || (*convert == '\'' && convert[vlen-1] == '\'')) {
X strcpy(convert, convert+1);
X convert[vlen-2] = '\0';
X lower = 0;
X } else {
X strlower(convert);
X lower = 1;
X }
X#ifdef RE
X# ifdef BSD
X if (re_comp(convert) != 0) {
X# else
X if ((cval = regcmp(convert, 0)) == 0) {
X# endif
X msg("Invalid search pattern");
X return(-1);
X }
X }
X#endif
X strcpy(key, akrcd);
X *strchr(key, ':') = '\0';
X if (lower) {
X strlower(key);
X }
X#ifdef RE
X# ifdef BSD
X if (re_exec(key) != 0)
X return(1);
X# else
X if (regex(cval, key) != 0)
X return(1);
X# endif
X return(0);
X#else
X while (*cp != '\0' && (lower == 0 || *cp != '*')) {
X if (*cp != *kp)
X return(0);
X ++cp;
X ++kp;
X }
X if (*cp == '\0' && *kp != '\0')
X return(0);
X return(1);
X#endif
X}
X
X
Xstatic
Xstrlower(str)
Xregister char *str;
X{
X
X while (*str) {
X if (*str >= 'A' && *str <= 'Z')
X *str = *str - 'A' + 'a';
X ++str;
X }
X}
SHAR_EOF
chmod 0644 keymatch.c || echo "restore of keymatch.c fails"
echo "x - extracting maint.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > maint.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)maint.c 2.1 DeltaDate 2/13/89 ExtrDate 2/13/89";
X#endif
X
X/* MAINT.C */
X/* This module is displays the maintenance menu and
X controls the execution of the associated routines
X*/
X#include "stdio.h"
X#include "cardfile.h"
X
Xchar *mfuncts[] = {"EXIT ",
X "DUMP ",
X "COMPRESS ",
X "REBUILD AK's",
X "EXTRACT ",
X 0
X };
X#define DUMP 1
X#define COMPRES 2
X#define RBUILD 3
X#define EXTRACT 4
X#define EXIT 0
X
X
Xmaint(fields, dbname, ak_data)
Xstruct Fdata *fields;
Xchar *dbname;
Xstruct AKdata *ak_data;
X{
X char first[SWIDTH];
X int func;
X
X sprintf(first, "Maintenance functions for %s", dbname);
X while ((func = menu(first, mfuncts)) != EXIT) {
X switch (func) {
X case DUMP:
X dumpdb(dbname, ak_data, fields);
X continue;
X case COMPRES:
X compress(dbname);
X rbuildak(dbname, ak_data, fields);
X continue;
X case RBUILD:
X rbuildak(dbname, ak_data, fields);
X continue;
X case EXTRACT:
X extract(fields, dbname);
X continue;
X default:
X msg("Illegal function chosen");
X }
X }
X}
SHAR_EOF
chmod 0644 maint.c || echo "restore of maint.c fails"
echo "x - extracting menu.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > menu.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)menu.c 2.1 DeltaDate 2/13/89 ExtrDate 2/13/89";
X#endif
X
X/* MENU.C */
X/* This subroutine is used to display a menu of commands
X and wait for the user to select one.
X It returns the number of the command selected.
X*/
X#include "cardfile.h"
X
Xmenu(dbname, functs)
Xchar *dbname;
Xchar **functs;
X{
X int func;
X char dummy[2];
X struct Sdata *sp, *mscreen;
X char *malloc();
X
X mscreen = (struct Sdata*)malloc((MAXFLDS+1) * sizeof(struct Sdata));
X sp = mscreen;
X do {
X sp->S_title = *functs;
X sp->S_length = 1;
X sp->S_result = dummy;
X sp->S_dfault = 0;
X ++sp;
X } while (*(functs++));
X screen(dbname, mscreen, 0, &func);
X free((char*)mscreen);
X return (func);
X}
SHAR_EOF
chmod 0644 menu.c || echo "restore of menu.c fails"
echo "x - extracting printdb.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > printdb.c &&
X#ifndef lint
Xstatic char Sccsid[] = "@(#)printdb.c 2.2 DeltaDate 4/16/89 ExtrDate 4/16/89";
X#endif
X
X/* PRINTDB.C */
X/* This module format prints the data base in the order requested.
X** NOTE: If a record contains multiple values for the key selected,
X** it will be printed multiple times.
X** Alternativly it will format print an extracted file (see extract.c)
X** The formats allowed are:
X** %NN - contents of field NN (1-maxfield)
X** %NN(form) - contents of field NN in printf '%form' format
X** %n - new-line
X** %t - tab
X** %f - form feed
X** %t(NN) - tab to column NN
X** %% - %
X** NOTE: '.' ends a format specification %1.1 prints the contents of
X** field 1 concatenated with a '1'.
X**/
X#include "stdio.h"
X#include "cardfile.h"
X#include "ascii.h"
X#include <curses.h>
X#include <term.h>
X#include <signal.h>
X
Xchar out_format[128], ext_file[15];
Xchar out_file[15], out_width[4];
Xstruct Sdata first_screen[] = {
X {"Format", 127, out_format, 0},
X {"Extracted File", 14, ext_file, 0},
X {"Output File", 14, out_file, 0},
X {"Output Width", 3, out_width, 0},
X {0, 0, 0, 0}
X };
X
Xstatic int quit = 0;
Xstatic int (*old_sig)();
Xstatic FILE *out;
Xstatic abort();
X
X
Xprintdb(fields, dbname)
Xstruct Fdata *fields;
Xchar *dbname;
X{
X char *keys[MAXAK+1];
X char keyv[MAXAK][TSIZE+1];
X int nkeys, i;
X struct Fdata *fp;
X char aknum[MAXAK];
X int keynum;
X char title[SWIDTH];
X char fname[FNSIZE];
X FILE *akfile, *dbfile;
X char akrec[AKSIZE+1], dbrec[DBSIZE+1];
X long offset, atol();
X int width;
X char *last;
X char hline[1024];
X
X sprintf(title, "Print %s data base", dbname);
X while (1) {
X last = "Enter ? for help.";
X screen(title, first_screen, last, 0);
X if (strcmp(ext_file, "?") == 0) {
X strcpy(hline, "Enter the name of the extract file generated");
X strcat(hline, " from\nthe maintenance menu. If you leave it");
X strcat(hline, " blank, the entire\ndata base will be dumped.");
X help(hline);
X continue;
X }
X if (strcmp(out_width, "?") == 0) {
X help("Enter the width of the output device, defaults to 80.");
X continue;
X }
X if (*out_width == '\0') {
X width = PWIDTH;
X } else {
X width = atoi(out_width);
X }
X if (strcmp(out_file, "?") == 0) {
X strcpy(hline, "Enter the name of the output file,");
X strcat(hline, " defaults to '|lp', the printer.");
X help(hline);
X continue;
X }
X if (*out_file == '\0') {
X strcpy(out_file, "|lp");
X }
X if (strcmp(out_format, "?") == 0) {
X strcpy(hline, "Enter the output format. All characters will");
X strcat(hline, " be\nprinted as entered except for % sequences.");
X strcat(hline, "\n\n\t%NN\t - contents of field NN (1-maxfield)");
X strcat(hline, "\n\t%NN(form) - contents of field NN in");
X strcat(hline, " printf '%form' format\n");
X strcat(hline, "\t%n\t- new-line\n");
X strcat(hline, "\t%t\t- tab\n");
X strcat(hline, "\t%t(NN)\t- tab to column NN\n");
X strcat(hline, "\t%f\t- form-feed\n");
X strcat(hline, "\t%%\t- %");
X help(hline);
X continue;
X }
X if (*out_format == '\0') { /* not specified, use default */
X fp = fields;
X i = 1;
X while (fp->F_title[0]) {
X sprintf(&out_format[strlen(out_format)], "%s: %%%d%%n",
X fp->F_title, i);
X ++i;
X ++fp;
X }
X strcat(out_format, "%n%n%n");
X }
X break;
X }
X if (ext_file[0] == '\0') {
X msg("No extract specified, entire database will be dumped");
X }
X fp = fields;
X nkeys = 0;
X if (ext_file[0] == '\0') {
X while (fp->F_title[0] != '\0') {
X if (fp->F_key != 'N') {
X sprintf(keyv[nkeys], "%-20s", fp->F_title);
X keys[nkeys] = keyv[nkeys];
X aknum[nkeys] = fp->F_key;
X ++nkeys;
X }
X ++fp;
X }
X keys[nkeys] = "Cancel ";
X aknum[nkeys] = '\0';
X ++nkeys;
X keys[nkeys] = 0;
X sprintf(title, "Print %s data base sorted by", dbname);
X keynum = menu(title, keys);
X if (aknum[keynum] == '\0') { /* cancel */
X return(1);
X }
X if (*out_file == '|')
X out = popen(out_file+1, "w");
X else
X out = fopen(out_file, "w");
X if (out == NULL) {
X msg("Unable to open output file");
X return(1);
X }
X
X sprintf(fname, "%s%s.ak%c", datadir, dbname, aknum[keynum]);
X if ((akfile = fopen(fname, "r")) == NULL) {
X msg("Unable to open alternate key file");
X getout();
X }
X sprintf(fname, "%s%s.db", datadir, dbname);
X if ((dbfile = fopen(fname, "r")) == NULL) {
X msg("Unable to open db file");
X getout();
X }
X putp(tparm(cursor_address, MSGLINE, 9));
X putp(clr_eol); /* clear line */
X fputs("DEL to abort printing", stdout);
X old_sig = signal(SIGINT, abort);
X
X while(!quit && fgets(akrec, AKSIZE, akfile) != NULL) {
X offset = atol(strchr(akrec, ':')+1);
X if (offset < 0L)
X continue;
X fseek(dbfile, offset, 0);
X if (fgets(dbrec, DBSIZE, dbfile) == NULL) {
X msg("Bad offset found");
X continue;
X }
X if (*dbrec == 'D') /* check for delete flag */
X continue;
X putrcd(0, dbrec, out, out_format, width, 1);
X }
X fclose(akfile);
X } else {
X if ((dbfile = fopen(ext_file, "r")) == NULL) {
SHAR_EOF
echo "End of part 1"
echo "File printdb.c is continued in part 2"
echo "2" > s2_seq_.tmp
exit 0
More information about the Alt.sources
mailing list