/*******************************************************************************
* 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 / DTD compiler                                       *
* STATUS           = Version 0, Release 1, Level 34 and up                     *
* COMPONENT NAME   = odtsref.c                                                 *
* DESCRIPTIVE NAME = Handles SHORTREF and USEMAP MD                            *
* DATE_WR          = 07/06/1988                                                *
* AUTHOR           = Pierre G. Richard - PETRUS at YKTVMX                      *
*                                                                              *
* FUNCTIONAL DESCRIPTION =                                                     *
*                                                                              *
* IMPLEMENTATION NOTE =                                                        *
*                                                                              *
* DEPENDENCIES =  (see Include list)                                           *
*                                                                              *
* IMPORT=                                                                      *
*                                                                              *
* EXPORT=                                                                      *
*                                                                              *
* CHANGE HISTORY =                                                             *
* Number Date     Inits    Change & Reason (brief)                             *
*      1 10/20/89 PETRUS   Fixed overflow in srm_p area for INVSREF name       *
*      2 01/08/93 PGR      Reference count on SNODE required for safe free     *
*******************************************************************************/

/*-------------+
|Include Files |
+-------------*/
#include "machine.h"
#include "portable.h"
#include "yaspapi.h"
#include "global.h"
#include "usrlib.h"
#include "sgml.h"
#include "hash.h"
#include "odt.h"

/*--------------+
|Local Functions|
+--------------*/
static void P_FCT install_mgi (void STACK_BASED *);

/*--------------------------------------------------------------------srf_mpty-+
|Create an empty sr map (done at init time).                                   |
|The empty map is treated like any other, except that there is no declaration  |
|entered -- no <!SHORTREF #EMPTY>.                                             |
|Do not confuse an EMPTY map (that can be activated: <!USEMAP #EMPTY...)       |
|with no map activated !                                                       |
|There is a "real" address for the empty map (vs. no map activated == (SRM *)0)|
|There is also a name (an empty string, but it exists !)                       |
+-----------------------------------------------------------------------------*/
void P_FCT srf_mpty(COMMON_P M_p)
{
   GA_P gbla_p = M_p->gbla_p;
   SNODE *snode_p;
   uchar name[1];

   name[0]='\0';
   snode_p = (SNODE *)ehsh_lnk(M_p->srm_scope,name,sizeof(SNODE));
   ++M_p->nbr_of_srmap;
   snode_p->u.srm_p = (SRM *)zalloc(GA(sr_max) * sizeof(SRM));
}

