/*******************************************************************************
* 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 / CSD compiler                                       *
* STATUS           = Version 0, Release 1, Level 34 and up                     *
* COMPONENT NAME   = ocsname.c                                                 *
* DESCRIPTIVE NAME = SGML declaration keywords recognition                     *
* DATE_WR          = 06/30/1987                                                *
* AUTHOR           = Pierre G. Richard - PETRUS at YKTVMX                      *
*                                                                              *
* FUNCTIONAL DESCRIPTION =                                                     *
*                                                                              *
* Change reserved names according to the NAMES parameter of the                *
* SGML Declaration.  Update implied tables.                                    *
*                                                                              *
* "rf_gnwdtab" is a static table that lists all Reserved Names,                *
* with their reference (default) value.                                        *
* It holds all keywords that may be changed thru the NAMES parameter of the    *
* SGML declaration.                                                            *
*                                                                              *
* It creates "gnwdtab" that contains an updated list of keywords,              *
* and updtates the function <-> character reference table ("fncrtab")          *
* if new function names (RE, RS, SEPCHAR, TAB) are entered.                    *
*                                                                              *
* IMPLEMENTATION NOTE =                                                        *
* "gnname.exe" is an utility that build the C stanzas for                      *
* the rf_gnwdtab list of keywords.                                             *
*                                                                              *
* DEPENDENCIES =  (see Include list)                                           *
*                                                                              *
* IMPORT=                                                                      *
*                                                                              *
* EXPORT=                                                                      *
*                                                                              *
* CHANGE HISTORY =                                                             *
* Number Date     Inits    Change & Reason (brief)                             *
*      1 09/25/88 PETRUS   OCS rebuilt                                         *
*******************************************************************************/

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

/*--------------+
|Local Functions|
+--------------*/
static int LP_FCT dicho (uchar *, GNWD *, int);

/*-----------------------------------------------------------------------dicho-+
| Performs a binary search in an array.  Returns the index or -1 if not found. |
+-----------------------------------------------------------------------------*/
static int LP_FCT dicho(uchar *needle, GNWD *haystack, int num)
{
   int cond, low, mid;

   --num;
   low = 0;                        /* low bound */
   while (low <= num) {
      mid=((uint)low+(uint)num)/2;
      cond = strcmp(needle, (haystack + mid)->s.p);
      if (cond < 0) {
         num = mid - 1;            /* set low range */
      }else if (cond > 0) {
         low = mid + 1;
      }else {                      /* found */
         return(mid);
      }
   }
   return(-1);
}

