/*******************************************************************************
* SMP00 Sample of an SGML Application Interfaced with the YASP Parser          *
*------------------------------------------------------------------------------*
* Written 1987 - 1993 by                                                       *
*         Pierre G. Richard                                                    *
*         IBM T.J. Watson Research Center                                      *
*         Yorktown Heights, New York                                           *
*         petrus@watson.ibm.com                                                *
*-----------------------------------------------------------------------------*
* FUNCTION NAME    = YASP / Application                                       *
* STATUS           = N/A                                                      *
* COMPONENT NAME   = smp00.c                                                  *
* DESCRIPTIVE NAME = Application sample                                       *
* DATE_WR          = 01/07/1990                                               *
* AUTHOR           = Pierre G. Richard - PETRUS at YKTVMX                     *
*                                                                             *
* FUNCTIONAL DESCRIPTION =                                                    *
*                                                                             *
* CHANGE HISTORY =                                                            *
******************************************************************************/

/*-------------+
|Include Files |
+-------------*/
#include "gendef.h"
#include "yaspapi.h"
#include "server.h"
#include "keeper.h"
#include "show.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

/*-----------------+
|Exported Functions|
+-----------------*/
extern uint C_FCT main (int, char **);

/*------------+
|Exported Data|
+------------*/
char *G_pri_fn;                        /* non reentrant */
char *G_ocs_fn;                        /* non reentrant */
boolean G_compil = FALSE;              /* default to production mode */
ulong G_curr_mem = 0;                  /* Current size of memory allocated */
ulong G_peak_mem = 0;                  /* Peak memory allocated */

/*---------+
|Local Data|
+---------*/
#define SEPOPT '/'                     /* Option separator on command line */
#define SGML_BANNER \
"\nAn SGML System Conforming to\nInternational Standard ISO 8879\
 --\nStandard Generalized Markup Language\n\n"

static uchar TERM_NM[] = "TERMINAL";   /* Terminal name */
static uchar PRIM_NM[] = "#PRIMARY";   /* Primary entity name */
static uchar CATALOG_NM[] = "CATALOG"; /* SGML Open CATALOG file name */
static uchar ACTIVE_LPD_PI[] = "yasp-active-lpd:";
static time_t starttime;               /* Timing: when we started (/V0) */
static short  verbose_level = 2;
static ulong yasp_rvl;                 /* rrvvll (Release, Version, Level) */

/*---------------+
|Local Functions |
+---------------*/
static int      C_FCT dispatch       (PAC *);
static boolean  initarg        (int, char **);
static void     interpret_pi   (PAC *);
static void     usage          (void);
static void     usage_notif    (void);
static void     usage_verbose  (void);
static void     display_tag_notif(DED *, boolean);
static void     ntf_stg        (PAC *);
static void     ntf_etg        (PAC *);
static void     ntf_data       (PAC *);
static void     ntf_map        (PAC *);
static void     ntf_re         (PAC *);
static void     ntf_pi         (PAC *);
static void     ntf_nsgml      (PAC *);
static void     ntf_ety        (PAC *);
static void     ntf_sdecst     (PAC *);
static void     ntf_bopro      (PAC *);
static void     ntf_dtdst      (PAC *);
static void     ntf_dtdnd      (PAC *);
static void     ntf_ltdst      (PAC *);
static void     ntf_ltdnd      (PAC *);
static void     ntf_eopro      (PAC *);
static void     ntf_eodoc      (PAC *);
static int      ntf_eodap      (PAC *);
static void     ntf_sr         (PAC *);
static void     ntf_skip       (PAC *);
static void     ntf_etyst      (PAC *);
static void     ntf_etynd      (PAC *);
static void     ntf_etydclst   (PAC *);
static void     ntf_etydclnd   (PAC *);
static void     ntf_notdclst   (PAC *);
static void     ntf_notdclnd   (PAC *);
static void     ntf_eltdclst   (PAC *);
static void     ntf_eltdclnd   (PAC *);
static void     ntf_atleltdclst(PAC *);
static void     ntf_atleltdclnd(PAC *);
static void     ntf_atlnotdclst(PAC *);
static void     ntf_atlnotdclnd(PAC *);
static void     services_query (PAC *, uchar *);
static void     services_capa  (PAC *);
static void     services_dlm   (PAC *);
static void     tell_position  (PAC *);

/*------------------------------------------------------------------------main-+
|Application - MAIN                                                            |
+-----------------------------------------------------------------------------*/
uint C_FCT main(int argc, char **argv)
{
   static PAC pac = { PAC_IDENTIFIER };
   uint rc;

   if (strcmp(PACID, PAC_IDENTIFIER)) {
      printf("Mismatch in PAC versions.  YASP: \"%s\", Appl: \"%s\"\n",
             PACID, PAC_IDENTIFIER);
      return(10);
   }
   if (initarg(argc,argv)) {
      yasp_rvl = *(((ulong *)PARSID)-1);
      pac.ase = dispatch; /* address of Services and Notification Dispatcher */
      pac.user_p = sr_init(G_compil, G_pri_fn, G_ocs_fn, TERM_NM, CATALOG_NM);
      printf(PARSID+1);
      printf(SGML_BANNER);
      if (!verbose_level) time(&starttime);
      rc = PRSMAIN(&pac);
      sr_term(pac.user_p);
      if (!verbose_level) {
         printf("RC=%d - elapsed=%ld secs\n", rc, time(NULL) - starttime);
         printf("Peak memory=%luK\n", G_peak_mem/1024);
         if (G_curr_mem) printf("Remains %lu to free", G_curr_mem);
      }
   }else {
      rc = 4;
   }
   return(rc);
}

