/*
 * IOPEN.C - open and close functions
 *
 *                      Copyright (c) 1987, Jim Mischel
 * Modifications:
 *
 * 08/13/87 - jim - original coding
 * 11/04/87 - jim - remove keytyp from iopen() calling sequence.  There are
 *                  no default key types.  iopen() now requires that the
 *                  cmp_rtn parameter be passed.
 *		    Added new error code I_NOCMP to be used if cmp_rtn is NULL.
 */

#include "inxdefs.h"
/*
 * iopen() - open file for indexed access and setup fields in control record.
 * If successful, returns a pointer to the control record.  Returns NULL
 * if unsuccessful.  If the routine is unable to open an existing file,
 * a new file is created.  It is possible to create a new index for an
 * existing data file, or a new data file for an existing index file.
 * In either case, no data will be lost, but new data could be added to
 * the end of the file.
 */
void *iopen(char *fname, unsigned recsiz, unsigned offset,
            char dupflag, int (*cmp_rtn)())
{
  register df_rec *db_control;
  char *path;
  inx_rec *irec;

  /* allocate space for control record */
  if ((db_control = malloc(sizeof(df_rec))) == NULL) {
    ierror(I_NOMEM);                    /* out of memory */
    return(NULL);
  }

  /* allocate space for data buffer */
  if ((db_control->df_dat_buff = malloc(recsiz)) == NULL) {
    ierror(I_NOMEM);                    /* out of memory */
    goto free_control;
  }

  /* allocate space for pathname */
  if ((db_control->df_path = malloc(strlen(fname))) == NULL) {
    ierror(I_NOMEM);
    goto free_datbuf;
  }

  /* copy pathname to control record */
  strcpy(db_control->df_path,fname);

  /* open index file */
  if ((path = malloc(256)) == NULL) {
    ierror(I_NOMEM);                    /* out of memory */
    goto free_fname;
  }

  strcpy(path,fname);
  if ((db_control->df_inx_file = fopen(strcat(path,".INX"),"r+b")) == NULL) {
    /* can't open index file, so create a new one */
    if ((db_control->df_inx_file = fopen(path,"w+b")) == NULL) {
      ierror(I_NOINX);                  /* couldn't create index file */
      goto free_path;
    }
    else {
      /* new index file created.  Add header node */
      irec = &db_control->df_inx_buff;
      irec->if_dat_ptr = 0L;
      irec->if_right_node = 0L;
      irec->if_left_node = 0L;
      irec->if_parent = 0L;
      irec->if_flags = BTHRD+ETHRD+LTHRD+RTHRD;
      if (iwrite_inx(db_control,irec,0L)) {
        ierror(I_INXWT);                /* couldn't write header record */
        goto free_path;
      }
    }
  }

  strcpy(path,fname);
  if ((db_control->df_dat_file = fopen(strcat(path,".DAT"),"r+b")) == NULL) {
    /* can't open data file, so create a new one */
    if ((db_control->df_dat_file = fopen(path,"w+b")) == NULL) {
      ierror(I_NODAT);                  /* couldn't create data file */
      goto close_inx;
    }
  }

  /* setup key comparison routine. */
   if (cmp_rtn == NULL) {
     ierror(I_NOCMP);		/* error:  no comparison routine */
     goto close_inx;
   }
   else
     db_control->df_cmp = cmp_rtn;

  db_control->df_rec_size = recsiz;
  db_control->df_key_offset = offset;
  db_control->df_key_ptr = db_control->df_dat_buff + offset;
  db_control->df_nxt_ptr = 0L;
  db_control->df_inx_ptr = 0L;
  db_control->df_dat_ptr = 0L;
  db_control->df_flags = DF_EOF + DF_TOF + DF_DELETE + ((dupflag) ? DF_DUP : 0);

  free(path);                           /* don't need this anymore */
  ierror(0);                            /* no problem */
  return(db_control);

close_inx:
  fclose(db_control->df_inx_file);
free_path:
  free(path);
free_fname:
  free(db_control->df_path);
free_datbuf:
  free(db_control->df_dat_buff);
free_control:
  free(db_control);
  return(NULL);
} /* iopen */

/*
 * iclose() - close files and free space used by control record
 */
void iclose(void *d)
{
  register df_rec *db_control = (df_rec *)d;

  fclose(db_control->df_dat_file);
  fclose(db_control->df_inx_file);
  free(db_control->df_path);
  free(db_control->df_dat_buff);
  free(db_control);
} /* iclose */
