/************************************************************************/
/* This is a sample program for the Keyed File System. It will create a */
/* keyed file from a sequential input file and perform various          */
/* operations on the keyed file.                                        */
/************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <kfs.h>                /* Need this for KFS                    */

KFS_FILEINFO file1;             /* Keyed file declaration               */
FILE *infile;                   /* Normal C file declaration            */

struct TR {                     /* A data structure for the keyed file  */
  char fld1[4];
  char keyfld[15];              /* The key field of the keyed file      */
  char fld2;
  short inputseq;
  char desc[40];
  char rest[18];
  } tr;

char inarea[80];
/* These internal routines will show you some of the information in the */
/* KFS_FILEINFO structure "file1" and print the keyed file.             */
static void prtKFS(KFS_FILEINFO *, char *);
static void prttr(struct TR, char *);

void main(argc, argv, envp)
  int argc;
  char *argv[];
  char *envp[];
  {
    int i;

/* These five statements needed for a KFS_Create                        */
    file1.KFS_keypos = 4;
    file1.KFS_keylen = 15;
    file1.KFS_recsize = sizeof(tr);
    file1.KFS_flags = KFS_Normal_PTR;
    strcpy(file1.KFS_filename, "keyfile.001");

/* Create a new file named KEYFILE.001 in the current directory         */
    KFS_Create(&file1);
    prtKFS(&file1, "Print after KFS_Create");

/* This is how you check the return code from a KFS function            */
    if (file1.KFS_rc == KFS_File_Already_Exists) {                     
      printf("Keyed file already exists, program terminated!\n");      
      return;                                                          
    } /* endif */                                                      
    KFS_Close(&file1);                                                 
    prtKFS(&file1, "Print after KFS_Close");                           
                                                                       
/* To open an existing file, specify only the file name and path        */
    strcpy(file1.KFS_filename, "keyfile.001");
    KFS_Open(&file1);
    prtKFS(&file1, "Print after KFS_Open");
    if (file1.KFS_rc != KFS_OK) {
      printf("Error opening new keyed file, program terminated!\n");
      return;
    } /* endif */

/* Open the sequential input file we'll use to build the keyed file     */
    if ((infile = fopen("kfssamp.dat", "r")) == NULL)
      {
       printf("Cannot open input file!\n");
       return;
      }

/* Just put some stuff in the keyed record for all records              */
    strncpy(tr.fld1, "REC", sizeof(tr.fld1));                          
    strcpy(tr.rest, "End of record !");                                
    tr.fld2 = ' ';                                                     
    tr.inputseq = 0;
    fgets(inarea, 80, infile);                                         
                                                                       
/* Read all the input records and build the keyed file                  */
    while (!feof(infile)) {
      tr.inputseq++;            /* This shows what sequence record added*/

/* Insure key field has no garbage (not really necessary here)          */
      memset(tr.keyfld, 0, sizeof(tr.keyfld));                       
                                                                     
/* Copy in key from sequential file                                     */
      strncpy(tr.keyfld, inarea, sizeof(tr.keyfld));

      strcpy(tr.desc, &inarea[sizeof(tr.keyfld)]);
      KFS_Add(&file1, &tr);     /* Add each new record to the file      */
      if (file1.KFS_rc != KFS_OK)
         if (file1.KFS_rc == KFS_No_Space_On_Disk) {
            printf("Not enough space to add key %s\n",
               file1.KFS_rc, tr.keyfld);
         } else {
            printf("Bad return code from KFS_Add, rc = %d, key = %s\n",
               file1.KFS_rc, tr.keyfld);
         } /* endif */
      fgets(inarea, 80, infile);
    } /* endwhile */

/* Read a record by key                                                 */
    strncpy(tr.keyfld, "Dmiddle key    ", 15);
    KFS_Read(&file1, &tr);
    switch (file1.KFS_rc) {     /* We could check KFS_rc like this      */
    case KFS_Key_Not_Found:
       printf("Key not found error\n");
       break;
    case KFS_File_Error:
       printf("Error reading file, file damaged?\n");
       break;
    } /* endswitch */
    prtKFS(&file1, "Print after KFS_Read"); /* Show the file structure  */
    prttr(tr, "TR structure after read");   /* Show the data area       */

/* Now read the first record in the file                                */
    KFS_ReadFirst(&file1, &tr);
    prtKFS(&file1, "Print after KFS_ReadFirst");
    prttr(tr, "TR structure after read");

/* Now read the second record in the file                               */
    KFS_ReadNext(&file1, &tr);                                         
    prtKFS(&file1, "Reading sequentially");                            
                                                                       
/* Now read the rest of the file                                        */
    while (file1.KFS_rc != KFS_EOF) {                                  
      prttr(tr, "TR structure after read");                            
      KFS_ReadNext(&file1, &tr);                                       
    } /* endwhile */                                                   
    printf("End of file reached\n");                                   
                                                                       
/* Delete a record (notice we didn't read it first)                     */
    strncpy(tr.keyfld, "Ni   key       ",15);
    KFS_Delete(&file1, &tr);                                           
    prtKFS(&file1, "Print after KFS_Delete");                          
                                                                       
/* Notice if we do a ReadNext that we get an error (Prev key must exist)*/
    KFS_ReadNext(&file1, &tr);
    prtKFS(&file1, "Print after KFS_ReadNext");
    if (file1.KFS_rc == KFS_Prior_Key_Not_Found) {
       printf("We (correctly) cant do a ReadNext when prior key is gone\n");
    prttr(tr, "TR structure still contains old information (except key)");
    } /* endif */
                                                                       
/* But a ReadGen will work to give us the next record                   */
    KFS_ReadGen(&file1, &tr, 15);
    prtKFS(&file1, "Print after KFS_ReadGen");
    if (file1.KFS_rc == KFS_Key_Not_Found) {
       printf("We couldnt find the key but still got the next record\n");
    } /* endif */
    prttr(tr, "TR structure now contains next record");
                                                                       
/* Update and replace an existing record                                */
    strncpy(tr.keyfld, "Dsecond key    ",15);                          
    strcpy(tr.fld1, "REP");                                            
    strcpy(tr.desc, "This record was replaced\n");                     
    KFS_Replace(&file1, &tr);                                          
    prtKFS(&file1, "Print after KFS_Replace");                         
    KFS_Read(&file1, &tr);                                             
    prtKFS(&file1, "Verifying replace by reading");
                                                                       
/* Read the complete file again                                         */
    KFS_ReadFirst(&file1, &tr);
    prtKFS(&file1, "Print after KFS_ReadFirst");
    prttr(tr, "TR structure after read");

    KFS_ReadNext(&file1, &tr);
    prtKFS(&file1, "Reading sequentially");
    while (file1.KFS_rc == KFS_OK) {
      prttr(tr, "TR structure after read");
      KFS_ReadNext(&file1, &tr);
    } /* endwhile */
    if (file1.KFS_rc == KFS_EOF)
      printf("\n\nEnd of file reached!!\n");
    else
      printf("Some other error ocurred\n");

/* Always close the file when finished                                  */
    KFS_Close(&file1);
  }

void prtKFS(KFS_FILEINFO *f, char *header)
  {
    printf("\n%s\n", header);
    printf("KFS_rc = %d\n", f->KFS_rc);
    printf("KFS_keypos = %d\n", f->KFS_keypos);
    printf("KFS_keylen = %d\n", f->KFS_keylen);
    printf("KFS_recsize = %d\n", f->KFS_recsize);
    printf("KFS_filename = %s\n", f->KFS_filename);

  }

void prttr(struct TR tr, char *header)
  {
    char cwork[40];
    printf("\n%s\n", header);
    strncpy(cwork, tr.keyfld, sizeof(tr.keyfld));
    cwork[sizeof(tr.keyfld)] = '\0';
    printf("tr.keyfld = %s\n", cwork);
    printf("tr.inputseq = %d\n", tr.inputseq);
    printf("tr.desc = %s\n", tr.desc);
  }