/*STATIC-----------------------------------------------------------------usage-+
|Explain how to use this program                                               |
+-----------------------------------------------------------------------------*/
static void usage()
{
   static char *msg[] = {
      "----------------------------------------------------------------",
      "Usage: SMP00 [options] [file]",
      "",
      "    file: name of file to be parsed, default to TERMINAL",
      " options: /C compilation mode (default is production mode)",
      "          /H displays this help text",
      "          /Sname uses the OCS file \"name.ocs\"",
      "          /Vn sets the verbose level to \"n\" (0, 1, 2, 3, 4, or 5)",
      "              (default is V2, try V? for an explanation)",
      "",
      "Purpose: sample of a YASP application which displays YASP notifications",
      "and its associated data (ALL notifications for a verbose level of 4.)",
      "Specific PI's have been implemented to furnish more information",
      "during the parsing of the document; enter \"<\?\?>\" to get a list.",
      "",
      "Ending terminal entry depends of the Operating System:",
      "try Ctl-Z, $(EOF) or press F1.",
      "----------------------------------------------------------------"
   };
   char **c_pp;
   uint count;

   for (c_pp=msg, count=sizeof(msg)/sizeof(char *); count--; ++c_pp) {
      printf("%s\n",*c_pp);
   }
}

/*STATIC-----------------------------------------------------------usage_notif-+
|Explain special notifications                                                 |
+-----------------------------------------------------------------------------*/
static void usage_notif()
{
   static char *msg[] = {
      "",
      "-------------+--------------------------------------------------",
      "    Enter:   | To:",
      "-------------+--------------------------------------------------",
      " <?>         | display SMP00 usage",
      " <\?\?>        | display this help text",
      " <?1>        | show the model you are working in",
      " <?2>        | show the current document structure",
      " <?3command> | pass a system command",
      " <?4...>     | query for miscellaneous values (\"<?4?>\" for help)",
      " <?5>        | display a summary on current capacities reached",
      " <?6>        | show the concrete delimiter strings.",
   };
   char **c_pp;
   uint count;

   printf(PARSID+1);
   count=sizeof(msg)/sizeof(char *);
   if (yasp_rvl < 127L) count -= 1; /* avoid to print the last line */
   for (c_pp=msg; count--; ++c_pp) {
      printf("%s\n",*c_pp);
   }
   printf("%s\n",*msg);             /* print first line again (separator) */
}

/*STATIC---------------------------------------------------------usage_verbose-+
|Explain what the verbose-level's doing                                        |
+-----------------------------------------------------------------------------*/
static void usage_verbose()
{
   static char *msg[] = {
      "",
      "Verbose levels:",
      "---------+------------------------------------------------------",
      "Level of | Means",
      "---------+------------------------------------------------------",
      "      0  | Say nothing, just parse, indicate ressources used",
      "      1  | Issue error messages, interpret specific PIs",
      "Def-> 2  | + Tell STG, ETG, DATA, RE, PI, NSGML, N/S/CDATA entit.",
      "      3  | + SDECST, BOPRO, DTDST, DTDND, EOPRO, EODOC",
      "      4  | + User's usemaps, Shortrefs, Skipped data,",
      "         |   position of all events on input",
      "      5  | + all entities starting and ending"
   };
   char **c_pp;
   uint count;

   count=sizeof(msg)/sizeof(char *);
   for (c_pp=msg; count--; ++c_pp) {
      printf("%s\n",*c_pp);
   }
   printf("%s\n",*msg);             /* print first line again (separator) */
}

/*STATIC---------------------------------------------------------------initarg-+
|Decode the /options and parameters on the command line                        |
+-----------------------------------------------------------------------------*/
static boolean initarg(int argc, char **argv)
{
   uint prm_pos;
   uchar *c_p;
   boolean bad_syntax = FALSE;

   G_ocs_fn = (uchar *)0;
   prm_pos = 0;                 /* count for positional parm */
   while (--argc) {
      if (*(c_p = *++argv) == SEPOPT) {
         switch(*++c_p) {      /* keywords parm */
         case 'h':
         case 'H':
            usage();
            break;
         case 'c':
         case 'C':
            G_compil = TRUE;
            break;
         case 's':
         case 'S':
            if (!(*++c_p)) {
               printf("A name must follow the S option: option discarded\n");
            }else {
               if (strlen(c_p) > 8) c_p[8] = '\0'; /* truncate */
               G_ocs_fn = c_p;
            }
            break;
         case 'v':
         case 'V':
            switch (*++c_p) {
            case '0': verbose_level= 0;  break;
            case '1': verbose_level= 1;  break;
            case '?': usage_verbose();
            case '2': verbose_level= 2;  break;
            case '3': verbose_level= 3;  break;
            case '4': verbose_level= 4;  break;
            default:  printf("Invalid verbose level: defaulted to V5\n");
            case '5': verbose_level= 5;  break;
            }
            break;
         default :
            bad_syntax = TRUE;
            break;
         }
      }else {
         switch(++prm_pos) {                /* Positional parms */
         case 1:
            G_pri_fn = c_p;                 /* get the file name */
            break;
         default:
            bad_syntax = TRUE;              /* no more than 1 allowed */
            break;
         }
      }
   }
   if (bad_syntax) {                        /* send explanations */
      usage();
      return(FALSE);
   }else {
      if (!prm_pos) G_pri_fn = TERM_NM;     /* default to TERMINAL */
      return(TRUE);
   }
}

