Category : Files from Magazines
Archive   : BYTE0389.ZIP
Filename : ZMAKEBIB.C

 
Output of file : ZMAKEBIB.C contained in archive : BYTE0389.ZIP


/*
** This program builds the bibliography database described in part III
** of "Trees 'N Keys" (Some Assembly Required, BYTE Magazine).
** It prompts for the input data filename, then reads that file and
** updates the database. Notice that this program doesn't create
** the database files (you have to use ZMAKEF to do that), it simply
** information to them. This means that you can keep adding stuff to
** the database 'til the cows come home....or your disk fills up.
*/

#include
#include
#include

/*
** ZSAM Globals
*/

#define nzkfiles 4 /* Number of key files */
#define nzdfiles 4 /* Number of data files */

#define KNODESIZE 512 /* Size of a key node */
/*
** ZSAM structure definitions.
*/

typedef unsigned char byte;

typedef struct { /* Key file header */
char kftype; /* Key file type, "K" or "O" */
unsigned int rootsc; /* Root sector */
unsigned int nokeysl; /* Number of keys, lo */
byte nokeysh; /* Number of keys, hi */
unsigned int kavsec; /* Key avail list head */
unsigned int nxkysc; /* Next free sector */
byte keylen; /* Key length */
byte maxks; /* Maximum keys per sector (node) */
unsigned int ackysc; /* Actual key sector in buffer */
byte misc[48]; /* Transient storage */
} zkey_header;

#define KHEADSIZE sizeof(zkey_header)-48

typedef struct { /* Data file header */
char dftype; /* Data file type, "S" or "C" */
unsigned int reclen; /* Record length */
unsigned int norecsl; /* Number of records, lo */
byte norecsh; /* Number of records, hi */
unsigned int davlo; /* Avail list, lo */
byte davhi; /* Avail list, hi */
unsigned int nxdalo; /* Next data record, lo */
byte nxdahi; /* Next data record, hi */
char misc[20]; /* Transient storage */
} zdat_header;
#define DHEADSIZE sizeof(zdat_header)-20

/*
** ZSAM interface storage.
*/

unsigned int zkfno; /* Current key file number */
unsigned int zdfno; /* Current data file number */
int zkfhand[nzkfiles]; /* Array of handles to key files */
int zdfhand[nzdfiles]; /* Array of handles to data files */
zkey_header *keyhead[nzkfiles]; /* Pointers to key file header storage */
zdat_header *dathead[nzdfiles]; /* Pointers to data file header storage */
char *keybuf[nzkfiles]; /* Pointers to key file buffers */
char *datbuf[nzdfiles]; /* Pointers to data file buffers */
long zoffset; /* Offset into files */

/*
** A pointer to the following structure (zsams) is passed
** to the ZSAM assembly routines.
*/
typedef struct {
unsigned int funct; /* Function code */
char *kbuf; /* Pointer to current key buffer */
char *dbuf; /* Pointer to current data buffer */
char *key; /* Pointer to current key */
char *rec; /* Pointer to current data record */
zkey_header *keyhd; /* Pointer to current key file header */
zdat_header *dathd; /* Pointer to current data file header */
} zsamstr;

zsamstr zsams;

extern int errno;

/*
** File definitions. Notice that ZSAM file numbers are assigned by
** *YOU* (the caller), not ZSAM. So, since I've set nzfiles and
** ndfiles to 4, I can reference key files and data files 0-3.
*/
#define MASTER_KEY 0
#define TITLE_DAT 0
#define KEYWORDS_KEY 1
#define KEYWORDS_DAT 1
#define AUTHMAST_KEY 2
#define AUTHMAST_DAT 2
#define AUTHNAME_KEY 3
#define AUTHNAME_DAT 3

/*
** User globals
*/
char difname[80]; /* Dictionary input filename */
char mastkey[10]; /* Master key */
char strng[80]; /* Temp. storage string for conversion */
int pg; /* Page number */
char title[80]; /* Story title */
int nauths; /* Number of authors */
char authky[20]; /* Author key */
char authrc[30]; /* Author's name record */
char temprc[80]; /* Temporary record */
int nkeys; /* Number of keys */
char keywd[20]; /* Keyword */
int i; /* Increment */
int j; /* Increment */
FILE *difile; /* Dictionary input file */

