/*******************************************************************************
* 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   = ocsmin.c                                                  *
* DESCRIPTIVE NAME = A minimal OCS to start parsing any Syntax                 *
* DATE_WR          = 08/20/1987                                                *
* AUTHOR           = Pierre G. Richard - PETRUS at YKTVMX                      *
*                                                                              *
* FUNCTIONAL DESCRIPTION =                                                     *
* Load a minimal OCS.                                                          *
* Also, define some SGML invariants (see OCSMIN.H):                            *
*      ALWDTAB alwdtab     : All SGML keywords                                 *
*      uchar *capnames     : Capacity Names                                    *
*      uchar *qntynames    : Quantity Names                                    *
*      DLMV   dlmv_tab[]   : Coded table to build delimiter                    *
*      DDLMV  ddlmv_tab[]  : Coded table to build delimiter                    *
*      ISO_banner          : "ISO 8879..."                                     *
*                                                                              *
* IMPLEMENTATION NOTE =                                                        *
*                                                                              *
* DEPENDENCIES =  (see Include list)                                           *
*                                                                              *
* IMPORT=                                                                      *
*                                                                              *
* EXPORT=                                                                      *
*                                                                              *
* CHANGE HISTORY =                                                             *
* Number Date     Inits    Change & Reason (brief)                             *
*      1 02/14/89 PETRUS   Dynamic Quantities                                  *
*      2 07/16/89 PETRUS   _loadds for Dynamic Link Library                    *
*      3 12/15/89 PETRUS   More independant, use the system ctype table        *
*      4 03/07/91 PETRUS   INI_MODE more appropriate than CON_MODE             *
*      5 12/14/91 PETRUS   ALWD lists all ISO keywords and replaces SGWD       *
*******************************************************************************/

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

/*-------------------------+
|Local functions and types |
+-------------------------*/
#define MAXFNCR        4           /* RE, RS, SPACE, TAB */
#define LIT_PCL_COUNT  3           /* |"|'|&|   */
#define MD_PCL_COUNT   4           /* |"|'|-|>| */
#define INI0_PCL_COUNT 1           /* |<| */
#define INI1_PCL_COUNT 1           /* |!| */
#define INI2_PCL_COUNT 2           /* |-|>| */

typedef struct t_BUNCH {   /* for all the mallocated storage we need */
   uchar  lit_pcl[LIT_PCL_COUNT + 1];
   uchar  md_pcl[MD_PCL_COUNT + 1];
   uchar  ini_pcl[INI2_PCL_COUNT + 1];
   DV     lit_dvtab[LIT_PCL_COUNT + 1];
   DV     md_dvtab[MD_PCL_COUNT + 1];
   DV     ini_dvtab[INI0_PCL_COUNT+1 + INI1_PCL_COUNT+1 + INI2_PCL_COUNT+1];
   FNCR   fncrtab[MAXFNCR];
}BUNCH;

static void _loadds LP_FCT sub_load_minocs(GLOBAL_AREA *, BUNCH *);


#if defined(IBMCSET2)
/*DEFINED---------------------------------------------------------is..., to...-+
| Character classification functions                                           |
| For IBMCSET2:                                                                |
| 1) To be able to run anywhere, YASP.DLL is compiled with:                    |
|    /Rn  (do not use CSET/2 run-time environment), and                        |
|    /Gd- (do not dynamically call the run-time library)                       |
|                                                                              |
| 2) _ctype.h is a table used when char-classification are macros.             |
|    BUT: _ctype.h is unresolved when /Rn /Gd- is in use!                      |
|                                                                              |
| Before the SubSystem/SAA library (dde4nbs.lib) had FUNCTIONS                 |
| for islower, isupper, isdigit and toupper.  Alas...                          |
+-----------------------------------------------------------------------------*/
#define isupper(c) (((c) >= 'A' && (c) <= 'Z') ? TRUE : FALSE)
#define islower(c) (((c) >= 'a' && (c) <= 'z') ? TRUE : FALSE)
#define isdigit(c) (((c) >= '0' && (c) <= '9') ? TRUE : FALSE)
#define toupper(c) (c - ('a' - 'A'))

#else
/*DEFINED---------------------------------------------------------is..., to...-+
| For all other system, just use the regular functions.                        |
+-----------------------------------------------------------------------------*/
#include <ctype.h>
#endif

