v17i040: bplus - B+ Tree Library, Part02/02

Bill Davidsen davidsen at crdos1.crd.ge.com
Sat Mar 16 07:27:13 AEST 1991


Submitted-by:  Bill Davidsen <davidsen at crdos1.crd.ge.com>
Posting-number: Volume 17, Issue 40
Archive-name: bplus/part02

#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file bplus.doc continued
#
CurArch=2
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file bplus.doc"
sed 's/^X//' << 'SHAR_EOF' >> bplus.doc
X
X
X
X         int cdecl find_exact(pe, pix);
X
X              ENTRY *pe;          Pointer to variable of type ENTRY
X              IX_DESC *pix;       Pointer to index file variable
X
X              Description:  The find_exact function searches the index
X              file for the key value contained in pe.key and the data
X              record position stored in pe.recptr.  If an exact match
X              is found for both of these values, the value IX_OK (1)
X              is returned, and the internal index file pointer is set
X              to that position in the index file.  If an exact match
X              is not found, the value IX_FAIL (0) is returned.
X
X
X
X         TAILORING OR CHANGING B-PLUS
X
X              Most applications can use the B-PLUS program as it is
X         distributed by Hunter and Associates without any changes.  It
X         allows multiple, large data files to be indexed in a fast,
X         efficient manner.  However, a description of the values that
X         can be changed to tailor B-PLUS are given in this section.
X
X              An index tree becomes full when no more entries can be
X         added to the tree.  This is the case when adding another
X         entry to the tree would cause the tree to grow larger than
X         its maximum allowed height.  This height depends on the size
X         of the index blocks and the average size of the keys used by
X         the data files.  The minimum capacity of a b-tree index is
X         given by the following formula:
X
X              C = (B / E + 1) * (B / (2 * E)  + 1) ** (H - 1)
X
X         where C is the number of entries in the index file, B is the
X
X                                   Page 8
X
X
X         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
X         -------------------------------------------------------------
X
X
X         block size in bytes, E is the average size of an ENTRY in
X         bytes, and H is the maximum tree height.
X
X              The maximum key size is defined by MAXKEY and is set at
X         100.  The block size is 1024 bytes as defined by IXB_SIZE.
X         Ten bytes are used by pointers so 1014 bytes are used by
X         entries.  The size of an ENTRY is 9 + the key length.
X
X              Thus, if the average key length is 11, an average ENTRY
X         is 20 bytes long and the minimum number of entries that can
X         be contained in a tree of height 4 is:
X
X              C = (1014 / 20 + 1) * (1014 / 40 + 1) ** 3
X                = 945,072
X
X         If the average ENTRY is 40 bytes long, the minimum number of
X         entries that can be contained in a tree of height 4 is
X         67,384.  The corresponding values for a tree of height 3 are
X         35,896 and 4927, respectively.
X
X              The maximum tree height is determined by MAX_LEVELS and
X         is set to eight.  Very little memory space is used by
X         allowing the maximum tree height to be this large.  B-PLUS
X         increases the height of the tree dynamically as required by
X         number of records in the data file.
X
X              If your application does not use long keys and your
X         files are not huge, IXB_SIZE can be changed to 512 bytes with
X         only a slight degradation in performance.
X
X              The root of an open index file is always memory resident
X         as defined by the variable of type IX_DESC.  A dynamic pool
X         of cache buffers is used for other index blocks of the tree.
X         The number of blocks in the pool is defined by NUM_BUFS with
X         a default value of 8.  Each memory block is sizeof(IXB_SIZE)
X         + 8 bytes in length so approximately 8K of memory is used for
X         cache storage of index blocks.  If the number of index files
X         that are open simultaneously is larger than 4, you may want
X         to increase NUM_BUFS.  If the usage of memory is critical,
X         the number of buffers can be decreased.  However, NUM_BUFS
X         must be at least 2.  In general, the speed of file access can
X         be expected to improve if the number of buffers is increased
X         since more of the index file is memory resident.
X
X              Because some indices are always memory resident, and
X         because the DOS Operating System requires it, it is very
X         important that all open index files be closed before an
X         application program terminates.
X
X              As stated earlier, the B-PLUS program has been tested
X
X                                   Page 9
X
X
X         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
X         -------------------------------------------------------------
X
X
X         using Microsoft's Optimizing C Compilers, Versions 4, 4.5 and
X         5.0, and Borland's Turbo C, Version 1.0.  However, standard K
X         & R programming guidelines are followed so B-PLUS should be
X         able to be used with other C Compilers with little
X         modification.  Since B-PLUS is non-recursive, the usage of
X         stack space does not change dynamically.  It is recommend
X         that the B-PLUS program be complied without stack checking.
X         For Microsoft C, the /Ox option can be used to maximize speed
X         and minimize code size.  For Turbo C, B-PLUS can be complied
X         with maximum optimization to minimize the object size and
X         improve performance.
X
X
X         ACKNOWLEDGMENTS AND REFERENCES
X
X              The following reference materials were used and helpful
X         in writing the B-PLUS program:
X
X              Wirth, Niklaus:
X                     Algorithms + Data Structures = Programs
X                     Prentice Hall (1976)
X
X              Hunt, William James:
X                     The C Toolbox
X                     (Serious C Programming for the IBM PC)
X                     Addison-Wesley (1985)
X
X
X              Wirth's book is a standard reference source for binary
X         trees and data structures.  Hunt's C Toolbox contains useful
X         C programming concepts with carefully constructed programming
X         examples.
X
X
X         USING THE BPLUS ROUTINES
X
X              The BPLUS.C routines must be compiled and the object
X         file (BPLUS.OBJ) loaded with programs that use the B_PLUS
X         toolkit.  Several sample C programs have been included which
X         illustrate how to use the BPLUS Toolkit.  These programs
X         should be compiled and run to make sure your copy of the
X         program is correct.
X
X
X         A SPECIAL NOTE REGARDING MICROSOFT C COMPILERS
X
X              The Microsoft C library routines are different for
X         Version 4.0 and for Version 5.0 and Quick C.  In particular,
X         the memcpy routine in Version 5.0 does not check that
X         overlapping bytes are copied correctly.  Consequently, the
X
X                                  Page 10
X
X
X         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
X         -------------------------------------------------------------
X
X
X         memmove routine must be used for Version 5.0 and for Quick C.
X         A macro is included in BLUS.C which makes this substitution.
X         This macro MUST be used (remove the comment delimiters) for
X         these versions of the Microsoft compilers.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X                                  Page 11
X\032
SHAR_EOF
echo "File bplus.doc is complete"
chmod 0644 bplus.doc || echo "restore of bplus.doc fails"
echo "x - extracting bplus.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > bplus.h &&
X
X/*  bplus.h - data structures and constants  */
X
X
X/* the next two lines delete the 'pascal' and 'cdecl' keywords
X   to make the source compile on an ANSI compiler.
X*/
X#ifndef	MSC		/* not Microsoft C */
X#define cdecl
X#define pascal
X#endif			/* MSC */
X
X/* the following checks are to define things frequently not in
X   UNIX compilers, since they are recent ANSI additions.
X*/
X#ifndef SEEK_SET
X#define SEEK_SET	0
X#endif
X#ifndef O_BINARY
X#define O_BINARY	0
X#endif
X
X#if	defined(ANSI_C) | defined(MSC) | defined(M_XENIX)
X#define Param(x) x
X#else
X#define Param(x) ()
X#endif	/* ANSI or PCC style decls */
X
X#define IX_OK       1
X#define IX_FAIL     0
X#define EOIX       (-2)
X#define MAXKEY      100
X#define NUM_BUFS    8
X#define MAX_LEVELS  8
X#define IXB_SIZE    1024
X#define IXB_SPACE  (IXB_SIZE - sizeof(short) - sizeof(long) * 2)
X
Xtypedef long RECPOS;
X
Xtypedef struct                    /*  entry structure in index        */
X  {  RECPOS   idxptr;             /*  points to lower index level     */
X     RECPOS   recptr;             /*  points to data record           */
X     char     key[MAXKEY];        /*  start of record key             */
X  }  ENTRY;
X
Xtypedef struct                    /*  index record format             */
X  {  RECPOS   brec;               /*  position in index file          */
X                                  /*  or location of next free block  */
X     short    bend;               /*  first unused block location     */
X     RECPOS   p0;                 /*  points to next level            */
X     char     entries[IXB_SPACE]; /*  here are the key entries        */
X  }  BLOCK;
X
Xtypedef struct                    /*  disk file info                  */
X  {  RECPOS   ff;                 /*  location of first free block    */
X     short    nl;                 /*  number of index levels          */
X  }  IX_DISK;
X
Xtypedef struct                    /*  memory buffer pool of indx blks */
X  {  short    dirty;              /*  true if changed                 */
X     short    handle;             /*  index file handle               */
X     short    count;              /*  number of times referenced      */
X     BLOCK    mb;
X  }  MEMBLOCK;
X
Xtypedef struct
X  {  MEMBLOCK     cache [ NUM_BUFS ];
X  }  IX_BUFFER;
X
Xtypedef struct                    /*  in-memory index descriptor      */
X  {  short    ixfile;
X     short    level;              /*  level in btree                  */
X     short    duplicate;          /*  no duplicate keys if 0          */
X     struct
X       {  RECPOS    cblock;       /*  position in index file          */
X          short     coffset;      /*  current offset within block     */
X       }  pos [ MAX_LEVELS ];
X     BLOCK    root;               /*  root index record               */
X     IX_DISK  dx;
X  }  IX_DESC;
X
X/* a few system procedure types here */
Xextern long filelength(), lseek(), tell();
Xextern char *mktemp();
Xextern int read(), write(), open(), close();
Xextern void exit();
X
X/* ================ external interface ================ */
Xint cdecl open_index Param((char *,IX_DESC *, int));
Xint cdecl close_index Param((IX_DESC *));
Xint cdecl make_index Param((char *,IX_DESC *, int));
Xint cdecl first_key Param((IX_DESC *));
Xint cdecl last_key Param((IX_DESC *));
Xint cdecl next_key Param((ENTRY *, IX_DESC *));
Xint cdecl prev_key Param((ENTRY *, IX_DESC *));
Xint cdecl find_key Param((ENTRY *, IX_DESC *));
Xint cdecl add_key Param((ENTRY *, IX_DESC *));
Xint cdecl locate_key Param((ENTRY *, IX_DESC *));
Xint cdecl delete_key Param((ENTRY *, IX_DESC *));
Xint cdecl find_exact Param((ENTRY *, IX_DESC *));
Xint cdecl find_1stkey Param((ENTRY *, IX_DESC *));
Xvoid clearkey Param((ENTRY *));
SHAR_EOF
chmod 0644 bplus.h || echo "restore of bplus.h fails"
echo "x - extracting makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > makefile &&
X# makefile for UNIX bplus test
X
X# Bplus routines, utility routines, and the whole library
XPLUSLIB		= bplus.o find1stkey.o
XUTILLIB		= filelen.o memmove.o
XLIB		= $(PLUSLIB) $(UTILLIB)
XLIBSRC		= bplus.c find1stkey.c filelen.c memmove.c
XDOCFILES	= read.me bplus.doc
X
XTESTS		= utest3 utest4 zoodb
XTESTOBJ		= utest3.o utest4.o zoodb.o
XTESTSRC		= utest3.c utest4.c s.zoodb.c
X
XDEMOSRC		= ndb.c lookup.c names.c
X
X# C flags, load flags, misc (shared) flags
XCFLAGS		= -O
XLFLAGS		=
XMFLAGS		= 
XCC		= cc $(CFLAGS) ${MFLAGS}
X
X# archive for distribution
XBPLUSARC	= bplus11a.arc
X
X# info to install the libraries
XLIBX286		= /lib
XLIBX386		= /lib/386
XLIBDOS		= /usr/lib/dos
X
Xall: $(TESTS)
X
X$(TESTS): bplus.a $$@.o
X	$(CC) $(LFLAGS) -o $@ $@.o bplus.a
X
X$(PLUSLIB):	bplus.h
X$(TESTOBJ):	bplus.h
X
Xbplus.a: $(LIB)
X	ar rv bplus.a $?
X	ranlib bplus.a
X
X# special section to make libraries under Xenix386, for Xenix286 and MS-DOS
Xextlib:		$(LIBSRC) bplus.h
X	@echo "Making x286 small"
X	cc -c -O -M2 $(LIBSRC)
X	ar rv Sbplus286.a $(LIB)
X	ranlib Sbplus286.a
X	@echo "Making x286 large"
X	cc -c -O -M2l $(LIBSRC)
X	ar rv Lbplus286.a $(LIB)
X	ranlib Lbplus286.a
X	@echo "Making DOS small"
X	cc -c -O -M2 -dos $(LIBSRC)
X	ar rv SbplusDOS.a $(LIB)
X	ranlib SbplusDOS.a
X	@echo "Making DOS large"
X	cc -c -O -M2l -dos $(LIBSRC)
X	ar rv LbplusDOS.a $(LIB)
X	ranlib LbplusDOS.a
X	@echo "Making 386 version"
X	cc -c -O $(LIBSRC)
X	ar rv bplus.a $(LIB)
X	touch extlib
X
X# install the special libraries - run su LIBOWNER
Xlibinstall: extlib
X	cp Slib286.a $(LIBX286)/Slibbplus.a
X	cp Llib286.a $(LIBX286)/Llibbplus.a
X	cp bplus.a $(LIBX386)/Slibbplus.a
X	cp SlibDOS.a $(LIBDOS)/Slibbplus.a
X	cp LlibDOS.a $(LIBDOS)/Llibbplus.a
X
X.SUFFIXES:	.exe
X
X# special inference rules, DOS and SCCS
X.o.exe:
X	$(CC) -o $@ -dos $< bplus.a
X.c~.o:
X	get -s $?
X	$(CC) -c $*.c && rm -f $*.c
X.c.o:
X	$(CC) -c $*.c
X
XMISCSAVE	= $(DOCFILES) bplus.h makefile
XSAVELIST	= $(LIBSRC) $(MISCSAVE) $(DEMOSRC)
Xbackup:		bplus.zoo
Xbplus.zoo:	$(SAVELIST) s.bplus.c
X	zoo aunPP bplus $?
X
Xbplusarc:	$(BPLUSARC)
X
X$(BPLUSARC):	$(SAVELIST)
X	rm -f $(BPLUSARC)
X	arc a bplus $?
X
Xshar:		bplus.shar
Xbplus.shar:	$(SAVELIST)
X	$${SHAR:-shar} $(SAVELIST) > bplus.shar
X
X# cleanup after backup
Xclean:		backup
X	rm $(SAVELIST)
X
X# phone number database software
X
XPDBX		= ndb lookup
Xpdbx:		$(PDBX) lookup.exe
X
X$(PDBX):	bplus.a $$@.o
X	cc $(MFLAGS) $(LFLAGS) -o $@ $@.o bplus.a
X
Xlookup.exe:	lookup.c
X	$(CC) $(LFLAGS) -dos -o lookup.exe lookup.c bplus.a
X
Xndb.o lookup.o:	bplus.h
SHAR_EOF
chmod 0644 makefile || echo "restore of makefile fails"
echo "x - extracting ndb.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ndb.c &&
X/*****************************************************************
X |  ndb - build Name DataBase
X |----------------------------------------------------------------
X |  takes data from a raw listing of names, phone numbers, room
X |  numbers, etc and builds an index by name. Name is in upper
X |  case, in the first 26 columns. The index points into the
X |  original text file.
X ****************************************************************/
X 
X#include <stdio.h>
X#include "bplus.h"
X#define EOS     ((unsigned char) 0)
X
XIX_DESC namesfile;
XENTRY index;
XFILE *namedata, *fopen();
X
Xmain() {
X    int status, n, nnames;
X    int names_count = 0, keys_count = 0;
X    long ftell();
X    char namebuf[132], names[6][30];
X
X    status = make_index("phdata.idx", &namesfile, 1);
X    if (status != IX_OK) {
X        printf("Can't create 'phdata.idx' file\n");
X        exit(1);
X    }
X    namedata = fopen("phdata", "r");
X    if (namedata == NULL) {
X        printf("Can't find 'phdata' file\n");
X        exit(1);
X    }
X
X    /* read loop */
X    while (index.recptr = ftell(namedata),
X        fgets(namebuf, 132, namedata) != NULL)
X    {        
X        namebuf[26] = EOS;
X        ++names_count;
X        nnames = sscanf(namebuf, "%s%s%s%s%s%s",
X            names[0], names[1], names[2],
X            names[3], names[4], names[5]);
X        for (n=0; n<nnames; ++n) {
X            if (strlen(names[n]) < 2) continue;
X            ++keys_count;
X            clearkey(&index);
X            strcpy(index.key, names[n]);
X            status = add_key(&index, &namesfile);
X            if (status != IX_OK) {
X                printf("Bad status on add of key '%s'\n", names[n]);
X                close_index(&namesfile);
X                exit(1);
X            }
X        }
X    }
X
X    /* wrapup */
X    printf("Build complete, %d names, %d keys\n",
X        names_count, keys_count);
X    close_index(&namesfile);
X    fclose(namedata);
X}
SHAR_EOF
chmod 0644 ndb.c || echo "restore of ndb.c fails"
echo "x - extracting lookup.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lookup.c &&
X/*****************************************************************
X |  lookup - lookup a name in the names data base
X |----------------------------------------------------------------
X |  finds all occurrences of the name(s) on the command line and
X |  displays the matching records from the original text file.
X |  Locates records with name fields starting with the string
X |  argument. "lookup j" finds all records with a first or last
X |  name starting with j.
X ****************************************************************/
X
X#include <stdio.h>
X#include <ctype.h>
X#include "bplus.h"
X
XIX_DESC namesfile;
XENTRY index;
XFILE *namedata, *fopen();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int n, status, keylen;
X    char uckey[MAXKEY];
X    int ch, chindex;
X
X    status = open_index("phdata.idx", &namesfile, 1);
X    namedata = fopen("phdata", "r");
X    
X    for (n = 1; n < argc; ++n) {
X        for (chindex = 0; ch = argv[n][chindex]; ++chindex) {
X            if (islower(ch)) ch = toupper(ch);
X            uckey[chindex] = ch;
X        }
X        
X        clearkey(&index);
X        strcpy(index.key, uckey);
X        status = locate_key(&index, &namesfile);
X        if (status == EOIX) continue;
X        keylen = strlen(uckey);
X        
X        dumprec(index.recptr);
X        while (next_key(&index, &namesfile) == IX_OK &&
X            (strncmp(index.key, uckey, keylen) == 0))
X        {
X            dumprec(index.recptr);
X        }
X    }
X
X    close_index(&namesfile);
X}
X
Xdumprec(seekloc)
Xlong seekloc;
X{
X    char line[132];
X    
X    fseek(namedata, seekloc, 0);
X    fgets(line, 132, namedata);
X    fputs(line, stdout);
X}
SHAR_EOF
chmod 0644 lookup.c || echo "restore of lookup.c fails"
echo "x - extracting names.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > names.c &&
X/*******************************************************************/
X/*                              NAMES.C                             */
X/*                                                                  */
X/* This example shows how easy it is to write a program for an      */
X/* online address book using the B-PLUS file indexing toolkit.      */
X/* The program creates a file of names, addresses, and telephone    */
X/* numbers.  A record is displayed on the screen by entering part   */
X/* or all of the name.  Although the program is usefully as written */
X/* it has purposely been kept simple.  You may want to add new      */
X/* features to the progran.                                         */
X/*                                                                  */
X/********************************************************************/
X
X
X#include <stdio.h>
X#include <string.h>
X#include "bplus.h"
X
X
Xtypedef struct              /* Here is the address record definition */
X  {
X     char lastname[16];     /* last name           */
X     char firstname[16];    /* first name          */
X     char address1[31];     /* first address line  */
X     char address2[31];     /* second address line */
X     char city[21];         /* the city            */
X     char state[3];         /* the state           */
X     char zipcode[6];       /* postal zip code     */
X     char telephone[14];    /* telephone number    */
X  }  ADDRESS;
X
X
XIX_DESC  nameindex;             /* index file variable  */
XFILE     *namefile;             /* data file pointer    */
XADDRESS  person;                /* data record variable */
X
X
Xvoid openfiles(void);
Xvoid closefiles(void);
Xint addrecord(void);
Xvoid getstring(char*, int);
Xvoid newaddress(void);
Xvoid printname(ENTRY*);
Xvoid getname(void);
Xvoid nextname(void);
Xvoid listnames(void);
X
X
Xvoid openfiles()
X  /* If the file NAMES.DAT already exist, open the index and data */
X  /* file.  Otherwise, these files are created.                   */
X  {
X    if ((namefile = fopen("names.dat","r+")) != NULL)
X      open_index("names.idx", &nameindex, 1);      /* open index file  */
X    else
X    {
X      namefile = fopen("names.dat","w+");          /* create data file */
X      if (namefile == NULL)
X        {
X          printf("Unable to open namefile\n");
X          exit(1);
X        }
X      make_index("names.idx", &nameindex, 1);   /* creat index file     */
X    }                                           /* allow duplicate keys */
X  } /* openfiles */
X
X
Xvoid closefiles()
X  /* close all files and exit */
X  {
X    fclose(namefile);
X    close_index(&nameindex);
X    exit(0);
X  } /* closefiles */
X
X
Xint addrecord()
X  /* add a new address to the data file - add index to index file */
X  {
X    ENTRY ee;
X    char name[32];
X    int ret;
X    ret = fseek(namefile, 0L, SEEK_END);      /* seek to end of datafile  */
X    if (ret == 0)
X      {
X        strcpy(ee.key, person.lastname);      /* key is last name followed */
X        strcat(ee.key, person.firstname);     /* first name.  Capitalize   */
X        strupr(ee.key);                       /*    and copy to ee.key.    */
X        ee.recptr = ftell(namefile);          /* get position in datafile  */
X        if (ee.recptr != -1L)
X          {
X            if (add_key(&ee, &nameindex) == IX_OK)     /* add key to index */
X              {
X                fwrite(&person,sizeof(person),1,namefile);  /* add address */
X                return (IX_OK);
X              }
X          }
X      }
X    else printf("Seek error - data file");
X    return (IX_FAIL);
X  } /* addrecord */
X
X
Xvoid getstring(mes, length)
X  char *mes;
X  int length;
X  /* input a string and check that it is not too long   */
X  {
X    char message[80];
X    gets(message);
X    if (strlen(message) > length) message[length] = '\0';
X    strcpy(mes,message);
X  } /* getstring */
X
X
Xvoid newaddress()
X  /* add new address records */
X  {
X    while (1)
X     {
X       printf("\n\nLast Name      : ");
X       getstring(person.lastname,15);
X       if ( strlen(person.lastname) > 0)       /* quit if no last name */
X         {
X           printf("First Name     : ");
X           getstring(person.firstname,15);
X           printf("Address Line 1 : ");
X           getstring(person.address1,30);
X           printf("Address Line 2 : ");
X           getstring(person.address2,30);
X           printf("City           : ");
X           getstring(person.city,20);
X           printf("State          : ");
X           getstring(person.state,2);
X           printf("Zip Code       : ");
X           getstring(person.zipcode,5);
X           printf("Telephone      : ");
X           getstring(person.telephone,13);
X           addrecord();                     /* update data and index files */
X           printf("\n");
X         }
X         else return ;
X     }
X  } /* newaddress */
X
X
Xvoid printname(e)
X  ENTRY *e;
X  /* retrieve a data record and print it on the screen */
X  {
X    int ret;
X
X    /* seek to the record address stored in ENTRY e->recptr */
X    ret = fseek(namefile, e->recptr, SEEK_SET);
X
X    if (ret == 0)     /* if OK read the record and display */
X      {
X        fread(&person,sizeof(person),1,namefile);
X        printf("\n\n            %s %s" , person.firstname,person.lastname);
X        printf("\n            %s", person.address1);
X        if (strlen(person.address2) > 0)
X           printf("\n            %s", person.address2);
X        printf("\n            %s, %s  %s", person.city,person.state,person.zipcode);
X        printf("\n            %s\n", person.telephone);
X      }
X    else printf("Seek error - data file");
X  } /* printname */
X
X
Xvoid getname()
X  /* Get an address record by entering part or all of name */
X  /* Enter last name first then first name with no spaces  */
X  {
X    ENTRY ee;
X    printf("\n\nEnter name: ");
X    gets(ee.key);
X
X    /* make all upper case letters and copy to ee.key */	
X    strupr(ee.key);
X
X    /* use locate_key instead of find_key so an exact match not required */
X    if (locate_key(&ee, &nameindex) != EOIX) printname(&ee);
X    else printf("No key this large in index file\n");
X  } /* getname */
X
X
Xvoid nextname()
X  /* display the next address in the address file */
X  {
X    ENTRY ee;
X    if (next_key(&ee, &nameindex) == IX_OK) printname(&ee);
X    else printf("\nEnd of index file\n");
X  } /* nextname */
X
X
Xvoid listnames()
X  /* list all the names in the address file */
X  {
X    ENTRY ee;
X    first_key(&nameindex);
X    while (next_key(&ee, &nameindex) == IX_OK) printname(&ee);
X  } /* listnames */
X
Xmain()
X  /* Here is the main program loop */
X  {
X    char cmd;
X    int  done;
X    done = 0;
X    openfiles();
X    do
X     {
X       printf("\nCommand: A (Add Name), F (Find), N (Next), L (List), Q (Quit): ");
X       cmd = toupper(getche());
X       switch (cmd)
X        {
X          case 'A': newaddress(); break;   /* add a name to address file   */
X          case 'F': getname(); break;      /* find an address              */
X          case 'N': nextname(); break;     /* display next address in file */
X          case 'L': listnames(); break;    /* display all addresses        */
X          case 'Q': closefiles();          /* quit and close files         */
X        }
X      }
X    while (!done);
X  } /* main */
X
X\032
SHAR_EOF
chmod 0644 names.c || echo "restore of names.c fails"
rm -f s2_seq_.tmp
echo "You have unpacked the last part"
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.



More information about the Comp.sources.misc mailing list