/* ************************************************************ */
/* MAIN ROUTINE FOLLOWS */
/* ************************************************************ */
main ()
{

/*
** Open all the ZSAM index and data files.
*/

zopenk("MINDEX.KEY",MASTER_KEY); /* Master index */
zopend("TITLES.DAT",TITLE_DAT); /* Titles data file */

/* NOTE: The KEYWORDS files are what I called the TOPICS files in
** the article. I changed it in the article so novice readers
** wouldn't get confused between "keys" and "keywords". */
zopenk("KEYWORDS.KEY",KEYWORDS_KEY); /* Keywords index */
zopend("KEYWORDS.DAT",KEYWORDS_DAT); /* Data file */

zopenk("AUTHOR.KEY",AUTHMAST_KEY); /* Author index */
zopend("AUTHOR.DAT",AUTHMAST_DAT); /* Data file */

zopenk("AUTHNAM.KEY",AUTHNAME_KEY); /* Author's name index */
zopend("AUTHNAM.DAT",AUTHNAME_DAT); /* Author's name data file */

/*
** Open the input file.
*/

printf("Enter data input filename:");
scanf("%s",difname);
if ((difile=fopen(difname,"r"))==NULL)
{ printf("*ERROR OPENING INPUT FILE-ABORTING*\n");
closeall();
exit(0);
}

/*
** MAIN LOOP -
** Read the issue date.
*/
fgets(mastkey,10,difile);

do {
/*
** Read page number.
*/
fgets(strng,10,difile);
sscanf(strng,"%d",&pg);

/*
** Build the master key. Notice that you have to
** flip the bytes for the page number so that the high
** byte comes first. This ensures that the keys will be
** stored in proper sorting order in the file.
*/
mastkey[4]=(unsigned char)(pg>>8);
mastkey[5]=(unsigned char)(pg & 255);
mastkey[6]='\000';
/*
** See if the key already exists, if it does, increment the
** last byte of mastkey[] and try again. Ultimately, we'll
** hit upon a unique key for this entry.
*/
while(zreadkr(MASTER_KEY,TITLE_DAT,mastkey,title)
== 0)
++mastkey[6];
/*
** We now have a unique key in mastkey[] - read in and
** attach title.
*/
for (i=0;i<81;++i) title[i]='\000';
fgets(title,82,difile);
zcreatkr(MASTER_KEY,TITLE_DAT,mastkey,title);

/*
** Now read in the names of the authors who wrote the article.

*/
fgets(strng,80,difile);
sscanf(strng,"%d",&nauths);
for (i=0;i { for (j=0;j<17;++j) authky[j]='\000';
fgets(authky,20,difile);
for (j=0;j<21;++j) authrc[j]='\000';
fgets(authrc,22,difile);
/*
** Build list of master keys appended to author key.
*/
if( zreadkr(AUTHMAST_KEY,AUTHMAST_DAT,authky,temprc)
== 0)
zappenddr(AUTHMAST_DAT,mastkey);
else
zcreatkr(AUTHMAST_KEY,AUTHMAST_DAT,authky,mastkey);
/*
** Add author's name to author file.
*/

if(zreadkr(AUTHNAME_KEY,AUTHNAME_DAT,mastkey,temprc)
== 0)
zappenddr(AUTHNAME_DAT,authrc);
else
zcreatkr(AUTHNAME_KEY,AUTHNAME_DAT,mastkey,authrc);
}
/*
** Read in keywords and add to keyword index.
*/
fgets(strng,80,difile);
sscanf(strng,"%d",&nkeys);
for (i=0;i {
for (j=0;j<17;++j) keywd[j]='\000';
fgets(keywd,18,difile);
if (zreadkr(KEYWORDS_KEY,KEYWORDS_DAT,keywd,temprc)
== 0)
zappenddr(KEYWORDS_DAT,mastkey);
else
zcreatkr(KEYWORDS_KEY,KEYWORDS_DAT,keywd,mastkey);
}
/*
** Read next date and continue. A "@" character indicates EOF.
*/
fgets(mastkey,10,difile);
} while (mastkey[0]!='@');
fclose (difile);
closeall();
printf("\nNORMAL TERMINATION...WHEW\n");
exit(0);
}


/*
** This routine closes all the ZSAM files that are open
** for this program.
*/
closeall()
{
zclosek(0); zclosed(0);
zclosek(1); zclosed(1);
zclosek(2); zclosed(2);
zclosek(3); zclosed(3);
return;
}

/****************************************/
/* ZSAM ENTRY POINTS FOLLOW */
/****************************************/

/*
** Open a key file.
** RETURNS: 0 successful, error number if not.
** If return is a -1, look in errno for system error.
** If return is -2, malloc failed - not enough space
** to open the file.
** If return is -3, the file is not a ZSAM file.
*/
int zopenk(fname,fnum)
char *fname; /* File name */
unsigned int fnum; /* File number */
{

char filetype;

zkfno=fnum;

/* Open the file and store the handle */
zkfhand[zkfno]=open(fname,O_RDWR | O_BINARY);
if(zkfhand[zkfno]==-1) return(-1);

/* Allocate space for key file header */
keyhead[zkfno] = (zkey_header *)malloc(sizeof(zkey_header));
if(keyhead[zkfno]==NULL) return(-2);

/* Allocate space for key file buffer */
keybuf[zkfno] = (char *)malloc(KNODESIZE);
if(keybuf[zkfno]==NULL)
{ free((void *)keyhead[zkfno]);
return(-2);
}

/* Read in the header information */
lseek(zkfhand[zkfno],SEEK_SET,0L);
read(zkfhand[zkfno],(void *)keyhead[zkfno],KHEADSIZE);
filetype = keyhead[zkfno]->kftype;
if((filetype!='K')&&(filetype!='O'))
{ close(zkfhand[zkfno]);
free((void *)keyhead[zkfno]);
return(-3);
}

/* All went well */
keyhead[zkfno]->ackysc=0; /* Nothing in buffer yet */
zrewindk(zkfno); /* Rewind the file */
return(0);
}


/*
** Open a data file.
** File number is assumed to be in zdfno.
** RETURNS: 0 successful, error number if not.
** If return is a -1, look in errno for system error.
** If return is -2, malloc failed - not enough space
** to open the file.
** If return is -3, the file is not a ZSAM file.
*/
int zopend(fname,fnum)
char *fname; /* File name */
unsigned int fnum; /* Data file number */
{

char filetype;
int dfbsize; /* Data file buffer size */

zdfno = fnum;

/* Open the file and store the handle */
zdfhand[zdfno]=open(fname,O_RDWR | O_BINARY);
if(zdfhand[zdfno]==-1) return(-1);

/* Allocate space for key file header */
dathead[zdfno] = (zdat_header *)malloc(sizeof(zdat_header));
if(dathead[zdfno]==NULL) return(-2);

/* Read in the header information */
lseek(zdfhand[zdfno],SEEK_SET,0L);
read(zdfhand[zdfno],(void *)dathead[zdfno],DHEADSIZE);
filetype = dathead[zkfno]->dftype;
if((filetype!='S')&&(filetype!='C'))
{ close(zdfhand[zdfno]);
free((void *)dathead[zdfno]);
return(-3);
}

/* Allocate space for data file buffer */
dfbsize = dathead[zdfno]->reclen;
if(dathead[zdfno]->dftype=='C') dfbsize+=6;
datbuf[zdfno]=(char *)malloc(dfbsize);
if(datbuf[zdfno]==NULL)
{ free((void *)dathead[zdfno]);
close(zdfhand[zdfno]);
return(-2);
}

/* All went well */
return(0);
}


/*
** Close a key file.
*/
int zclosek(fnum)
unsigned int fnum; /* key file number */
{

zkfno=fnum;

/* Write the header information back out */
lseek(zkfhand[zkfno],SEEK_SET,0L);
write(zkfhand[zkfno],(void *)keyhead[zkfno],KHEADSIZE);

/* Close the file */
close(zkfhand[zkfno]);

return(0);
}

/*
** Close a data file.
*/
int zclosed(fnum)
unsigned int fnum; /* Data file number */
{
zdfno=fnum;

/* Write the header information back out */
lseek(zdfhand[zdfno],SEEK_SET,0L);
write(zdfhand[zdfno],(void *)dathead[zdfno],DHEADSIZE);

/* Close the file */
close(zdfhand[zdfno]);

return(0);
}

/*
** Rewind a key file.
** This routine sets the keyfile to its logical start.
** Returns ZSAM error number
*/
int zrewindk(fnum)
unsigned int fnum; /* Key file number */
{
zkfno=fnum;
zsams.funct=0; /* Rewind function */
zsams.keyhd=keyhead[zkfno]; /* Send header info */
return(zsam(&zsams));
}

/*
** Read key record.
** Search the keyfile for ZKEY, copy the associated record into ZREC.
** Returns ZSAM error code.
*/
int zreadkr(kfile,dfile,zkey,zrec)
unsigned int kfile; /* Key file */
unsigned int dfile; /* Data file */
char *zkey; /* Pointer to key string */
char *zrec; /* Pointer to data record */
{
zkfno=kfile;
zdfno=dfile;
zsams.funct = 1; /* Set function code */
zsams.kbuf = keybuf[zkfno]; /* Key file node buffer */
zsams.dbuf = datbuf[zdfno]; /* Data file buffer */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.key = zkey; /* Key string */
zsams.rec = zrec; /* Record string */
return(zsam(&zsams));
}

/*
** Read next keyed record.
** Searches in kfile for the inorder successor of the current
** key. Copies the new key into ZKEY and the associated data record
** into ZREC.
** Returns ZSAM error code.
*/
int zreadnkr(kfile,dfile,zkey,zrec)
unsigned int kfile; /* Key file number */
unsigned int dfile; /* Data file number */
char *zkey; /* Key string */
char *zrec; /* Data record string */
{
zkfno=kfile;
zdfno=dfile;
zsams.funct = 2; /* Set function code */
zsams.kbuf = keybuf[zkfno]; /* Key file node buffer */
zsams.dbuf = datbuf[zdfno]; /* Data file buffer */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.key = zkey; /* Key string */
zsams.rec = zrec; /* Record string */
return(zsam(&zsams));
}

/*
** Read next data record.
** dfile must be a complex data file.
** This routine searches for the next record in the current record
** set and copies that record into ZREC.
** Returns ZSAM error number.
*/
int zreadndr(dfile,zrec)
unsigned int dfile; /* Data file number */
char *zrec; /* Record string */
{
zdfno=dfile;
zsams.funct = 3; /* Set function code */
zsams.dbuf = datbuf[zdfno]; /* Data file buffer */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.rec = zrec; /* Record string */
return(zsam(&zsams));
}

/*
** Create keyed record.
** Adds the key in ZKEY into kfile. Creates a new record in dfile,
** loads that record with ZREC, and attaches it to ZKEY.
*/
int zcreatkr(kfile,dfile,zkey,zrec)
unsigned int kfile; /* Key file number */
unsigned int dfile; /* Data file number */
char *zkey; /* Key string */
char *zrec; /* Data record string */
{
zkfno=kfile;
zdfno=dfile;
zsams.funct = 4; /* Set function code */
zsams.kbuf = keybuf[zkfno]; /* Key file node buffer */
zsams.dbuf = datbuf[zdfno]; /* Data file buffer */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.key = zkey; /* Key string */
zsams.rec = zrec; /* Record string */
return(zsam(&zsams));
}

/*
** Insert key.
** The key in ZKEY is added to kfile. Whatever is the current record
** in dfile is associated with that key. (A new data record is NOT
** created.)
** Returns ZSAM error code.
*/
int zinsertk(kfile,dfile,zkey)
unsigned int kfile; /* Key file number */
unsigned int dfile; /* Data file number */
char *zkey; /* Key string */
{
zkfno=kfile;
zdfno=dfile;
zsams.funct = 5; /* Set function code */
zsams.kbuf = keybuf[zkfno]; /* Key file node buffer */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.key = zkey; /* Key string */
return(zsam(&zsams));
}

/*
** Write data record.
** The contents of ZREC overwrite the contents of dfile's current record.
** Returns ZSAM error code.
*/
zwritedr(dfile,zrec)
unsigned int dfile; /* Data file number */
char *zrec; /* Record string */
{
zdfno=dfile;
zsams.funct = 6; /* Set function code */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.dbuf = datbuf[zdfno];
zsams.rec = zrec; /* Record string */
return(zsam(&zsams));
}

/*
** Append data record.
** dfile must be a complex data file. A new data record is created in
** dfile and is attached to the current record set. The contents of
** ZREC are written into this new record.
** Returns ZSAM error code.
*/
zappenddr(dfile,zrec)
unsigned int dfile; /* Data file number */
char *zrec; /* Record string */
{
zdfno=dfile;
zsams.funct = 7; /* Set function code */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.rec = zrec; /* Record string */
return(zsam(&zsams));
}

/*
** Delete keyed record.
** kfile is searched for ZKEY. If found, ZKEY is deleted and the
** record (or record set) in dfile associated with ZKEY is deleted
** from dfile.
** Returns ZSAM error code.
*/
zdelkr(kfile,dfile,zkey)
unsigned int kfile; /* Key file number */
unsigned int dfile; /* Data file number */
char *zkey; /* Key string */
{
zkfno=kfile;
zdfno=dfile;
zsams.funct = 8; /* Set function code */
zsams.kbuf = keybuf[zkfno]; /* Key file node buffer */
zsams.dbuf = datbuf[zdfno]; /* Data file buffer */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.key = zkey; /* Key string */
return(zsam(&zsams));
}

/*
** Delete key.
** kfile is searched for ZKEY. If ZKEY is found, it is deleted.
**
*/
zdelk(kfile,zkey)
unsigned int kfile; /* Key file number */
char *zkey; /* Key string */
{
zkfno=kfile;
zsams.funct = 9; /* Set function code */
zsams.kbuf = keybuf[zkfno]; /* Key file node buffer */
zsams.keyhd = keyhead[zkfno]; /* Key file header info */
zsams.key = zkey; /* Key string */
return(zsam(&zsams));
}

/*
** Delete data record.
** dfile must be a complex file. The current record in dfile is
** deleted from the record set.
** Returns ZSAM error code.
*/
zdeld(dfile)
unsigned int dfile; /* Data file number */
{
zdfno=dfile;
zsams.funct = 10; /* Set function code */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.dbuf = datbuf[zdfno]; /* Data file record buffer */
return(zsam(&zsams));
}

/*
** Rewind a data record set.
** dfile must be a complex data file. The current record set is
** set to its logical beginning so that a call to zreadndr() will
** return the first record in the set.
*/
zrewindd(dfile)
unsigned int dfile; /* Data file number */
{
zdfno=dfile;
zsams.funct = 11; /* Set function code */
zsams.dathd = dathead[zdfno]; /* Data file header info */
zsams.dbuf = datbuf[zdfno]; /* Data file record buffer */
return(zsam(&zsams));
}

/*
** FOLLOWING ARE THE ROUTINES THAT ZSAM CALLS TO
** DO ITS FILE I/O.
** Note: I've modified these routines so that they do check
** for number of bytes written. This was for my own debug
** information and if you think it slows things down too much
** (cough) you can take the if statements out. -- RG
*/

/*
** zgetks() - Get a keyfile sector.
*/
zgetks(node)
unsigned int node;
{
/* Calculate offset (multiply by 512) */
zoffset = ((long)node) << 9;

lseek(zkfhand[zkfno],zoffset,0);
read(zkfhand[zkfno],keybuf[zkfno],KNODESIZE);

return;
}

/*
** zputks() - Put a keyfile sector.
*/
zputks(node)
unsigned int node;
{
/* Calculate offset */
zoffset = ((long)node) << 9;

lseek(zkfhand[zkfno],zoffset,0);
if(write(zkfhand[zkfno],keybuf[zkfno],KNODESIZE)!=KNODESIZE)
{ printf("Error writing key file: %d",zkfno);
exit(0);
}

return;
}

/*
** zgetdr() - Get a data file record.
*/
zgetdr(recl,offset,recordn,count)
unsigned int recl;
unsigned int offset;
unsigned long recordn;
unsigned int count;
{
/* Calculate true offset */
zoffset = (long)recl * (long)(recordn-1) +
(long)offset + DHEADSIZE;

lseek(zdfhand[zdfno],zoffset,0);
read(zdfhand[zdfno],datbuf[zdfno],count);

return;
}

/*
** zputdr() - Put a data record.
*/

zputdr(recl,offset,recordn,count)
unsigned int recl; /* Record length for this data file */
unsigned int offset; /* Offset into record */
unsigned long recordn; /* Record number */
unsigned int count; /* Number of bytes */
{
/* Calculate true offset */
zoffset = (long)recl * (long)(recordn-1) +
(long)offset + DHEADSIZE;

lseek(zdfhand[zdfno],zoffset,0);
if(write(zdfhand[zdfno],datbuf[zdfno],count)!=count)
{ printf("Error writing data file %d",zdfno);
exit(0);
}

return;
}