/*******************************************************************************
* YORKTOWN ADVANCED SGML PARSER (YASP)                                         *
*         An SGML Parser conforming to International Standard ISO 8879 --      *
*         Standard Generalized Markup Language                                 *
*------------------------------------------------------------------------------*
* Written 1987 - 1993 by                                                       *
*         Pierre G. Richard                                                    *
*         IBM T.J. Watson Research Center                                      *
*         Yorktown Heights, New York                                           *
*         petrus@watson.ibm.com                                                *
*------------------------------------------------------------------------------*
* FUNCTION NAME    = YASP / General Library                                    *
* STATUS           = Version 0, Release 1, Level 16 and up                     *
* COMPONENT NAME   = samgr.c                                                   *
* DESCRIPTIVE NAME = gather in a sorted array elements of a same kind          *
* DATE_WR          = 05/27/1987                                                *
* AUTHOR           = Pierre G. Richard - PETRUS at YKTVMX                      *
*                                                                              *
* FUNCTIONAL DESCRIPTION =                                                     *
*                                                                              *
* These procedures are designed to create a sorted array of elements.          *
*                                                                              *
* Typical calls are:                                                           *
*                                                                              *
* At initialization:                                                           *
*     +------------------------------------+                                   *
*     |id = (void *)sa_init(length,compf)  |                                   *
*     |uint length;                        |                                   *
*     |int (*compf)();                     |                                   *
*     +------------------------------------+                                   *
* request the creation of a new array,                                         *
* each element having a length of "length",                                    *
* the user supplied compare function being "compf".                            *
* returns an identifier used by further calls,                                 *
* to reference these elements                                                  *
*                                                                              *
* When a new element is encountered,                                           *
*     +------------------------------------+                                   *
*     |void sa_instl(id,elmt_p)            |                                   *
*     |void *id;                           |                                   *
*     |ELMT *elmt_p;                       |                                   *
*     +------------------------------------+                                   *
*                                                                              *
* stores this new element in the array                                         *
*                                                                              *
* At terminaison:                                                              *
*     +--------------------------------------+                                 *
*     |elemt_p = (ELMT *)sa_term(id,count_p) |                                 *
*     |void *id;                             |                                 *
*     |uint *count_p;                        |                                 *
*     +--------------------------------------+                                 *
* returns a pointer to the array, and set at count_p the number of             *
* elements in the array.                                                       *
*                                                                              *
* CHANGE HISTORY =                                                             *
* Number Date     Inits    Change & Reason (brief)                             *
*      1 06/30/87 PETRUS   Sort is done at the terminaison (faster)            *
*      2 08/08/87 PETRUS   Added the (void *) type                             *
*      3 04/17/88 PETRUS   Do not sort if compare is NULL                      *
*******************************************************************************/

#define INCRT 50
/*-------------+
|Include Files |
+-------------*/
#include "machine.h"
#include "portable.h"
#include "yaspapi.h"
#include "global.h"
#include "usrlib.h"

/*-------------------+
|Local data and types|
+-------------------*/
typedef struct t_SRYID {
   int (P_FCT * compf)(uchar *, uchar *, GA_P);
   GA_P gbla_p;
   uint length;
   int  count;
   int  max;
   uchar **content_pp;
}SRYID;

/*--------------+
|Local functions|
+--------------*/
static void P_FCT exchange (int,int,void *);
static int  P_FCT compare  (int,int,void *);

/*---------------------------------------------------------------------sa_init-+
|Open a new array.                                                             |
|This must be the first call before to sa_instl a member.                      |
|The length of each item is passed by parameter.                               |
|A descriptor is returned, to be used by subsequent sa_instl                   |
+-----------------------------------------------------------------------------*/
void * P_FCT sa_init(
   GA_P gbla_p,
   uint length,
   int (P_FCT * compf)(uchar *, uchar *, GA_P))
{
   SRYID *sryid_p;

   sryid_p = (SRYID *)malloc(sizeof(SRYID));
   sryid_p->gbla_p = gbla_p;
   sryid_p->count = -1;
   sryid_p->length = length;
   sryid_p->compf = compf;
   sryid_p->content_pp=(uchar **)malloc(sizeof(uchar **)*(sryid_p->max=INCRT));
   return((void *)sryid_p);
}

/*--------------------------------------------------------------------sa_instl-+
|Install a new element.                                                        |
+-----------------------------------------------------------------------------*/
void P_FCT sa_instl(register void *sryid_p, uchar *content_p)
{
   GA_P gbla_p = ((SRYID *)sryid_p)->gbla_p;
   int i;

   if ((i = ++(((SRYID *)sryid_p)->count)) >= ((SRYID *)sryid_p)->max) {
      ((SRYID *)sryid_p)->content_pp =
      (uchar **)realloc(
         ((SRYID *)sryid_p)->content_pp,(
            sizeof(uchar **) * (
               ((SRYID *)sryid_p)->max += INCRT
            )
         )
      );
   }
   memcpy(
      (
         *(((SRYID *)sryid_p)->content_pp + i) =
         (uchar *)malloc(
            ((SRYID *)sryid_p)->length
         )
      ),
      content_p,
      ((SRYID *)sryid_p)->length
   );
}

/*STATIC--------------------------------------------------------------exchange-+
|Exchange (for wqsort)                                                         |
+-----------------------------------------------------------------------------*/
static void P_FCT exchange(int ix1, int ix2, void *a_p)
{
#define sryid_p ((SRYID *)a_p)  /* to avoid casts */
   uchar *content_p;

   content_p = *(sryid_p->content_pp + ix1);
   *(sryid_p->content_pp + ix1) = *(sryid_p->content_pp + ix2);
   *(sryid_p->content_pp + ix2) = content_p;
#undef sryid_p
}

/*STATIC---------------------------------------------------------------compare-+
|Compare (for wqsort)                                                          |
+-----------------------------------------------------------------------------*/
static int P_FCT compare(int ix1, int ix2, void *a_p)
{
#define sryid_p ((SRYID *)a_p)  /* to avoid casts */
   return(
      (*(sryid_p->compf))(
         *(sryid_p->content_pp+ix1),
         *(sryid_p->content_pp+ix2),
         sryid_p->gbla_p
      )
   );
#undef sryid_p
}

/*---------------------------------------------------------------------sa_term-+
|Terminate: create and return the array                                        |
+-----------------------------------------------------------------------------*/
uchar * P_FCT sa_term(void *sryid_p, uint *count_p)
{
   GA_P gbla_p = ((SRYID *)sryid_p)->gbla_p;
   uchar *c_p, *d_p;
   uchar **c_pp, **d_pp;        /* array of content pointers */
   uint  length;
   int   count;

   length = ((SRYID *)sryid_p)->length;
   count = *count_p = ((SRYID *)sryid_p)->count + 1;

   if (((SRYID *)sryid_p)->compf) {
      wqsort(count,compare,exchange,sryid_p);
   }
   c_pp = d_pp = ((SRYID *)sryid_p)->content_pp;
   free((SRYID *)sryid_p);
   c_p = d_p = (uchar *)malloc(count * length);
   while (count--) {
      memcpy(c_p,*c_pp,length);
      c_p += length;
      free(*c_pp++);
   }
   free(d_pp);
   return(d_p);
}
/******************************************************************************/