/*STATIC--------------------------------------------------------------dispatch-+
|Application Services and Notifications dispatcher                             |
+-----------------------------------------------------------------------------*/
static int C_FCT dispatch(PAC *pac_p)
{
   switch(pac_p->func) {
   case SGET_PFC:    if ((!verbose_level) &&      /* Count dynamic memory */
                        ((G_curr_mem += (uint)pac_p->stg.len) > G_peak_mem)) {
                        G_peak_mem = G_curr_mem;
                     }
                     return(sr_allo(pac_p));
   case SFRE_PFC:    if (!verbose_level) G_curr_mem -= (uint)pac_p->stg.len;
                     return(sr_free(pac_p));
   case MSG_PFC:     if (!verbose_level) {       /* /V0: don't tell errors */
                        return (pac_p->errsev==ERH_T_SEV) ? 10 : 0;
                     }
                     return(sr_msg(pac_p,pac_p->user_p));
   case FIND_PFC:    return(sr_find(pac_p,pac_p->user_p));
   case XENOP_PFC:   return(sr_xenop(pac_p,pac_p->user_p));
   case XENRD_PFC:   return(sr_xenrd(pac_p,pac_p->user_p));
   case XENCL_PFC:   return(sr_xencl(pac_p,pac_p->user_p));
   case XENGP_PFC:   return(sr_xengp(pac_p,pac_p->user_p));
   case XENSP_PFC:   return(sr_xensp(pac_p,pac_p->user_p));
   case UTOPR_PFC:   return(sr_utopr(pac_p));
   case UTRD_PFC:    return(sr_utrd(pac_p));
   case UTOPW_PFC:   return(sr_utopw(pac_p));
   case UTWRT_PFC:   return(sr_utwrt(pac_p));
   case UTCL_PFC:    return(sr_utcl(pac_p));
   case ELTST_PFC:   if (verbose_level >= 1) ntf_stg(pac_p);    break;
   case ELTND_PFC:   if (verbose_level >= 1) ntf_etg(pac_p);    break;
   case TEXT_PFC:    if (verbose_level >= 1) ntf_data(pac_p);   break;
   case MAP_PFC:     if (verbose_level >= 1) ntf_map(pac_p);    break;
   case RE_PFC:      if (verbose_level >= 1) ntf_re(pac_p);     break;
   case PI_PFC:      if (verbose_level >= 1) ntf_pi(pac_p);     break;
   case NSGML_PFC:   if (verbose_level >= 2) ntf_nsgml(pac_p);  break;
   case ETY_PFC:     if (verbose_level >= 2) ntf_ety(pac_p);    break;
   case DECST_PFC:   if (verbose_level >= 3) ntf_sdecst(pac_p); break;
   case PROST_PFC:   if (verbose_level >= 3) ntf_bopro(pac_p);  break;
   case DTDST_PFC:   if (verbose_level >= 3) ntf_dtdst(pac_p);  break;
   case DTDND_PFC:   if (verbose_level >= 3) ntf_dtdnd(pac_p);  break;
   case LTDST_PFC:   if (verbose_level >= 3) ntf_ltdst(pac_p);  break;
   case LTDND_PFC:   if (verbose_level >= 3) ntf_ltdnd(pac_p);  break;
   case PROND_PFC:   if (verbose_level >= 3) ntf_eopro(pac_p);  break;
   case DOCND_PFC:   if (verbose_level >= 3) ntf_eodoc(pac_p);  break;
   case DAPND_PFC:   return(ntf_eodap(pac_p));
   case SR_PFC:      if (verbose_level >= 4) ntf_sr(pac_p);     break;
   case SKIP_PFC:    if (verbose_level >= 4) ntf_skip(pac_p);   break;
   case ETYST_PFC:   if (verbose_level >= 5) ntf_etyst(pac_p);  break;
   case ETYND_PFC:   if (verbose_level >= 5) ntf_etynd(pac_p);  break;
   case ETYDCLST_PFC: if (verbose_level >= 5) ntf_etydclst(pac_p); break;
   case ETYDCLND_PFC: if (verbose_level >= 5) ntf_etydclnd(pac_p); break;
   case NOTDCLST_PFC: if (verbose_level >= 5) ntf_notdclst(pac_p); break;
   case NOTDCLND_PFC: if (verbose_level >= 5) ntf_notdclnd(pac_p); break;
   case ELTDCLST_PFC: if (verbose_level >= 5) ntf_eltdclst(pac_p); break;
   case ELTDCLND_PFC: if (verbose_level >= 5) ntf_eltdclnd(pac_p); break;
   case ATLELTDCLST_PFC: if (verbose_level >= 5) ntf_atleltdclst(pac_p); break;
   case ATLELTDCLND_PFC: if (verbose_level >= 5) ntf_atleltdclnd(pac_p); break;
   case ATLNOTDCLST_PFC: if (verbose_level >= 5) ntf_atlnotdclst(pac_p); break;
   case ATLNOTDCLND_PFC: if (verbose_level >= 5) ntf_atlnotdclnd(pac_p); break;
   default:
      printf("*** Function %d not implemented\n",pac_p->func);
      break;
   }
   return(0);
}

