#include "dbinc.h"
/*****************************************************************************
*                                                                            *
*      COMMON OCEANOGRAPHIC DATA ACCESS SYSTEM (CODAS)                       *
*                                                                            *
*      WRITTEN BY:  RAMON CABRERA, ERIC FIRING, and JULIE RANADA             *
*                   JOINT INSTITUTE FOR MARINE AND ATMOSPHERIC RESEARCH      *
*                   1000 POPE ROAD  MSB 404                                  *
*                   HONOLULU, HI 96822                                       *
*                                                                            *
*      VERSION:     3.00                                                     *
*                                                                            *
*      DATE:        APRIL 1989                                               *
*                                                                            *
*****************************************************************************/
/*

       FILE:  dbloadsd.c

              FUNCTIONS FOR LOADING STRUCTURE DEFINITIONS FROM EXTERNAL FILE

*/
/*-----------------------------------------------------------------------------

    FUNCTION:  DBLOADSD

       Loads a set of structure definitions from an external text file
       into memory, and appends it to a linked list of structure definitions
       for that database.

    PARAMETERS:

       filename = name of external text file
       ierr = error code

    RETURNS:  VOID

*/
#if PROTOTYPE_ALLOWED
void DBLOADSD(char *filename, int *ierr)
#else
void DBLOADSD(filename, ierr)
char *filename;
int *ierr;
#endif
{
   STRUCT_DEF_HDR_TYPE *strdef_list, **link_address;
   USHORT nentries;

   *ierr = 0;
   if ((!(db)) || first_database_call)
   {
      *ierr = DB_IS_NOT_OPEN;
      return;
   }
   if ((db->error_code = load_structure_definition(filename, &strdef_list,
      &nentries, &(db->format_list))) != 0)
   {
      db->error_data = STRUCTURE_DEF;
      report_db_error("DBLOADSD");
      *ierr = db->error_code * 1000 - db->error_data;
      return;
   }
   if (strdef_list)
   {
      if (db->struct_def == NULL)   /* allows multiple calls to DBLOADSD */
      {
         db->struct_def = strdef_list;
         db->prev_strdef = strdef_list + (nentries - 1);
      }
      else
      {
         concat_strdef(&(db->struct_def), strdef_list);
         if ((db->block_strdef_loaded) && (db->next_strdef == NULL))
         {
            db->next_strdef = strdef_list;
            link_address = (STRUCT_DEF_HDR_TYPE **) &(
               (db->block_strdef + (db->block_hdr.struct_def_nentries - 1))
               ->LINK_PTR );
            *link_address = db->next_strdef;
/*          (db->block_strdef + (db->block_hdr.struct_def_nentries - 1))
               ->pa.access.link_ptr = db->next_strdef; */
         }
      }
   }
   if (db->format_list)
      if (match_formats(db->struct_def, db->format_list))
      {
         report_db_error("DBLOADSD");
         *ierr = FORMAT_ERROR;
         return;
      }
}

/*-----------------------------------------------------------------------------

    FUNCTION:  load_structure_definition

       It loads structure definitions (DEFINE_STRUCT/ELEM/FORMAT) and
       structure printing formats (DEFINE_FORMAT) from an external text file
       into memory.

    PARAMETERS:

       filename    = name of external text file
       hdr         = pointer to memory location that structure
                     definitions have been loaded into
       nentries    = no. of STRUCT_DEF_ELEM_TYPE entries loaded
       format_list = pointer to memory location that structure
                     printing formats have been loaded into

    RETURNS:  0 if okay
              error code otherwise

*/
#if PROTOTYPE_ALLOWED
int load_structure_definition(char *filename, 
			      STRUCT_DEF_HDR_TYPE **hdr, 
			      USHORT *nentries, 
			      FORMAT_HDR_TYPE **format_list)
