home *** CD-ROM | disk | FTP | other *** search
-
-
- /*
- GARBAGEC.C Function PbGarbageCollect: eliminates the blank areas of a
- phonebook file.
-
- This function reduces to 0 the unused bytes in a phonebook.
-
- INPUT: Name of phonebook file to process.
-
- OUTPUT: If successful, returns 1. Otherwise sets Pberrno and returns 0.
- */
-
- #include <stdlib.h>
- #include <malloc.h>
- #include <stdio.h>
- #include <io.h>
- #include <phonebk.h>
- #include <ctype.h>
- #include <dos.h>
-
- int pascal PbGarbageCollect(char *PbFilename)
- {
- int retval = 0; /* default (failed) return value */
- PB *SourcePb = NULL,
- *NewPb = NULL;
- long PbSize, unused, avail;
- int filenum;
- LONGWORD clusters,
- sectors,
- bytes, /* need these temp's to prevent integer overflow */
- next_offset;
-
- struct diskfree_t diskspace; /* for call to _dos_getdiskfree */
- unsigned drive; /* for call do _dos_getdiskfree */
-
- int i, j; /* loop counters */
- size_t red, writ; /* returns for fread() and fwrite() */
-
- char *temp_name = NULL; /* tmpnam() allocates space for this */
-
- LONGWORD *offsets = NULL; /* will hold 1000 bytes at a time of offset array */
- fpos_t source_pos, /* for pushing and popping fpos in sourcePb */
- o_dest_pos, /* for pushing and popping fpos in destPb's offsets */
- e_dest_pos; /* for pushing and popping fpos in destPb's entries */
-
- WORD entry_size,
- next_entry_size;
- char *entry_buffer = NULL;
-
- Pberrno = 0; /* Initially, always reset */
-
- /* First, check params */
- if (PbFilename == NULL) {
- Pberrno = INVALIDPARAMETER;
- return(NULL);
- }
-
- /* Open the named phonebook */
- SourcePb = PbOpenPhonebook(NULL, PbFilename);
- if (!SourcePb) {
- return(0); /* PbOpenPhonebook has set Pberrno */
- }
-
- /* We need to know: size of the phonebook to clean,
- # of unused (garbage) bytes in that phonebook,
- # of bytes available on disk,
- # of bytes as a safety margin. */
-
- filenum = fileno(SourcePb->fp);
- PbSize = filelength(filenum);
- if (PbSize == -1L) {
- goto closeup;
- }
- unused = SourcePb->header.FreeBytes;
-
- /* Determine the drive number for call to _dos_getdiskfree */
- if (PbFilename[1] == ':') {
- PbFilename[0] = toupper(PbFilename[0]);
- drive = PbFilename[0] - 'A' + 1;
- }
- else drive = 0;
-
- if (_dos_getdiskfree(drive, &diskspace)) {
- goto closeup;
- }
- avail = (clusters = diskspace.avail_clusters) *
- (sectors = diskspace.sectors_per_cluster) *
- (bytes = diskspace.bytes_per_sector);
-
- /* If not enough diskspace for operation, set Pberrno and get out */
- if (PbSize - unused > avail - DISKSPACEMARGIN) {
- Pberrno = OUTOFDISKSPACE;
- goto closeup;
- }
-
- /* Create a new phonebook with a temporary name, and copy entries into it */
- temp_name = tmpnam(NULL);
- NewPb = PbCreatePhonebook(NULL, temp_name);
- if (!NewPb) {
- goto closeup; /* PbCreatePhonebook has set Pberrno */
- }
- if (fseek(SourcePb->fp, 160L, SEEK_SET)) {
- Pberrno = FSEEKERROR;
- goto closeup;
- }
- if (fseek(NewPb->fp, 160L, SEEK_SET)) {
- Pberrno = FSEEKERROR;
- goto closeup;
- }
- if (fgetpos(NewPb->fp, &o_dest_pos)) { /* save position in offset array */
- goto closeup;
- }
- if (fseek(NewPb->fp, 4160L, SEEK_SET)) { /* get ready for copying 1st entry */
- Pberrno = FSEEKERROR;
- goto closeup;
- }
- if (fgetpos(NewPb->fp, &e_dest_pos)) { /* save position in entry section */
- goto closeup;
- }
- next_offset = 4160L; /* offset of next entry that goes in */
- entry_buffer = (char *)malloc(entry_size = sizeof(PBEFIXED));
- if (!entry_buffer) {
- Pberrno = OUTOFMEM;
- goto closeup;
- }
- offsets = (LONGWORD *)malloc(1000);
- if (!offsets) {
- Pberrno = OUTOFMEM;
- goto closeup;
- }
-
- /* Read and process the 4K offset array, 1K at a time */
- for (i=0; i<4; i++) {
- red = fread(offsets, sizeof(LONGWORD), 250, SourcePb->fp);
- if (red != 250) {
- Pberrno = CANTREAD;
- goto closeup;
- }
- if (fgetpos(SourcePb->fp, &source_pos)) { /* save pos in source */
- goto closeup;
- }
- if (fsetpos(NewPb->fp, &e_dest_pos)) { /* go to last position in entries*/
- goto closeup;
- }
-
- /* For each 1/4 of the offset array, scan it for non-NULL entries */
- for (j=0; j<250; j++) {
- if (offsets[j]) {
- NewPb->header.entries++;
-
- /* Get the entry in two reads: 1st, the fixed part, then the rest */
- if (fseek(SourcePb->fp, offsets[j], SEEK_SET)) {
- Pberrno = FSEEKERROR;
- goto closeup;
- }
- red = fread(entry_buffer, 1, sizeof(PBEFIXED), SourcePb->fp);
- if (red != sizeof(PBEFIXED)) {
- Pberrno = CANTREAD;
- goto closeup;
- }
-
- /* Reallocate the entry_buffer only if new entry is larger than last */
- next_entry_size = ((PBEFIXED *)entry_buffer)->length;
- if (entry_size < next_entry_size) {
- entry_buffer = (char *)realloc(entry_buffer, next_entry_size);
- if (!entry_buffer) {
- Pberrno = OUTOFMEM;
- goto closeup;
- }
- }
- entry_size = next_entry_size;
- red = fread(entry_buffer + sizeof(PBEFIXED), 1,
- entry_size - sizeof(PBEFIXED),
- SourcePb->fp);
- if (red != entry_size - sizeof(PBEFIXED)) {
- Pberrno = CANTREAD;
- goto closeup;
- }
-
- /* Now copy that entry to end of new phonebook, setting the new offset*/
- offsets[j] = next_offset;
- next_offset += entry_size;
- writ = fwrite(entry_buffer, 1, entry_size, NewPb->fp);
- if (writ != entry_size) {
- Pberrno = CANTWRITE;
- goto closeup;
- }
- } /* end: if (offsets[j]) */
- } /* end: for all 250 offsets in this 1/4 */
-
- if (fgetpos(NewPb->fp, &e_dest_pos)) { /* save position for entries */
- goto closeup;
- }
- if (fsetpos(NewPb->fp, &o_dest_pos)) { /* go to last pos in offsets */
- goto closeup;
- }
-
- /* Write the updated 1/4 section of the offset array */
- writ = fwrite(offsets, sizeof(LONGWORD), 250, NewPb->fp);
- if (writ != 250) {
- Pberrno = CANTWRITE;
- goto closeup;
- }
- if (fgetpos(NewPb->fp, &o_dest_pos)) { /* save pos in offsets */
- goto closeup;
- }
- if (fsetpos(SourcePb->fp, &source_pos)) { /* return to pos for entries */
- goto closeup;
- }
- } /* end of 4 reads of 1K each */
-
- /* If # of records in new phonebook don't match # of records in old, error */
- if (NewPb->header.entries != SourcePb->header.entries) {
- Pberrno = INCONSISTENTPBH; /* this is a warning only */
- }
-
- /* One more detail: have to copy the header of the source Pb onto the copy */
- rewind(NewPb->fp);
- SourcePb->header.FreeBytes = 0; /* the only field different */
- writ = fwrite(&SourcePb->header, 1, sizeof(PBH), NewPb->fp);
- if (writ != sizeof(PBH)) {
- Pberrno = CANTWRITE;
- goto closeup;
- }
-
- /* If we've reached here, all is well: out with the old, in with the new! */
-
- /* First, close up the files and null out the phonebook ptrs */
- if (fclose(SourcePb->fp)) {
- Pberrno = CANTCLOSE;
- }
- free(SourcePb);
- SourcePb = NULL;
- if (fclose(NewPb->fp)) {
- Pberrno = CANTCLOSE;
- }
- free(NewPb);
- NewPb = NULL;
-
- /* Finally, delete the old and rename the new to the old name */
- if (remove(PbFilename)) {
- goto closeup;
- }
- if (rename(temp_name, PbFilename)) {
- goto closeup;
- }
- retval = 1; /* Success! */
- closeup:
- if (temp_name) {
- free(temp_name);
- }
- if (entry_buffer) {
- free(entry_buffer);
- }
- if (offsets) {
- free(offsets);
- }
- if (SourcePb) {
- if (fclose(SourcePb->fp)) {
- Pberrno = CANTCLOSE;
- }
- free(SourcePb);
- }
- if (NewPb) {
- if (fclose(NewPb->fp)) {
- Pberrno = CANTCLOSE;
- }
- free(NewPb);
- }
- return(retval);
- }