#include <stdio.h>         /* NULL */
#include <string.h>        /* stricmp */
#include "dbext.h"         /* STRUCT_DEF_HDR_TYPE, LINK_PTR */
/** 1999/07/06 Pierre Jaccard
               The next include is required for explicit declaration of
               function stricmp. **/
#ifdef LACKS_STRICMP 
#  include "misc.h"
#endif
#include "find_def.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:  find_def.c

              Function used to find a structure definition from some list.

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

   FUNCTION:  find_def

      Given the name of a structure and a pointer to a linked list of
      structure definitions in memory, it returns a pointer to
      the definition of the named structure.

   PARAMETERS:

      struct_name = name of structure to search for

      str_def = pointer to linked list of structure definitions in memory

   RETURNS:

      NULL if the structure definition for struct_name was not found
      *structure definition otherwise

*/
#if PROTOTYPE_ALLOWED
STRUCT_DEF_HDR_TYPE *find_def(char *struct_name, STRUCT_DEF_HDR_TYPE *linked_list)
#else
STRUCT_DEF_HDR_TYPE *find_def(struct_name, linked_list)
char *struct_name;
STRUCT_DEF_HDR_TYPE *linked_list;
#endif
{
   STRUCT_DEF_HDR_TYPE *str_def_ptr, **next_link;

   str_def_ptr = linked_list;
   while (str_def_ptr != NULL)
   {
      while (*(str_def_ptr->name))
      {
         if (!stricmp(str_def_ptr->name, struct_name))  /* found */
            return(str_def_ptr);
         str_def_ptr += str_def_ptr->nelem + 1;         /* skip to next */
      }
      next_link = (STRUCT_DEF_HDR_TYPE **) &(str_def_ptr->LINK_PTR);
      str_def_ptr = *next_link;
   }
   return(NULL);              /* not found */
}

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

    FUNCTION:  find_elem

       Given the name of a structure, the name of a member of that
       structure, and a linked list of structure definitions,
       it calculates the buffer (relative) offset to, and the no. of
       bytes comprising that particular member of the named structure.
       It also retrieves the member's STRUCT_DEF_ELEM_TYPE information.
       (Note:  The member may be a simple data type or another structure.)

    PARAMETERS:

       elem_name   = pointer to name of element to search for
       struct_name = pointer to name of structure to search
       linked_list = pointer to a linked list of structure definitions

       data_ofs = pointer to offset to data associated with that element
       nb       = pointer to no. of bytes comprising that element
       elem_def = pointer to element's definition (STRUCT_DEF_ELEM_TYPE info)

    RETURNS:  0 if okay
              database error code otherwise

*/
#if PROTOTYPE_ALLOWED
int find_elem(char *elem_name, char *struct_name, 
	      STRUCT_DEF_HDR_TYPE *linked_list, 
	      unsigned int *data_ofs, unsigned int *nb, 
	      STRUCT_DEF_ELEM_TYPE *store_def)
#else
int find_elem(elem_name, struct_name, linked_list, data_ofs, nb, store_def)
char *elem_name, *struct_name;
STRUCT_DEF_HDR_TYPE *linked_list;
unsigned int *data_ofs, *nb;
STRUCT_DEF_ELEM_TYPE *store_def;
#endif
{
   STRUCT_DEF_HDR_TYPE *str_def;
   STRUCT_DEF_ELEM_TYPE *elem_def;
   int i;
   long size;

   /* first find structure definition */
   if ( (str_def = find_def(struct_name, linked_list)) == NULL )
      return(UNDEFINED_STRUCTURE);

   /* then cumulate offset and find nb */
   for (i = 0, elem_def = (STRUCT_DEF_ELEM_TYPE *) str_def + 1, *data_ofs = 0;
        i < str_def->nelem; i++, elem_def++)
   {
      if ( (size = get_elem_size(elem_def, linked_list)) < 0 )
         return(UNDEFINED_STRUCTURE);
      if (stricmp(elem_name, elem_def->name)) /* no match so increment offset */
         *data_ofs += (unsigned int) size;
      else        /* match so now determine no. of bytes */
      {
         *nb = (unsigned int) size;
         strcpy(store_def->name, elem_def->name);
         strcpy(store_def->units, elem_def->units);
         store_def->value_type = elem_def->value_type;
         store_def->count = elem_def->count;
         return(0);
      }
   }
   return(NO_SUCH_ELEMENT);  /* not found */
}

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

    FUNCTION:  get_struct_size

       It searches a linked list of structure definitions for the
       given structure name and calculates the size of the structure
       based on the definition(s) found.

    PARAMETERS:

       struct_name = pointer to name of structure to search for
                     (not case-sensitive)
       linked_list = pointer to head of linked list of structure definitions

    RETURNS:  no. of bytes in structure, if properly defined in linked list
              -1 on error

*/
#if PROTOTYPE_ALLOWED
long get_struct_size(char *struct_name, STRUCT_DEF_HDR_TYPE *linked_list)
#else
long get_struct_size(struct_name, linked_list)
char *struct_name;
STRUCT_DEF_HDR_TYPE *linked_list;
#endif
{
   STRUCT_DEF_HDR_TYPE *str_def;
   STRUCT_DEF_ELEM_TYPE *elem_def;
   long size, temp;
   int i;

   if ( (str_def = find_def(struct_name, linked_list)) == NULL ) return(-1);

   for (i = 0, size = 0, elem_def = (STRUCT_DEF_ELEM_TYPE *) str_def + 1;
      i < str_def->nelem; i++, size += temp, elem_def++)
      if ( (temp = get_elem_size(elem_def, linked_list)) < 0 ) return(-1);
   return(size);
}

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

    FUNCTION:  get_elem_size

       Given an element definition and the pointer to a linked list of
       structure definitions, it returns the no. of bytes associated
       with that element.  (The linked list pointer is needed in case
       the element is a structure.)

    PARAMETERS:

       elem_def    = pointer to element's STRUCT_DEF_ELEM_TYPE information
       linked_list = pointer to linked list of structure definitions

    RETURNS:  no. of bytes (>= 0) if okay
              < 0 if indeterminable (undefined structure)

*/
#if PROTOTYPE_ALLOWED
long get_elem_size(STRUCT_DEF_ELEM_TYPE *elem_def, STRUCT_DEF_HDR_TYPE *linked_list)
#else
long get_elem_size(elem_def, linked_list)
STRUCT_DEF_ELEM_TYPE *elem_def;
STRUCT_DEF_HDR_TYPE  *linked_list;
#endif
{
   extern UBYTE VALUE_SIZE[];

   if (elem_def->value_type != STRUCT_VALUE_CODE)
      return(elem_def->count * VALUE_SIZE[elem_def->value_type]);
   else
   {
      if (elem_def->count <= 0) return(-(elem_def->count));
      return(elem_def->count * get_struct_size(elem_def->name, linked_list));
   }
}