/*--------------------------------------------------------------------srf_sdec-+
|Decode a new shortref map.                                                    |
|                                                                              |
|Enter here when SHORTREF has been decoded,                                    |
|Returns with curr_char (supposed to ) == MDC                                  |
|                                                                              |
|This routine build an address list with as many entries as shortref.          |
|The adresses of the mapped shortref point the name of the entities they       |
|are related to.  All shortref not mapped have NULL adresses.                  |
|When all the prolog will have been parsed (and therefore all entities set),   |
|this list will be scanned again and the entities solved.                      |
|                                                                              |
|[150] short reference mapping declaration = mdo, "SHORTREF",                  |
|                   ps+, map name,                                             |
|                   (ps+, parameter literal, ps+, name)+,                      |
|                   ps*, mdc                                                   |
|                                                                              |
|[151] map name = name                                                         |
|                                                                              |
+-----------------------------------------------------------------------------*/
void P_FCT srf_sdec(COMMON_P M_p)
{
   GA_P gbla_p = M_p->gbla_p;
   SNODE *snode_p;
   SRM   *srm_p;
   EQTK  *ch_p;
   uchar name[NAMELEN_MAX+1], *c_p, *name_p;
   int sr_nmbr;

   /*-------------------+
   |Decode shortmap name|
   +-------------------*/
   skip_Wps(gbla_p);
   if (GA(curr_token) != NOT_FOUND_TK) {
      errorh(gbla_p,NONAME,ERH_T_SEV+ERH_LOCATE);
   }
   get_name(gbla_p,name);
   snode_p = (SNODE *)ehsh_lnk(M_p->srm_scope,name,sizeof(SNODE));
   if (snode_p->u.srm_p) {
      errorh(gbla_p,DUPSRMD,ERH_W_SEV+ERH_LOCATE);
   }else {
      ++M_p->nbr_of_srmap;
   }
   skip_ps(gbla_p);
   srm_p = (SRM *)zalloc((GA(sr_max) *(sizeof(SRM)+NAMELEN+1))
                        + NAMELEN+1);  /* extra room for INVSREF */
   name_p = (uchar *)srm_p + (GA(sr_max) * sizeof(SRM));

   do {                                /* for each mapping */
      /*-----------------------+
      |Decode parameter literal|
      +-----------------------*/
      get_plit(gbla_p, GA(lit_p), FALSE);
      for (
         c_p=(ch_p=GA(srtab))->s.p;
         (*c_p)&&(strcmp(GA(lit_p), c_p));
         c_p=(++ch_p)->s.p
      );
      if (ch_p->token == NOT_FOUND_TK) {
         errorh(gbla_p,INVSREF,ERH_W_SEV+ERH_LOCATE);
         sr_nmbr = -1;
      }else {
         sr_nmbr = (uint)ch_p->token - (uint)SR_first;
      }
      /*------------------------+
      |Decode mapped entity name|
      +------------------------*/
      skip_ps(gbla_p);
      get_enam(gbla_p,name_p);
      if (sr_nmbr != -1) {
         if ((srm_p + sr_nmbr)->name_p) {
            errorh(gbla_p,DUPSREF,ERH_W_SEV+ERH_LOCATE);
         }else {
            (srm_p + sr_nmbr)->name_p = name_p;
            name_p += 1 + strlen(name_p);
         }
      }
   }while (
      (skip_ps(gbla_p)) &&
      ((GA(curr_token)==LIT_TK)||(GA(curr_token)==LITA_TK))
   );

   if (snode_p->u.srm_p) {            /* if duplicate */
      free((uchar *)srm_p);           /* just free (error caught above) */
   }else {
      snode_p->u.srm_p = (SRM *)realloc((uchar *)srm_p,name_p-(uchar *)srm_p);
   }
}

/*STATIC-----------------------------------------------------------install_mgi-+
|Install a (new ?) element type name in the hash tables,                       |
|that will change the current map.                                             |
+-----------------------------------------------------------------------------*/
#define M_p ((COMMON_P)XM_p)
static void P_FCT install_mgi(void STACK_BASED * XM_p)
{
   GA_P gbla_p = M_p->gbla_p;
   uchar name[NAMELEN_MAX+1];
   GI *gi_p;

   get_gi(gbla_p,name);
   gi_p = (GI *)ehsh_lnk(M_p->elt_scope,name,sizeof(GI));
   if (gi_p->snode_p) {                      /* already switching to a map */
      errorh(gbla_p,DUPSRU,ERH_I_SEV+ERH_LOCATE);   /* is ignored */
   }else {
      gi_p->snode_p = M_p->snode_p;
      ++(M_p->snode_p->ref_cnt);
   }
}
#undef M_p