/*STATIC----------------------------------------------------------interpret_pi-+
|Some "specials" PI (beginning with a digit) are interpreted to show           |
|(and debug) the internal structure.                                           |
+-----------------------------------------------------------------------------*/
static void interpret_pi(PAC *pac_p)
{
   uchar *pi_lit = pac_p->dad.p;

   switch(*pi_lit) {
   case '\0': usage();                                       break;
   case '?' : usage_notif();                                 break;
   case '1' : show_elt(kep_qcur());                          break;
   case '2' : kep_show();                                    break;
   case '3' : printf("RC=%d\n",system((char *)pi_lit+1));    break;
   case '4' : services_query(pac_p,pi_lit+1);                break;
   case '5' : services_capa(pac_p);                          break;
   case '6' : services_dlm(pac_p);                           break;
   default:
      if ((!strncmp(pi_lit, ACTIVE_LPD_PI, sizeof(ACTIVE_LPD_PI) - 1)))  {
         uchar *c1_p = pi_lit + (sizeof(ACTIVE_LPD_PI)-1);
         uint rlen = pac_p->dad.len - (sizeof(ACTIVE_LPD_PI)-1);
         uchar *c2_p;

         for (;;) {
            while ((rlen)&&(*++c1_p == ' ')) --rlen;  /* skip leading blanks */
            if (!rlen) break;
            c2_p = c1_p + 1;
            while ((--rlen)&&(*c2_p != ' ')) ++c2_p;  /* skip trailing blanks */
            pac_p->dad.p = c1_p;
            pac_p->dad.len = c2_p - c1_p;
            pac_p->psf = ALINK_PSF;
            pac_p->pse(pac_p);
            c1_p = c2_p;
         }
      }
      break;
   }
}

/*STATIC-----------------------------------------------------display_tag_notif-+
|Display a line indicating a tag notification was received                     |
+-----------------------------------------------------------------------------*/
static void display_tag_notif(DED *ded_p, boolean is_start_tag)
{
   uchar *c_p, *d_p, *e_p, *f_p;

   c_p = is_start_tag? "Start" : "End";
   switch (ded_p->tagmin) {
   case NET_ST_MNF:    d_p = "NET-enabling Start-tag";  break;
   case EMPTY_ST_MNF:  d_p = "Empty Start-tag";         break;
   case UNCL_ST_MNF:   d_p = "Unclosed Start-tag";      break;
   case NULL_ET_MNF:   d_p = "NULL End-tag";            break;
   case EMPTY_ET_MNF:  d_p = "Empty End-tag";           break;
   case UNCL_ET_MNF:   d_p = "Unclosed End-tag";        break;
   case NO_MNF:        d_p = NULL;                      break;
   case DATA_ET_MNF:   d_p = "Data End-tag";            break;
   default:            d_p = "????";                    break;
   }
   if (!(ded_p->is & IMP_LF)) {
      if (!d_p) {
         printf("=> %s %s", c_p, ded_p->elt_p->name.p);
      }else {
         printf("=> %s %s (%s)", c_p, ded_p->elt_p->name.p, d_p);
      }
   }else {
      switch (ded_p->impldby) {
      case DOC_IMF:
         e_p = "start of document instance set";
         f_p = NULL;
         break;
      case DATA_IMF:
         e_p = "data";
         f_p = NULL;
         break;
      case STG_IMF:
         e_p = "start-tag: \"";
         f_p = ded_p->by_elt_p->name.p;
         break;
      case ETG_IMF:
         e_p = "end-tag: \"";
         f_p = ded_p->by_elt_p->name.p;
         break;
      case EDTG_IMF:
         e_p = "end-datatag: \"";
         f_p = ded_p->by_elt_p->name.p;
         break;
      case EOF_IMF:
         e_p = "end of entity";
         f_p = NULL;
         break;
      default:
         e_p = "????";
         f_p = NULL;
         break;
      }
      if (!d_p) {
         if (!f_p) {
            printf(
               "=> %s %s (Implied by %s)",
               c_p, ded_p->elt_p->name.p, e_p
            );
         }else {
            printf(
               "=> %s %s (Implied by %s%s\")",
               c_p, ded_p->elt_p->name.p, e_p, f_p
            );
         }
      }else {
         if (!f_p) {
            printf(
               "=> %s %s (%s, implied by %s)",
               c_p, ded_p->elt_p->name.p, d_p, e_p
            );
         }else {
            printf(
               "=> %s %s (%s, implied by %s%s\")",
               c_p, ded_p->elt_p->name.p, d_p, e_p, f_p
            );
         }
      }
   }
   if ((verbose_level >= 4) && (ded_p->srm_p)) {
      char *mapname = (ded_p->srm_p-1)->mapname.p;
      printf(". SHORTREF map is: %s", *mapname ? mapname : "#EMPTY");
   }
}