/*---------------------------------------------------------------------nam_bld-+
|                                                                              |
+-----------------------------------------------------------------------------*/
void P_FCT nam_bld(GA_P gbla_p, GNWDTAB **new_gnwdtab_pp, FNCR *new_fncrtab_p)
{
   uchar   *c_p;
   FCTCLS   fctcls;
   int      i, ofs;
   uchar    name_p[NAMELEN_MAX+1];
   GNWD    *new_gnwd_p, *gnwd_p;
   GNWDTAB *new_gnwdtab_p;
   FNCR    *fncr_p;

   *new_gnwdtab_pp = new_gnwdtab_p = (GNWDTAB *)zalloc(sizeof(GNWDTAB));

   /*--------------------+
   |Check where we are.. |
   +--------------------*/
   chk_gnam(gbla_p,GA(alwdtab_p)->NAMES.s.p);
   skip_Wps(gbla_p);
   chk_gnam(gbla_p,GA(alwdtab_p)->SGMLREF.s.p);
   skip_Wps(gbla_p);

   /*-----------------------+
   |Enter the variant names |
   +-----------------------*/
   for (;;) {
      get_name(gbla_p,name_p);       /* get replaced name */
      i = dicho(name_p, (GNWD *)&GA(gnwdtab), sizeof(GNWDTAB)/sizeof(GNWD));
      if (i == -1) {                 /* not found */
         MSGCODE msgcode;

         if (!strcmp(name_p, GA(alwdtab_p)->QUANTITY.s.p)) break; /* OK */
         i = dicho(name_p, (GNWD *)GA(alwdtab_p), sizeof(ALWDTAB)/sizeof(GNWD));
         if (i == -1) {
            msgcode = NOREFNAM;      /* Not a keyword */
         }else {
            switch (*(((uchar **)(GA(alwdtab_p)))[i]-1)) {
            case SYST_CHARID:
               msgcode = NOVA2NAM;   /* Reserved for the SYSTEM declaration */
               break;
            default:                 /* SGML_CHARID */
               msgcode = NOVANAM;    /* Reserved for the SGML declaration */
               break;
            }
         }
         errorh(gbla_p, msgcode, ERH_W_SEV+ERH_LOCATE, name_p);
         skip_ps(gbla_p);
         get_name(gbla_p,name_p);    /* discard the replacement name */
      }else {
         new_gnwd_p = (GNWD *)new_gnwdtab_p + i;
         if (new_gnwd_p->s.ofs) {    /* name already replaced */
            errorh(
               gbla_p,DUPVANAM,ERH_W_SEV+ERH_LOCATE,
               name_p,sk_point(gbla_p,new_gnwd_p->s.ofs)
            );
            skip_ps(gbla_p);
            get_name(gbla_p,name_p); /* discard the replacement name */
         }else {
            skip_ps(gbla_p);         /* replaced name found and replaceable */
            get_name(gbla_p,name_p); /* get the replacement name */
            i = dicho(
               name_p, (GNWD *)GA(alwdtab_p), sizeof(ALWDTAB)/sizeof(GNWD)
            );
            if (i != -1) {           /* Name is already a keyword */
               errorh(gbla_p,INVRPTNAM,ERH_W_SEV+ERH_LOCATE);
            }else {
               gnwd_p=(GNWD *)new_gnwdtab_p, i = 0;
               for (;;) {
                  if (i == sizeof(GNWDTAB)/sizeof(GNWD)) {
                     new_gnwd_p->s.ofs=sk_park(gbla_p,name_p,1+strlen(name_p));
                     break;
                  }else if ((gnwd_p->s.ofs) &&
                     (!strcmp(name_p,sk_point(gbla_p, gnwd_p->s.ofs)))) {
                     errorh(
                        gbla_p,DUPNAMREP,ERH_W_SEV+ERH_LOCATE,
                        name_p, (((GNWD *)(&GA(gnwdtab))) + i)->s.p
                     );
                     break;
                  }
                  ++i, ++gnwd_p;
               }
            }
         }
      }
      skip_ps(gbla_p);
   }

   /*---------------------------------+
   |Change the FNCR table if required |
   +---------------------------------*/
   for (i=0; i<3; ++i) {
      switch (i) {
      case  0:
         ofs = new_gnwdtab_p->RE.s.ofs;
         fctcls = RE_FCTCLS;
         break;
      case  1:
         ofs = new_gnwdtab_p->RS.s.ofs;
         fctcls = RS_FCTCLS;
         break;
      default:
         ofs = new_gnwdtab_p->SPACE.s.ofs;
         fctcls = SPACE_FCTCLS;
         break;
      }
      if (ofs) {
         fncr_p = new_fncrtab_p -1;
         while ((++fncr_p)->fctcls != fctcls);
         fncr_p->s.ofs = ofs;      /* set the ofs of the new_name */
      }
   }
   /*---------------------------------+
   |Park the unchanged default values |
   +---------------------------------*/
   for (
      i=sizeof(GNWDTAB)/sizeof(GNWD),
      gnwd_p = (GNWD *)&GA(gnwdtab),
      new_gnwd_p=(GNWD *)new_gnwdtab_p;
      i--;
      ++gnwd_p, ++new_gnwd_p) {
      if (!new_gnwd_p->s.ofs) {
         c_p = gnwd_p->s.p;
         new_gnwd_p->s.ofs = sk_park(gbla_p,c_p,1+strlen(c_p));
      }
   }
}
/******************************************************************************/