/*--------------------------------------------------------------------srf_udec-+
|Decode a shortref map use in the Document Type Declaration.                   |
|                                                                              |
|Enter here when USEMAP has been decoded,                                      |
|Returns with curr_char (supposed to ) == MDC                                  |
|                                                                              |
|[152] short reference use declaration = mdo, "USEMAP",                        |
|                   ps+, map specification,                                    |
|                   (ps+, associated element type)?, <= one at least in DTD    |
|                   ps*, mdc                                                   |
|                                                                              |
|[153] map specification = map name | (rni,"EMPTY")                            |
|                                                                              |
+-----------------------------------------------------------------------------*/
void P_FCT srf_udec(COMMON_P M_p)
{
   GA_P gbla_p = M_p->gbla_p;
   uchar name[NAMELEN_MAX+1];

   /*--------------+
   |Decode map name|
   +--------------*/
   skip_ps(gbla_p);                /* 10/30/90: no ambiguity created if no ps */
   if (GA(curr_token) == RNI_TK) {
      chk_gnam(gbla_p,GA(gnwdtab).EMPTY.s.p);
      name[0] = '\0';
   }else {
      if (GA(curr_token) != NOT_FOUND_TK) {
         errorh(gbla_p,NONAME,ERH_T_SEV+ERH_LOCATE);
      }
      get_name(gbla_p,name);             /* get the name */
   }
   M_p->snode_p = (SNODE *)ehsh_lnk(M_p->srm_scope,name,sizeof(SNODE));

   /*-----------------------------+
   |Decode associated element type|
   +-----------------------------*/
   skip_ps(gbla_p);                /* 10/30/90: no ambiguity created if no ps */
   switch (GA(curr_token)) {
   case GRPO_TK:
      get_nmgp(gbla_p,install_mgi,M_p); /* these gis associated with a map */
      break;
   case NOT_FOUND_TK:
      install_mgi(M_p);                 /* this gi associated with a map */
      break;
   default:
      errorh(gbla_p,NOASSELT,ERH_W_SEV+ERH_LOCATE);
      return;                           /* If at MDC, recovery is possible */
   }
   skip_ps(gbla_p);
}

/*---------------------------------------------------------------------srf_bld-+
|Build short reference table from the SNODE structure.                         |
+-----------------------------------------------------------------------------*/
#define M_p ((COMMON_P)XM_p)
void P_FCT srf_bld(void STACK_BASED * XM_p, EHSH *ehsh_p)
{
   GA_P gbla_p = M_p->gbla_p;
   SNODE *snode_p;
   SRM   *srm_p;
   ETY   *ety_p;
   uint    sr_nmbr;
   uchar *name_p;

   snode_p = (SNODE *)(ehsh_p->var_p);

   if (!snode_p->u.srm_p) {                     /* Used, but no mapping found */
      errorh(gbla_p,NOSRM,ERH_W_SEV,ehsh_p->name_p);   /* tell user, */
      ehsh_p->var_p = (void *)0;                /* remove from shsh table */
      snode_p->u.ix = -1;                       /* and discard it */
      /*-------------------------------+
      |snode_p is not freed NOW:       |
      |it can still be used by a GI.   |
      |Do it later when scanning GIs ! |
      +-------------------------------*/
   }else {
      srm_p = M_p->srm_p;
      srm_p++->mapname.ofs =
      sk_park(gbla_p, ehsh_p->name_p,1+strlen(ehsh_p->name_p));
      M_p->srm_p += GA(sr_max) + 1;
      for (sr_nmbr=0; sr_nmbr < GA(sr_max); ++sr_nmbr) {
         if ((name_p = (snode_p->u.srm_p + sr_nmbr)->name_p) != (uchar *)0) {
            if (!(ety_p = (ETY *)ehsh_fnd(GA(gety_scope),name_p))) {
               errorh(gbla_p,NOSRETY,ERH_W_SEV,ehsh_p->name_p,name_p);
               (srm_p + sr_nmbr)->ix = -1;
            }else {
               /*-----------------------------------------------------+
               |If an associated gety does exist, replace the name ptr|
               |by the value of its index entry in the ETY array      |
               |This assumes build_ety has been done.                 |
               +-----------------------------------------------------*/
               (srm_p + sr_nmbr)->ix = ety_p->val.ext._.ety_ix;
            }
         }else {
            (srm_p + sr_nmbr)->ix = -1;
         }
      }
      free(snode_p->u.srm_p);                        /* dont need it no more */
      /* Warning: snode_p->ix and snode_p->srm_p are a same field ! */
      snode_p->u.ix = diffptr(srm_p, M_p->srm_orig); /* for GIs srm pointer */
   }
}
#undef M_p
/******************************************************************************/
