#include "common.h"  /* realloc() */
#include "geninc.h"
#include "valuelst.h" /* VALUE_CODE[] */
/*****************************************************************************
*                                                                            *
*      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:  defstruc.c

              FUNCTIONS FOR PROCESSING DEFINE_STRUCT STATEMENT
*/

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

   FUNCTION:  define_struct

      Processes a DEFINE_STRUCT statement in the producer definition file.
      It sets up a space in memory for the array of STRUCTURE_DEFINITION_
      ENTRY_TYPE structures corresponding to each element of the
      structure being defined.  It sets the structure_definition and
      nelem fields of the data_list entry (if id < MAX_DATA_LIST_SIZE)
      or elem_list entry (otherwise) accordingly.

   PARAMETERS:

      fpin = pointer to file containing structure definition

      head_ptr = address of pointer to head of list of structure definitions

      nentries = pointer to no. of entries in list so far

   RETURNS:

      0 if okay
      system or database error code otherwise

*/
#if PROTOTYPE_ALLOWED
int define_struct(FILE *fpin, STRUCT_DEF_HDR_TYPE **head_ptr, USHORT *nentries)
#else
int define_struct(fpin, head_ptr, nentries)
FILE *fpin;
STRUCT_DEF_HDR_TYPE **head_ptr;
USHORT *nentries;
#endif
{
   int i, nelem, temp;
   unsigned int add_bytes;
   long curpos;
   CHAR struct_name[20], keyword[20], type[12], buff[80];
   STRUCT_DEF_ENTRY_TYPE *str_def;

   if (getwords_nc(fpin, buff, 80, 2) != 2)
      goto read_error;
   if (sscanf(buff, " %19s %d", struct_name, &nelem) != 2)
      goto read_error;
   struct_name[19] = '\0';
   add_bytes = (nelem + 1) * STRUCT_DEF_ENTRY_SIZE;
   if ((*head_ptr = (STRUCT_DEF_HDR_TYPE *) realloc((char *) (*head_ptr),
      *nentries * STRUCT_DEF_ENTRY_SIZE + add_bytes)) == NULL)
      return(INSUFFICIENT_MEMORY);
   str_def = (STRUCT_DEF_ENTRY_TYPE *) (*head_ptr) + *nentries;
   set_byte((UBYTE *) str_def, 0, add_bytes);
   strcpy(str_def->hdr.name, struct_name);
   str_def->hdr.nelem = (LONG) nelem;
   str_def += 1;

   for (i = 0; i < nelem; i++)
   {
      getword_nc(fpin, keyword, 20);
      if (strcmp(keyword, "ELEM"))
      {
         printf("\n SCANNING: %s, should be ELEM\n", keyword);
         return(READ_ERROR);
      }
      if (getwords_nc(fpin, buff, 80, 4) != 4)
         goto read_error;
      if (sscanf(buff, " %hd %11s %19s %11s",
         &(str_def[i].elem.count), type, str_def[i].elem.name,
         str_def[i].elem.units) != 4)
         goto read_error;
      if ((temp = get_code(VALUE_CODE, type)) == BADINT)
      {
         printf("\n SCANNING:  %s\n", buff);
         return(INVALID_VALUE_TYPE);
      }
      else
      str_def[i].elem.value_type = temp;
      curpos = ftell(fpin);
      if (getword_nc(fpin, keyword, 20))
      {
         if (!strcmp(keyword, "FORMAT"))
            *((FORMAT_SPEC **) str_def[i].elem.format_ptr) =
               define_format_spec(fpin);
         else
            if (fseek(fpin, curpos, SEEK_SET) != 0)
               return(SEEK_ERROR);
      }
   }
   *nentries += (nelem + 1);
   return(0);

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

/*
   ARRAY OF POINTERS TO PRINT FUNCTIONS -- Default is fprintf; special print
   functions must return unsigned int indicating number of bytes printed, and
   take output file pointer and data pointer as arguments.
*/
static struct
{
   char *name;
   unsigned int (*print_function)();
} PRINT_FUNCTION[] =
{
   {""                   , NULL},  /* NULL pointer defaults to fprintf */
   {"NULL"               , NULL},
   {"fprintf"            , NULL},
   {"print_bit_pattern"  , print_bit_pattern},
   {"print_ymdhms_time"  , print_ymdhms_time},
   {"print_dmsh_position", print_dmsh_position},
   {"prpckpt"            , prpckt},
   {"prpckp"             , prpckp},
   {NULL                 , NULL}    /* list terminator must be NULL */
};

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

    FUNCTION:  define_format_spec

       It reads a format specification from an external text file,
       allocates memory and loads it into memory.

    PARAMETER:  fpin = pointer to external text file

    RETURNS:  pointer to memory location that the format specification has
              been loaded into if okay
              NULL otherwise

*/
#if PROTOTYPE_ALLOWED
FORMAT_SPEC *define_format_spec(FILE *fpin)
#else
FORMAT_SPEC *define_format_spec(fpin)
FILE *fpin;
#endif
{
   char line[255], print_function_name[20], *format_string, pause_string[6], test[3];
   int pause, print_function_index;
   FORMAT_SPEC *format_ptr;

   if (get_quotation(fpin, line, 255) == NULL)
      goto read_error;
   if ((format_string = malloc(strlen(line))) == NULL)
      goto memory_error;
   if ((format_ptr = (FORMAT_SPEC *) malloc(sizeof(FORMAT_SPEC))) == NULL)
      goto memory_error;
   strcpy(format_string, line);
   if (getwords_nc(fpin, line, 256, 2) != 2)
      goto read_error;
   if (sscanf(line, " %5s %19s %2s", pause_string, print_function_name, test)
      != 2)
      goto read_error;
   if (!stricmp(pause_string, "PAUSE"))
      pause = PAUSE;
   else if (!stricmp(pause_string, "GO"))
      pause = GO;
   else goto read_error;
   if ((print_function_index = find_print_function(print_function_name)) < 0)
      goto read_error;
   format_ptr->fmt_string = format_string;
   format_ptr->pause = pause;
   format_ptr->print_function =
      PRINT_FUNCTION[print_function_index].print_function;
   return(format_ptr);

   read_error:
      printf("\n ERROR: In define_format_spec\n Scanning: %s\n", line);
      return(NULL);
   memory_error:
      printf("\n ERROR: In define_format_spec\n Insufficient memory\n");
      return(NULL);
}

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

    FUNCTION:  find_print_function

       Given the name of a special printing function, it searches the static
       array PRINT_FUNCTION for the corresponding index.

    PARAMETER:  fn_name = name of printing function to search for

    RETURNS:  array index if found
              -1 otherwise

*/
#if PROTOTYPE_ALLOWED
int find_print_function(char *fn_name)
#else
int find_print_function(fn_name)
char *fn_name;
#endif
{
   int i = 0;

   while (PRINT_FUNCTION[i].name)
      if (!stricmp(PRINT_FUNCTION[i].name, fn_name))
         return(i);
      else i++;
   return(-1);
}