/*STATIC---------------------------------------------------------------ntf_stg-+
|Start Tag                                                                     |
+-----------------------------------------------------------------------------*/
static void ntf_stg(PAC *pac_p)
{
   DED  *ded_p = pac_p->dad.p;

   kep_elt(ded_p->elt_p, (boolean)(ded_p->tagmin==NET_ST_MNF));
   if (verbose_level >= 2) {
      display_tag_notif(ded_p, TRUE);      /* TRUE: it's a start-tag */
      tell_position(pac_p);
      show_avs(ded_p->atd_p,10);
      /* we don't care about ded_p->is */
   }
}

/*STATIC---------------------------------------------------------------ntf_etg-+
|End Tag                                                                       |
+-----------------------------------------------------------------------------*/
static void ntf_etg(PAC *pac_p)
{
   DED  *ded_p = pac_p->dad.p;

   kep_end();
   if (verbose_level >= 2) {
      display_tag_notif(ded_p, FALSE);     /* FALSE: it's an end-tag */
      tell_position(pac_p);
      if (ded_p->atd_p) show_avs(ded_p->atd_p,10); /* AVS of REGION end-tag */
   }
}

/*STATIC--------------------------------------------------------------ntf_data-+
|Report DATA                                                                   |
+-----------------------------------------------------------------------------*/
static void ntf_data(PAC *pac_p)
{
   kep_data(pac_p->dad.len);
   if (verbose_level >= 2) {
      printf("=> Data |%.*s|",pac_p->dad.len,pac_p->dad.p);
      tell_position(pac_p);
   }
}

/*STATIC---------------------------------------------------------------ntf_map-+
|A USEMAP has been found in document instance                                  |
+-----------------------------------------------------------------------------*/
static void ntf_map(PAC *pac_p)
{
   SRM *srm_p = (SRM *)pac_p->dad.p;
   char *mapname;

   kep_map(srm_p);
   if (verbose_level >= 4) {
      mapname = (srm_p-1)->mapname.p;
      printf("--- Map \"%s\" activated",*mapname ? mapname : "#EMPTY");
      tell_position(pac_p);
   }
}

/*STATIC----------------------------------------------------------------ntf_re-+
|Record End                                                                    |
+-----------------------------------------------------------------------------*/
static void ntf_re(PAC *pac_p)
{
   if (verbose_level >= 2) {
      printf("=> Record End");
      tell_position(pac_p);
   }
}