/*--------------------------------------------------------------------min_load-+
| Most of the data are constants                                               |
| We need to use an imbedded _loadds function in OS2, because ds belongs to    |
| the caller.                                                                  |
+-----------------------------------------------------------------------------*/
void * P_FCT min_load(GA_P gbla_p)
{
   BUNCH *D_p;

   D_p = (BUNCH *)zalloc(sizeof(BUNCH));   /* use caller data pointer */
   sub_load_minocs((GLOBAL_AREA *)gbla_p,D_p);
   return(D_p);
}

/*STATIC-------------------------------------------------------sub_load_minocs-+
| Build a minimal OCS based on the system character set                        |
| Return a pointer to a mallocated area that can be freed after the            |
| real OCS has been loaded.                                                    |
|                                                                              |
| Three minimal dvtab will be built, for LITP_MODE, MD_MODE, and INI_MODE.     |
|  in LITP_MODE: only LIT, LITA, and CRO will be recognized                    |
|  in MD_MODE:   only LIT, LITA, COM, and MDC will be recognized               |
|  in INI_MODE:  only STAGO, MDO, MDO_COM, MDO_MDC will be recognized          |
|                                                                              |
| The final dvtable will look like: (except the pcl is sorted on the           |
|                                                     system character set)    |
|      (*---------------LITP_MODE----------------*)                            |
|      {         3<<8,  0          , "\"\'&"     },                            |
|      {            0,  LIT_TK     , NULL_STRING },                            |
|      {            0,  LITA_TK    , NULL_STRING },                            |
|      {            0,  CRO_TK     , "#"         },                            |
|      (*----------------MD_MODE-----------------*)                            |
|      {         4<<8,  0          , "\"\'->"    },                            |
|      {            0,  LIT_TK     , NULL_STRING },                            |
|      {            0,  LITA_TK    , NULL_STRING },                            |
|      {            0,  COM_TK     , "-"         },                            |
|      {            0,  MDC_TK     , NULL_STRING },                            |
|      (*---------------INI_MODE-----------------*)                            |
|      {         1<<8,  0          , "<"         },                            |
|      {   +---(DV *),  0          , NULL_STRING },                            |
|          |                                                                   |
|      {   +-->  1<<8,  STAGO_TK   , "!"         },                            |
|      {   +---(DV *),  0          , NULL_STRING },                            |
|          |                                                                   |
|      {   +-->  2<<8,  MDO_TK     , "->"        },                            |
|      {            0,  MDO_COM_TK , "-"         },                            |
|      {            0,  MDO_MDC_TK , NULL_STRING }                             |
|                                                                              |
+-----------------------------------------------------------------------------*/
#define NULL_STRING  ((uchar *)(st.iso_bnr + (sizeof(st.iso_bnr)-1)))
static void _loadds LP_FCT sub_load_minocs(GLOBAL_AREA *gbla_p, BUNCH *D_p)
{
   uint   i;
   ushort *i_p;
   uchar *lit_c_p, *md_c_p, *ini_c_p, *c_p, **c_pp;
   DV    *lit_dv_p, *md_dv_p, *ini_dv_p;
   FNCR  *fncr_p;
   GNWD  *gnwd_p;

   /*-----------------------------------+
   |Establish addressability of         |
   |SGML constants thru the Global Area |
   +-----------------------------------*/
   GA(alwdtab_p) = &alwdtab;
   GA(dlmv_tab)  = dlmv_tab;  /* coded table to build the delimiters */
   GA(ddlmv_tab) = ddlmv_tab; /* coded table to build the combined delimiters */
   GA(qnty_names) = (uchar const **)st.qnty_names;
   GA(cap_names)  = (uchar const **)st.cap_names;
   GA(cap_names)  = (uchar const **)st.cap_names;
   GA(ISO_banner) = (uchar *)st.iso_bnr;

   GA(fncr_max) = MAXFNCR;
   GA(fncrtab) = fncr_p = D_p->fncrtab;
   SET_BITON(GA(opt).ot,GENERAL_CASE_OT);
   /* SET_BITOFF(GA(opt).ot,ENTITY_CASE_OT); **not used** */
   memcpy((uchar *)GA(qntytab),(uchar *)st.qntytab,sizeof(QNTYTAB));
   memcpy((uchar *)GA(cappoint),(uchar *)cap_points,sizeof(GA(cappoint)));

   /*----------------+
   |Build the DS tab |
   +----------------*/
   GA(dstab)[COM_ix].p  = (uchar *)st.aCOM;
   GA(dstab)[CRO_ix].p  = (uchar *)st.aCRO;
   GA(dstab)[LIT_ix].p  = (uchar *)st.aLIT;
   GA(dstab)[LITA_ix].p = (uchar *)st.aLITA;
   GA(dstab)[MDC_ix].p  = (uchar *)st.aMDC;
   GA(dstab)[MDO_ix].p  = (uchar *)st.aMDO;
   GA(dstab)[REFC_ix].p = (uchar *)st.aREFC;

   /*-------------------------------------+
   |Initialize primary nodes in min dvtab |
   +-------------------------------------*/
   lit_dv_p = GA(dvtbent)[LITP_MODE].dv_p = D_p->lit_dvtab;
   lit_dv_p->i.h.is_bseq = FALSE;
   lit_dv_p->i.h.count = LIT_PCL_COUNT;
   lit_c_p = (lit_dv_p->s.str = D_p->lit_pcl) - 1;
/* *lit_dv_p->t.token = 0; */

   md_dv_p = GA(dvtbent)[MD_MODE].dv_p = D_p->md_dvtab;
   md_dv_p->i.h.is_bseq = FALSE;
   md_dv_p->i.h.count = MD_PCL_COUNT;
   md_c_p = (md_dv_p->s.str = D_p->md_pcl) - 1;
/* *md_dv_p->t.token = 0; */

   GA(dltab)['<'] = INI_MO;
   ini_dv_p = GA(dvtbent)[INI_MODE].dv_p = D_p->ini_dvtab;
   ini_dv_p->i.h.count = INI0_PCL_COUNT;         /* (1) */
   ini_dv_p->s.str = (uchar *)st.aMDO;           /* "<" */

   ++ini_dv_p;
   ini_dv_p->i.next = ini_dv_p + 1;
   ini_dv_p->s.str = NULL_STRING;

   (++ini_dv_p)->i.h.count = INI1_PCL_COUNT;     /* (1) */
   ini_dv_p->t.tk = STAGO_TK;
   ini_dv_p->s.str = (uchar *)st.aMDO + 1;       /* "!" */

   ++ini_dv_p;
   ini_dv_p->i.next = ini_dv_p + 1;
   ini_dv_p->s.str = NULL_STRING;

   (++ini_dv_p)->i.h.count = INI2_PCL_COUNT;
   ini_dv_p->t.tk = MDO_TK;
   ini_c_p = (ini_dv_p->s.str = D_p->ini_pcl) - 1;    /* will be |-|>| */

   /*-----------------+
   |Build the GNWDTAB |
   +-----------------*/
   i=sizeof(GNWDTAB)/sizeof(GNWD);
   for (gnwd_p=(GNWD *)&GA(gnwdtab),c_pp=(uchar **)st.gnwd_names;i--;++gnwd_p) {
      gnwd_p->s.p = *c_pp++;
   }

   /*---------------------------------------------------------+
   |Build gtype, uctab, dltab, dvtab (pcl and secondary nodes)|
   |                                                          |
   |The shunned chars in the reference concrete syntax are:   |
   |CONTROLS + 0-31, 127, 255;                                |
   |Also in ISO 8879-1986 note 1, p50 states these shunned    |
   |char are "character set" independant.                     |
   +---------------------------------------------------------*/
   for (i=0, c_p=GA(uctab), i_p=GA(gtype); i < MAX_CHARSET; ++i, ++c_p, ++i_p) {
      if (islower(i)) {           /* system charset dependent */
         *i_p = S_LETTER | S_NMSTRT;
         *c_p = (uchar)toupper(i);
      }else if (isupper(i)) {
         *i_p = S_LETTER | S_NMSTRT;
         *c_p = (uchar)i;
      }else if (isdigit(i)) {
         *i_p = S_DIGIT;
         *c_p = (uchar)i;         /* upper is the same */
      }else {
         *c_p = (uchar)i;         /* set uctab anyway */
         switch (i) {             /* need to do it this way: a pcl is sorted */
         default:
            *i_p = S_NONSGML;     /* can be changed later */
            break;
         case '\"':               /* LIT */
         case '\'':               /* LITA */
            GA(dltab)[i] = LITP_MO | MD_MO;
            *(++lit_c_p) = *(++md_c_p) = (uchar)i;
            (++lit_dv_p)->t.tk=(++md_dv_p)->t.tk=(i == '\"') ? LIT_TK : LITA_TK;
            lit_dv_p->s.str = md_dv_p->s.str = NULL_STRING;
            break;
         case '&':                /* CRO */
            GA(dltab)[i] = LITP_MO;
            *(++lit_c_p) = (uchar)i;
            (++lit_dv_p)->t.tk = CRO_TK;
            lit_dv_p->s.str = (uchar *)st.aCRO + 1;      /* "#" */
            break;
         case '-':                /* COM */
            GA(dltab)[i] = MD_MO;
            *(++md_c_p) = (uchar)i;
            (++md_dv_p)->t.tk = COM_TK;
            md_dv_p->s.str = (uchar *)st.aCOM + 1;       /* "-" */
            *(++ini_c_p) = (uchar)i;
            (++ini_dv_p)->t.tk = MDO_COM_TK;
            ini_dv_p->s.str = (uchar *)st.aCOM + 1;
            break;
         case '>':                /* MDC */
            GA(dltab)[i] = MD_MO;
            *(++md_c_p) = (uchar)i;
            (++md_dv_p)->t.tk = MDC_TK;
            md_dv_p->s.str = NULL_STRING;
            *(++ini_c_p) = (uchar)i;
            (++ini_dv_p)->t.tk = MDO_MDC_TK;
            ini_dv_p->s.str = NULL_STRING;
            break;
         }
      }
   }

   /*--------------------------------------+
   |Build the FNCR tab, complete the gtype |
   +--------------------------------------*/
   fncr_p->s.p = (uchar *)st.gRE+1;
   fncr_p->fctcls = RE_FCTCLS;
   GA(RE_char) = (uchar)(fncr_p->ch_nb = '\r');
   (++fncr_p)->s.p = (uchar *)st.gRS+1;
   fncr_p->fctcls = RS_FCTCLS;
   GA(RS_char) = (uchar)(fncr_p->ch_nb = '\n');
   (++fncr_p)->s.p = (uchar *)st.gSPACE+1;
   fncr_p->fctcls = SPACE_FCTCLS;
   GA(SPACE_char) = (uchar)(fncr_p->ch_nb = ' ');
   (++fncr_p)->s.p = (uchar *)st.sTAB+1;
   fncr_p->fctcls = SEPCHAR_FCTCLS;
   fncr_p->ch_nb = '\t';
   GA(gtype)[' ']  = S_SSPCHAR;
   GA(gtype)['\n'] = S_SSPCHAR;
   GA(gtype)['\r'] = S_SSPCHAR;
   GA(gtype)['\t'] = S_SEPCHAR;
   GA(gtype)['_']  = S_NMCHAR;
   GA(gtype)['.']  = S_NMCHAR | S_SPECIAL;
   GA(gtype)['<']  = S_SGML;
   GA(gtype)['!']  = S_SGML;
   GA(gtype)['\"'] = S_SGML;
   GA(gtype)['\''] = S_SPECIAL;
   GA(gtype)['&']  = S_SGML;
   GA(gtype)['-']  = S_SPECIAL;
   GA(gtype)['>']  = S_SGML;
   GA(gtype)['#']  = S_SGML;
   GA(gtype)['%']  = S_SGML;
   GA(gtype)['(']  = S_SPECIAL;
   GA(gtype)[')']  = S_SPECIAL;
   GA(gtype)['*']  = S_SGML;
   GA(gtype)['+']  = S_SPECIAL;
   GA(gtype)[',']  = S_SPECIAL;
   GA(gtype)['/']  = S_SPECIAL;
   GA(gtype)[':']  = S_SPECIAL;
   GA(gtype)[';']  = S_SGML;
   GA(gtype)['=']  = S_SPECIAL;
   GA(gtype)['?']  = S_SPECIAL;
   GA(gtype)['@']  = S_SGML;
   GA(gtype)['[']  = S_SGML;
   GA(gtype)[']']  = S_SGML;
   GA(gtype)['{']  = S_SGML;
   GA(gtype)['|']  = S_SGML;
   GA(gtype)['}']  = S_SGML;
   GA(gtype)['~']  = S_SGML;
   GA(gtype)['^']  = S_SGML;
}
/******************************************************************************/