#else
int load_structure_definition(filename, hdr, nentries, format_list)
char *filename;
STRUCT_DEF_HDR_TYPE **hdr;
USHORT *nentries;
FORMAT_HDR_TYPE **format_list;
#endif
{
   FILE *fpin;
   char keyword[80];
   USHORT fmt_nentries = 0;
   int error_code;
#if (COMPILER == VAX_VMS_C)
   FILE *fptemp;
#endif

   *nentries = 0;
/*
 ---> OPEN STRUCTURE DEFINITION FILE
*/
   if ((fpin = fopen(filename, "rb")) == NULL)
   {
      printf("\n ERROR: Cannot open file %s", filename);
      return(UNABLE_TO_OPEN);
   }
#if (COMPILER == VAX_VMS_C)
   if ((fptemp = fopen("TEMP.DEF", "w")) == NULL)
   {
      printf("\n ERROR: Cannot open temporary data file TEMP.DEF");
      return(UNABLE_TO_OPEN);
   }
   strip_comments(fpin, fptemp);
   fclose(fpin);
   fclose(fptemp);
   if ((fpin = fopen("TEMP.DEF", "r")) == NULL)
   {
      printf("\n ERROR: Cannot open temporary data file TEMP.DEF");
      return(UNABLE_TO_OPEN);
   }
#endif
/*
 ---> ALLOCATE MEMORY FOR STRUCTURE DEFINITIONS & FORMAT SPECIFICATIONS
*/
   if ((*hdr = (STRUCT_DEF_HDR_TYPE *) calloc(1, STRUCT_DEF_ENTRY_SIZE)) == NULL)
      return(INSUFFICIENT_MEMORY);
   if ((*format_list = (FORMAT_HDR_TYPE *) calloc(1, sizeof(FORMAT_ENTRY_TYPE)))
      == NULL)
      return(INSUFFICIENT_MEMORY);
/*
 ---> SCAN EXTERNAL FILE
*/
   while (getword_nc(fpin, keyword, 80))
   {
      if (!strcmp(keyword, "DEFINE_STRUCT"))
      {
         if ((error_code = define_struct(fpin, hdr, nentries)) != 0)
            return(error_code);
      }
      else if (!strcmp(keyword, "DEFINE_FORMAT"))
      {
         if ((error_code = define_format(fpin, format_list, &fmt_nentries)) != 0)
            return(error_code);
      }
      else
      {
         printf("\n ERROR: Unrecognized parameter\n SCANNING: %s\n",keyword);
         return(READ_ERROR);
      }
   }

   fclose(fpin);
#if (COMPILER == VAX_VMS_C)
   unlink("TEMP.DEF");
#endif

/*
 ---> ADD NULL ENTRY TERMINATORS FOR THE TWO LINKED LISTS
*/
   if (*nentries)
   {
      if ((*hdr = (STRUCT_DEF_HDR_TYPE *) realloc((char *) *hdr,
         (1 + *nentries) * STRUCT_DEF_ENTRY_SIZE)) == NULL)
         return(INSUFFICIENT_MEMORY);
      set_byte((UBYTE *) (*hdr + *nentries), 0, STRUCT_DEF_ENTRY_SIZE);
      (*nentries)++;  /* add entry for NULL terminator */
   }

   if (fmt_nentries)
   {
      if ((*format_list = (FORMAT_HDR_TYPE *) realloc((char *) *format_list,
         (1 + fmt_nentries) * sizeof(FORMAT_HDR_TYPE))) == NULL)
         return(INSUFFICIENT_MEMORY);
      set_byte((UBYTE *)(*format_list + fmt_nentries), 0, sizeof(FORMAT_HDR_TYPE));
      return(match_formats(*hdr, *format_list));
   }
   else
      return(0);
}

/*-----------------------------------------------------------------------------

    FUNCTION:  define_format

       It processes the DEFINE_FORMAT statements from an external text file.

    PARAMETERS:

       fpin = pointer to external text file
       format_list = pointer to linked list of structure format definitions
       nentries = no. of FORMAT_ENTRY_TYPE entries in format_list

    RETURNS:  0 if okay
              error code otherwise

*/
#if PROTOTYPE_ALLOWED
int define_format(FILE *fpin, FORMAT_HDR_TYPE **format_list, USHORT *nentries)
#else
int define_format(fpin, format_list, nentries)
FILE *fpin;
FORMAT_HDR_TYPE **format_list;
USHORT *nentries;
#endif
{
   char keyword[20], buff[80], test[3], *struct_name, *elem_name;
   USHORT nelem, i;
   unsigned int nbytes;
   FORMAT_ENTRY_TYPE *format_ptr;

   if ((getwords_nc(fpin, buff, 80, 2) != 2) ||
      (sscanf(buff, "%19s %hd %2s", keyword, &nelem, test) != 2))
   {
      printf("\n SCANNING: %s", buff);
      return(READ_ERROR);
   }
   nbytes = (*nentries + nelem + 1) * sizeof(FORMAT_ELEM_TYPE);
   if ((*format_list = (FORMAT_HDR_TYPE *) realloc(*format_list, nbytes)) == NULL)
      return(INSUFFICIENT_MEMORY);
   format_ptr = (FORMAT_ENTRY_TYPE *) *format_list + *nentries;
   if ((struct_name = malloc(strlen(keyword))) == NULL)
      return(INSUFFICIENT_MEMORY);
   strcpy(struct_name, keyword);
   format_ptr->hdr.name = struct_name;
   format_ptr->hdr.nelem = nelem;

   for (i = 0; i < nelem; i++)
   {
      format_ptr += 1;
      if (!getword_nc(fpin, keyword, 20))
         goto read_error;
      if (strcmp(keyword, "FORMAT"))
         goto read_error;
      if (!getword_nc(fpin, keyword, 20))
         goto read_error;
      if ((elem_name = malloc(strlen(keyword))) == NULL)
         return(INSUFFICIENT_MEMORY);
      strcpy(elem_name, keyword);
      format_ptr->elem.name = elem_name;
      format_ptr->elem.format_ptr = define_format_spec(fpin);
   }
   *nentries += nelem + 1;
   return(0);

   read_error:
      printf("\n SCANNING: %s\n", keyword);
      return(READ_ERROR);
}

/*-----------------------------------------------------------------------------

    FUNCTION:  concat_strdef

       It appends a block of structure definitions to a linked list of
       more structure definitions.

   PARAMETERS:

      head = pointer to head of linked list

      new = pointer to block of structure definitions to be appended

    RETURNS:  VOID

*/
#if PROTOTYPE_ALLOWED
void concat_strdef(STRUCT_DEF_HDR_TYPE **head, STRUCT_DEF_HDR_TYPE *new)
#else
void concat_strdef(head, new)
STRUCT_DEF_HDR_TYPE **head, *new;
#endif
{
   STRUCT_DEF_HDR_TYPE *member, *save, **link_address;

   if (*head == NULL)
      *head = new;
   else
   {
      member = *head;
      do
      {
         while (*(member->name))
            member += member->nelem + 1;
         save = member;
         link_address = (STRUCT_DEF_HDR_TYPE **) &(save->LINK_PTR);
         member = *link_address;
/*       member = save->pa.access.link_ptr; */
      } while (member != NULL);
      link_address = (STRUCT_DEF_HDR_TYPE **) &(save->LINK_PTR);
      *link_address = new;
/*    save->pa.access.link_ptr = new;  */
   }
}

