
/*-------------------------------------------------------------------------*
 *                                                                         *
 * Attempts to rebuild Index file from data file.                          *
 *                                                                         *
 * Compile/link under Manx C 5.0d                                          *
 *   cc -hi allprecomp -pp -wnuq -o rebuildrmfindex.o rebuildrmfindex.c    *
 *   ln -o rebuildrmfindex rebuildrmfindex.o -lc                           *
 *                                                                         *
 * Compile/link for Lattice 5.10                                           *
 *     LC -L -Hinclude:allprecomp.q rebuildrmfindex                        *
 *           (pre-compiled header file)                                    *
 *                                                                         *
 *-------------------------------------------------------------------------*/
 
#include "avl.structs.h"

int rebuild_index( char *datafile, char *newindex );

main( int argc, char *argv[] )
{
    char *oldd,*newi;
    long oldnamelen;
    int noerrs;

    if( argc < 2 ) {
        printf("\n Syntax is %s 'name of rmf file'\n",argv[0]);
        exit( 10 );
    }
        
    oldnamelen = strlen(argv[1]) + 50;    
    oldd = AllocMem( oldnamelen, MEMF_CLEAR );
    newi = AllocMem( oldnamelen, MEMF_CLEAR );
    
    strcpy(oldd,argv[1]);

    strcpy(newi,argv[1]);
    strcat(newi,".NEW.RMFINDEX");
    
    noerrs = rebuild_index( oldd, newi );
    
    if( noerrs ) {
        printf("\n\n A new index has been created\n");
        printf("     New Index File Name: %s \n",newi);
    }
    else {
        printf("\n\n  Unable to rebuild Index File\n\n");
    }
    
    FreeMem( oldd, oldnamelen );
    FreeMem( newi, oldnamelen );
    
}