/*STATIC----------------------------------------------------------------ntf_PI-+
|Processing Instruction                                                        |
+-----------------------------------------------------------------------------*/
static void ntf_pi(PAC *pac_p)
{
   if (verbose_level >= 2) {
      printf("=> PI |%.*s|",pac_p->dad.len,pac_p->dad.p);
      tell_position(pac_p);
   }
   interpret_pi(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_nsgml-+
|Non SGML character                                                            |
+-----------------------------------------------------------------------------*/
static void ntf_nsgml(PAC *pac_p)
{
   char c = *((char *)pac_p->dad.p);

   printf("=> Non-SGML character found: [%02x]",c);
   tell_position(pac_p);
}

/*STATIC---------------------------------------------------------------ntf_ety-+
|An entity must be processed by the application.                               |
+-----------------------------------------------------------------------------*/
static void ntf_ety(PAC *pac_p)
{
   ETY *ety_p = pac_p->dad.p;

   printf("=> ENTITY");
   tell_position(pac_p);
   show_ety(ety_p,10);             /* incnt */
}

/*STATIC------------------------------------------------------------ntf_sdecst-+
|Beginning of SGML Declaration                                                 |
+-----------------------------------------------------------------------------*/
static void ntf_sdecst(PAC *pac_p)
{
   printf("--- SGML Declaration Started");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_bopro-+
|Beginning of Prolog                                                           |
+-----------------------------------------------------------------------------*/
static void ntf_bopro(PAC *pac_p)
{
   printf("--- Prolog Started");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_dtdst-+
|Beginning of a DTD                                                            |
+-----------------------------------------------------------------------------*/
static void ntf_dtdst(PAC *pac_p)
{
   printf("--- DTD Started");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_dtdnd-+
|End of a DTD                                                                  |
+-----------------------------------------------------------------------------*/
static void ntf_dtdnd(PAC *pac_p)
{
   printf("--- DTD Ended for document type name: \"%s\"", pac_p->dad.p);
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_ltdst-+
|Beginning of a LPD                                                            |
+-----------------------------------------------------------------------------*/
static void ntf_ltdst(PAC *pac_p)
{
   printf("--- LPD Started");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_ltdnd-+
|End of a LPD                                                                  |
+-----------------------------------------------------------------------------*/
static void ntf_ltdnd(PAC *pac_p)
{
   printf("--- LPD Ended for link type name: \"%s\"", pac_p->dad.p);
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_eopro-+
|Beginning of Prolog                                                           |
+-----------------------------------------------------------------------------*/
static void ntf_eopro(PAC * pac_p)
{
   printf("--- Prolog Ended for element: \"%s\"",((ELT *)pac_p->dad.p)->name.p);
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_eodoc-+
|End of Document                                                               |
+-----------------------------------------------------------------------------*/
static void ntf_eodoc(PAC *pac_p)
{
   printf("--- End of Document");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_eodap-+
|End of Document right After Prolog                                            |
+-----------------------------------------------------------------------------*/
static int ntf_eodap(PAC *pac_p)
{
   if (verbose_level >= 3) {
      printf("--- End of Document right After Prolog - Ending YASP");
      tell_position(pac_p);
   }
   return(END_RESUME_RC);        /* To end silently */
}

/*STATIC----------------------------------------------------------------ntf_sr-+
|A mapped SHORTREF has been found                                              |
+-----------------------------------------------------------------------------*/
static void ntf_sr(PAC *pac_p)
{
   SRM *srm_p = pac_p->dad.p;
   int sr_id = pac_p->dad.len;

   printf(
      "--- Found shortref #%d, mapped to entity \"%s\" in map \"%s\"",
      sr_id + 1,
      (srm_p[sr_id].ety_p) ? (srm_p[sr_id].ety_p)->name.p : "(unknown)",
      (srm_p-1)->mapname.p
   );
   tell_position(pac_p);
}

/*STATIC--------------------------------------------------------------ntf_skip-+
|Report SKIPPED DATA                                                           |
+-----------------------------------------------------------------------------*/
static void ntf_skip(PAC *pac_p)
{
   uchar *c_p;

   switch (pac_p->sdc) {
   case COMMENT_SDC:
      c_p = "Comment";
      break;
   case ERROR_SDC:
      c_p = "Error";
      break;
   case MSINCL_SDC:
      c_p = "Marked Section INCLUDE or TEMP";
      break;
   case MSIGN_SDC:
      c_p = "Marked Section IGNORE (and Close)";
      break;
   case MSCDATA_SDC:
      c_p = "Marked Section CDATA";
      break;
   case MSRCDATA_SDC:
      c_p = "Marked Section RCDATA";
      break;
   case MSC_SDC:
      c_p = "Marked Section Close";
      break;
   case MDOMDC_SDC:
      c_p = "Null comment";
      break;
   default:
      c_p = "Unknown code";
   }
   printf("=> Skipped Data: %s", c_p);
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_etyst-+
|An new entity is about to be read                                             |
+-----------------------------------------------------------------------------*/
static void ntf_etyst(PAC *pac_p)
{
   printf(
      "--- Entity: \"%s\" started",
      ((ETY *)pac_p->dad.p)->name.p ? ((ETY *)pac_p->dad.p)->name.p : PRIM_NM
   );
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------------ntf_etynd-+
|Current entity is finished                                                    |
+-----------------------------------------------------------------------------*/
static void ntf_etynd(PAC *pac_p)
{
   printf(
      "--- Entity: \"%s\" ended",
      ((ETY *)pac_p->dad.p)->name.p ? ((ETY *)pac_p->dad.p)->name.p : PRIM_NM
   );
   if (pac_p->oeb_p) {
      printf(
         " - \"%s\" resumed",
         (pac_p->oeb_p->ety_p)->name.p ? (pac_p->oeb_p->ety_p)->name.p : PRIM_NM
      );
   }
   tell_position(pac_p);
}

/*STATIC----------------------------------------------------------ntf_etydclst-+
|ENTITY Declaration started                                                    |
+-----------------------------------------------------------------------------*/
static void ntf_etydclst(PAC *pac_p)
{
   printf("--- ENTITY Declaration started\n");
   tell_position(pac_p);
}

/*STATIC----------------------------------------------------------ntf_etydclnd-+
|ENTITY Declaration ended                                                      |
+-----------------------------------------------------------------------------*/
static void ntf_etydclnd(PAC *pac_p)
{
   ETY *ety_p = (ETY *)pac_p->dad.p;
    
   printf("--- ENTITY Declaration ended\n");
   tell_position(pac_p);
   printf("=> ENTITY");
   show_ety_dcl(ety_p,10);
}

/*STATIC----------------------------------------------------------ntf_notdclst-+
|NOTATION Declaration started                                                  |
+-----------------------------------------------------------------------------*/
static void ntf_notdclst(PAC *pac_p)
{
   printf("--- NOTAION Declaration started\n");
   tell_position(pac_p);
}

/*STATIC----------------------------------------------------------ntf_notdclnd-+
|NOTATION Declaration ended                                                    |
+-----------------------------------------------------------------------------*/
static void ntf_notdclnd(PAC *pac_p)
{
   NCB *ncb_p = (NCB *)pac_p->dad.p;
    
   printf("--- NOTATION Declaration ended\n");
   tell_position(pac_p);
   printf("=> NOTATION");
   show_ncb_dcl(ncb_p,12);
}

/*STATIC----------------------------------------------------------ntf_eltdclst-+
|ELEMENT Declaration started                                                   |
+-----------------------------------------------------------------------------*/
static void ntf_eltdclst(PAC *pac_p)
{
   printf("--- ELEMENT Declaration started\n");
   tell_position(pac_p);
}

/*STATIC----------------------------------------------------------ntf_eltdclnd-+
|ELEMENT Declaration ended                                                     |
+-----------------------------------------------------------------------------*/
static void ntf_eltdclnd(PAC *pac_p)
{
   ushort i = 1 + pac_p->dad.len;
   ELT *elt_p = (ELT *)pac_p->dad.p;

   printf("--- ELEMENT Declaration ended\n");
   tell_position(pac_p);
   printf("=> ELEMENT(S)");
   while (--i) {
      show_elt_dcl(elt_p++);
   }
   printf("\n");
}

/*STATIC-------------------------------------------------------ntf_atleltdclst-+
|ATTLIST Declaration for element(s) started                                    |
+-----------------------------------------------------------------------------*/
static void ntf_atleltdclst(PAC *pac_p)
{
   printf("--- ATTLIST Declaration for element(s) started\n");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------ntf_atleltdclnd-+
|ATTLIST Declaration for element(s) ended                                      |
+-----------------------------------------------------------------------------*/
static void ntf_atleltdclnd(PAC *pac_p)
{
   ushort i = 1 + pac_p->dad.len;
   ELT *elt_p = (ELT *)pac_p->dad.p;

   printf("--- ATTLIST Declaration for element(s) ended\n");
   tell_position(pac_p);
   printf("=> For element(s) ");
   while (--i) {
      printf("%s, ", (elt_p++)->name.p);
   }
   printf("list of defined attributes");
   sb_show_ad(((ELT *)pac_p->dad.p)->atd.p);
}

/*STATIC-------------------------------------------------------ntf_atlnotdclst-+
|ATTLIST Declaration for element(s) started                                    |
+-----------------------------------------------------------------------------*/
static void ntf_atlnotdclst(PAC *pac_p)
{
   printf("--- ATTLIST Declaration for notation(s) started\n");
   tell_position(pac_p);
}

/*STATIC-------------------------------------------------------ntf_atlnotdclnd-+
|ATTLIST Declaration for notation(s) ended                                      |
+-----------------------------------------------------------------------------*/
static void ntf_atlnotdclnd(PAC *pac_p)
{
   ushort i = 1 + pac_p->dad.len;
   NCB *ncb_p = (NCB *)pac_p->dad.p;

   printf("--- ATTLIST Declaration for notation(s) ended\n");
   tell_position(pac_p);
   printf("=> For notation(s) ");
   while (--i) {
      printf("%s, ", (ncb_p++)->exid.name.p);
   }
   printf("list of defined attributes");
   sb_show_ad(((NCB *)pac_p->dad.p)->atd.p);
}

/******************************************************************************/
/*                                                                            */
/*                    P A R S E R     S E R V I C E S                         */
/*                                                                            */
/******************************************************************************/

/*STATIC-------------------------------------------------------services_query-+
|                                                                             |
+----------------------------------------------------------------------------*/
static void services_query(PAC *pac_p, uchar *c_p)
{
   int rc;

   switch (*c_p++) {
   case '<':
      if (*c_p) {
         pac_p->psf = QOPT_PSF;
         pac_p->pse(pac_p);
         if (((OPT *)(pac_p->dad.p))->ot & GENERAL_CASE_OT) {
            /* strupr is not standard */
            uchar *d_p = c_p - 1;
            while (*++d_p) *d_p = (uchar)(toupper(*d_p));
         }
         pac_p->psf = QELT_PSF;
         pac_p->dad.p = c_p;
         pac_p->pse(pac_p);
         if (!pac_p->dad.p) {
            printf("\n-----\"%s\": no such element\n",c_p);
         }else {
            show_elt((ELT *)pac_p->dad.p);
         }
      }else {
         pac_p->psf = QLELT_PSF;
         pac_p->pse(pac_p);
         {
            ELT *elt_p = (ELT *)pac_p->dad.p;
            ushort i = 1 + pac_p->dad.len;
            while (--i) {
               printf("%s ",(elt_p++)->name.p);
            }
            printf("\n");
         }
      }
      break;
   case '$':                      /* NOTATION */
      if (*c_p) {
         pac_p->psf = QOPT_PSF;
         pac_p->pse(pac_p);
         if (((OPT *)(pac_p->dad.p))->ot & GENERAL_CASE_OT) {
            /* strupr is not standard */
            uchar *d_p = c_p - 1;
            while (*++d_p) *d_p = (uchar)(toupper(*d_p));
         }
         pac_p->psf = QNOTA_PSF;
         pac_p->dad.p = c_p;
         if ((rc=pac_p->pse(pac_p)) == 0) {
            if (!pac_p->dad.p) {
               printf("\n-----\"%s\": no such notation\n",c_p);
            }else {
               show_ncb((NCB *)pac_p->dad.p, 0);
            }
         }else {
            printf("RC=%d\n",rc);
         }
      }else {
         pac_p->psf = QLNOTA_PSF;
         if ((rc=pac_p->pse(pac_p)) == 0) {
            NCB *ncb_p = (NCB *)pac_p->dad.p;
            ushort i = 1 + pac_p->dad.len;
            while (--i) {
               printf("%s ",(ncb_p++)->exid.name.p);
            }
            printf("\n");
         }else {
            printf("RC=%d\n",rc);
         }
      }
      break;
   case '&':
      if (*c_p) {
         pac_p->psf = QOPT_PSF;
         pac_p->pse(pac_p);
         if (((OPT *)(pac_p->dad.p))->ot & ENTITY_CASE_OT) {
            /* strupr is not standard */
            uchar *d_p = c_p - 1;
            while (*++d_p) *d_p = (uchar)(toupper(*d_p));
         }
         pac_p->psf = QGETY_PSF;
         pac_p->dad.p = c_p;
         pac_p->pse(pac_p);
         show_ety((ETY *)pac_p->dad.p,0);
      }else {
         pac_p->psf = QLGETY_PSF;
         if ((rc=pac_p->pse(pac_p)) == 0) {
            ETY *ety_p = (ETY *)pac_p->dad.p;
            ushort i = 1 + pac_p->dad.len;
            while (--i) {
               printf("%s ",(ety_p++)->name.p);
            }
            printf("\n");
         }else {
            printf("RC=%d\n",rc);
         }
      }
      break;
   case '%':
      if (*c_p) {
         pac_p->psf = QPETY_PSF;
         pac_p->dad.p = c_p;
         pac_p->pse(pac_p);
         show_ety((ETY *)pac_p->dad.p,0);
      }else {
         pac_p->psf = QLPETY_PSF;
         pac_p->pse(pac_p);
         {
            ETY *ety_p = (ETY *)pac_p->dad.p;
            ushort i = 1 + pac_p->dad.len;
            while (--i) {
               printf("%s ",(ety_p++)->name.p);
            }
            printf("\n");
         }
      }
      break;
   case 'w':          /* Where are we ? */
   case 'W':
      printf("Current location is:\n");
      {
         OEB *oeb_p;

         for (oeb_p=pac_p->oeb_p; oeb_p; oeb_p = *(OEB **)(oeb_p + 1)) {
            if (oeb_p->ety_p->is & EXTERNAL_EF) {
               printf(
                  "\tin external entity \"%s\", row %d, col %d, info \"%s\"\n",
                  oeb_p->ety_p->name.p ? oeb_p->ety_p->name.p : PRIM_NM,
                  oeb_p->row, oeb_p->col, oeb_p->appl_info
               );
            }else {
               if (oeb_p->ety_p->name.p) {
                  printf(
                     "\tin internal entity \"%s\", offset %d\n",
                     oeb_p->ety_p->name.p, oeb_p->col
                  );
               }else {
                  printf(
                     "\tin literal, at offset %d\n", oeb_p->col
                  );
               }
            }
         }
      }
      break;
   case 's':
   case 'S':
      pac_p->psf = QSR_PSF;
      pac_p->pse(pac_p);
      show_sr(pac_p->dad.len, (SRTBE *)(pac_p->dad.p));
      break;
   case 'f':
   case 'F':
      pac_p->psf = QFCT_PSF;
      pac_p->pse(pac_p);
      show_fct(pac_p->dad.len, (FNCR *)(pac_p->dad.p));
      break;
   case 'q':
   case 'Q':
      pac_p->psf = QQTY_PSF;
      pac_p->pse(pac_p);
      show_qty((uint *) (pac_p->dad.p));
      break;
   case 'o':
   case 'O':
      pac_p->psf = QOPT_PSF;
      pac_p->pse(pac_p);
      show_opt((OPT *) (pac_p->dad.p));
      break;
   default:
      printf("*** Invalid query ***\n");
      /* Fall thru */
   case '?':
      printf(
         "Enter:      | to query:\n"
         "------------+-------------------------------\n"
         "<?4w>       | the current location\n"
         "<?4s>       | the ShortRef Strings\n"
         "<?4f>       | the Function Characters\n"
         "<?4q>       | the declared Quantities\n"
         "<?4o>       | the enabled Options / Features\n"
         "<?4<[name]> | an element-name\n"
         "<?4&[name]> | a general entity\n"
         "<?4%%[name]> | a parameter entity\n"
         "<?4$[name]> | a notation\n"
      );
      break;
   }
}

/*STATIC--------------------------------------------------------services_capa-+
|                                                                             |
+----------------------------------------------------------------------------*/
static void services_capa(PAC *pac_p)
{
   void *arr_ptr[3];

   pac_p->dad.p = arr_ptr;
   pac_p->psf = QCAPA_PSF;
   pac_p->pse(pac_p);
   show_cap((ulong *)arr_ptr[0],(uint *)arr_ptr[1],(ulong *)arr_ptr[2]);
}

/*STATIC---------------------------------------------------------services_dlm-+
|                                                                             |
+----------------------------------------------------------------------------*/
static void services_dlm(PAC *pac_p)
{
   pac_p->psf = QDLM_PSF;
   pac_p->pse(pac_p);
   show_dlm((uchar **)(pac_p->dad.p));
}

/*STATIC---------------------------------------------------------tell_position-+
|Tell the position field in PAC                                                |
+-----------------------------------------------------------------------------*/
static void tell_position(PAC *pac_p)
{
   uchar *c_p;

   if ((yasp_rvl >= 126L) && (verbose_level >= 4)) {
      if (pac_p->pos.ety_p != NULL) {
         c_p = pac_p->pos.ety_p->name.p;
         if (!c_p) c_p = PRIM_NM;
      }else {
         c_p = "(irrelevant)";
      }
      printf(
         "   (l=%d c=%d o=%ld e=%s)",
         pac_p->pos.row, pac_p->pos.col, pac_p->pos.ofs, c_p
      );
   }
   printf("\n");
}
/******************************************************************************/