int rebuild_index( char *datafile, char *newindex )
{

     char                  * databuffer, * datapointer;
     struct RecordHeader   * rh;
     struct DataFileHeader * dfh;
     struct DiskIndex      * dtnode;
     struct IndexFile      *ix;
     LONG                  bread,rba;
     LONG                  reclen,totallen;
     LONG newIfile,oldDfile;
     ULONG recordcount;
     int i,j,dlen,kindx;

     databuffer  = NULL;
     recordcount = 0;

     oldDfile = Open( datafile, MODE_OLDFILE );
     if( !oldDfile ) {
         printf("\n COULD NOT OPEN file %s\n\n",datafile);
         return( FALSE );
     }

     newIfile = Open( newindex, MODE_NEWFILE );
     if( !newIfile ) {
         printf("\n COULD NOT CREATED file %s\n\n",newindex);
         Close( oldDfile );
         return( FALSE );
     }    

     dtnode = AllocMem( sizeof(struct DiskIndex), MEMF_CLEAR );    
     dfh    = AllocMem( sizeof(struct DataFileHeader), MEMF_CLEAR );    
     rh     = AllocMem( sizeof(struct RecordHeader), MEMF_CLEAR );    
     ix     = AllocMem( sizeof(struct IndexFile), MEMF_CLEAR );    
     
     if( !ix || !rh || !dfh || !dtnode ) { /* a mem alloc. failed */
         printf("\nUnable to allocate memory\n\n");
         if( rh )
             FreeMem(rh,sizeof(struct RecordHeader));
         if( dfh )
             FreeMem(dfh,sizeof(struct DataFileHeader));
         if( dtnode )
             FreeMem(dtnode,sizeof(struct DiskIndex));
         if( ix )
             FreeMem(ix,sizeof(struct IndexFile));
         Close( oldDfile );
         Close( newIfile );
         return( FALSE  );
     }
     
     /* init. and write fixed length IndexHeader info */
     
     for( i = 0; i < MAXINDICES; i++ )
          ix->dups = 1;    /* will allow duplicates */
          
     /* rba_primary must point to the first DI_Info block */
     /* DI_Info always follows IndexHeader                */
     ix->rba_primary = sizeof(struct IndexFile);
     
     Write(newIfile,ix,sizeof(struct IndexFile) );
     
     
     /* read past datafile header */
     bread = Read( oldDfile, dfh, sizeof(struct DataFileHeader) );
     
     /* our current position is where first record is located */
     rba = Seek(oldDfile, 0, OFFSET_CURRENT );    
     rba = Seek(oldDfile, 0, OFFSET_CURRENT );    
     
while( 1 ) {

     bread = Read( oldDfile, rh, sizeof(struct RecordHeader) );
     if( bread == 0 ) /* end of file */
         break;
     
     if( bread < sizeof(struct RecordHeader) ) { /* read error */
         Close( oldDfile );
         Close( newIfile );
         FreeMem( rh, sizeof(struct RecordHeader) );
         FreeMem( dfh,sizeof(struct DataFileHeader));
         FreeMem( dtnode,sizeof(struct DiskIndex));
         FreeMem( ix,sizeof(struct IndexFile));
         return( NULL );
     }
     
         
     reclen = rh->recordlength;
     if( reclen <= 0 ) { /* if zero must be a deleted block */
                         /* create deleteindex entry        */     
         dtnode->di_info.recaddr = rba;
         dtnode->di_info.blklength = rh->blocklength;
         dtnode->di_info.recstatus = 'D';
         dtnode->di_info.keylen[0] = 3;
         
         dtnode->keydata[0] = 'z'; /* a dummy key */
         dtnode->keydata[1] = 'd'; /* even the delete index */
         dtnode->keydata[2] = 'r'; /* requires a non-null primary key */
         
         totallen = sizeof(struct DI_Info) + 3;
         Write(newIfile,dtnode,totallen);
         Seek(oldDfile,rh->blocklength,OFFSET_CURRENT);
         rba = Seek(oldDfile, 0, OFFSET_CURRENT );    
         rba = Seek(oldDfile, 0, OFFSET_CURRENT );    
         
         continue; 
     }
     
     /* else assume active data block */
     databuffer = AllocMem( reclen, MEMF_CLEAR );
     datapointer = databuffer;
     if( !databuffer ) {  /* no mem to load data record */
         Close( oldDfile );
         Close( newIfile );
         FreeMem( rh, sizeof(struct RecordHeader) );
         FreeMem( dfh,sizeof(struct DataFileHeader));
         FreeMem( dtnode,sizeof(struct DiskIndex));
         FreeMem( ix,sizeof(struct IndexFile));
         return( NULL );
     }
     
     /* read data record */     
     bread = Read( oldDfile, databuffer, reclen );
     if( bread == 0 ) /* end of file */
         break;
     
     if( bread < reclen ) { /* read error */
         Close( oldDfile );
         Close( newIfile );
         FreeMem( databuffer, reclen );
         FreeMem( rh, sizeof(struct RecordHeader) );
         FreeMem( dfh,sizeof(struct DataFileHeader));
         FreeMem( dtnode,sizeof(struct DiskIndex));
         FreeMem( ix,sizeof(struct IndexFile));
         return( NULL );
     }
     
     
     dlen = strlen(datapointer); /* this is gonna get the length of     */
                                 /* the prime key, its NULL terminated  */
                                 /* the data record is a series of NULL */
                                 /* terminated strings                  */

     if( dlen > 0 && dlen < MAXKEYLEN ) { /* valid key length */
     
         dtnode->di_info.recaddr   = rba;
         dtnode->di_info.blklength = rh->blocklength;
         dtnode->di_info.recstatus = 'A';
         dtnode->di_info.keylen[0] = dlen;

         kindx = 0;                           
         for( j = 0; j < dlen; j++ )
              dtnode->keydata[kindx++] = *(datapointer+j);

         totallen = sizeof(struct DI_Info) + dlen;
         datapointer = ((char *)(ULONG)datapointer + dlen + 1);

         for( i = 1; i <= rh->numaltindx; i++ ) {

              switch( *datapointer )
                {
                  case 0xf1:
                  case 0xf2:
                  case 0xf3:
                  case 0xf4:
                  case 0xf5:
                       ++datapointer;
                       dlen = strlen(datapointer);
                       if( dlen > 0 && dlen < MAXKEYLEN ) {
                           dtnode->di_info.keylen[i] = dlen;
                           for( j = 0; j < dlen; j++ )
                                dtnode->keydata[kindx++] = *(datapointer+j);
                           totallen = totallen + dlen;
                           datapointer = ((char *)(ULONG)datapointer + dlen + 1);
                       }
                }
         }

         Write(newIfile,dtnode,totallen);
         ++recordcount;
     
     }

     /* reclen does not include the 4byte Trailer (blocklength does) */
     /* skip over this records trailing null bytes                   */
     Seek(oldDfile,sizeof(struct EOR_Trailer),OFFSET_CURRENT);
     
     rba = Seek(oldDfile,0,OFFSET_CURRENT);  /* just to make sure I  */
     rba = Seek(oldDfile,0,OFFSET_CURRENT);  /* do this twice, Seek  */
                                             /* returns the previous */
                                             /* file position.       */
                                             /* Thus setting RBA for */
                                             /* next record          */
     
     FreeMem(databuffer,reclen);             /* varying length data  */
                                             /* so free each time    */
     
}     
     
/* position to beginning of IndexFile   */     
/* write fixed Index info. back to file */
/* (just making sure)                   */

ix->numberofrecords = recordcount;
Seek(newIfile,0,OFFSET_BEGINNING);
Write(newIfile,ix,sizeof(struct IndexFile) );

Seek(newIfile,0,OFFSET_END);

Close( newIfile );
Close( oldDfile );

FreeMem( rh,sizeof(struct RecordHeader));
FreeMem( dfh,sizeof(struct DataFileHeader));
FreeMem( dtnode,sizeof(struct DiskIndex));
FreeMem( ix,sizeof(struct IndexFile));

return( TRUE );
     
}

