/*******************************************************************************
* 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   = show.c                                                   *
* DESCRIPTIVE NAME = Show components of the interface control blocks          *
* DATE_WR          = 09/12/1988                                               *
* AUTHOR           = Pierre G. Richard - PETRUS at YKTVMX                     *
*                                                                             *
* FUNCTIONAL DESCRIPTION =                                                    *
*                                                                             *
* CHANGE HISTORY =                                                            *
* Number Date     Inits    Change & reason (brief)                            *
*      1 06/06/90 DUROT    Packaging                                          *
*      2 06/29/90 PETRUS   Clean-up the code                                  *
*      3 13/12/90 PETRUS   Added descriptor for CDATA attributes              *
*      4 01/10/91 PETRUS   PAC007                                             *
*      4 01/26/91 PETRUS   PAC008 - YASP V1.25                                *
*******************************************************************************/

/*-------------+
|Include Files |
+-------------*/
#include "gendef.h"
#include "yaspapi.h"      /* YASP Application Program Interface */
#include "show.h"
#include "pse.h"          /* Indeces to tables */

#include <stdio.h>        /* Standard I/O */
#include <stdlib.h>       /* Standard Library */
#include <string.h>       /* String manipulation */
#include <ctype.h>

/*--------------+
|Local Functions|
+--------------*/
static uchar  *sb_get_dcl_content  (ELT *);
static void    sb_show_datatag     (DTP *);
static void    sb_show_mdl         (MDL *,uint, int);

#define IS_BITON(i,selec)        ((i) & (selec))

/*STATIC------------------------------------------------------sb_show_datatag-+
|Show a datatag                                                               |
+----------------------------------------------------------------------------*/
static void sb_show_datatag(DTP *dtp_p)
{
   if (! *dtp_p->c_p) {
      printf ("P=(NO PAD) ");
   }else {
      printf("P=\"%s\" ",dtp_p->c_p);
   }
   ++dtp_p;
   do {
      printf("T=\"%s\" ",dtp_p->c_p);
   }while(*(++dtp_p)->c_p);
}

/*-----------------------------------------------------------------sb_show_ad-+
|Show the attlist MD                                                          |
+----------------------------------------------------------------------------*/
void sb_show_ad(ATD *atd_p)
{
   uchar *c_p;

   if (!atd_p) {
      printf("*** NO ATTRIBUTES ***\n");
   }else do {
      switch (atd_p->kind) {
      default:
      case CDATA_AFK:     c_p = "CDATA";      break;
      case ENTITY_AFK:    c_p = "ENTITY";     break;
      case ENTITIES_AFK:  c_p = "ENTITIES";   break;
      case ID_AFK:        c_p = "ID";         break;
      case IDREF_AFK:     c_p = "IDREF";      break;
      case IDREFS_AFK:    c_p = "IDREFS";     break;
      case NAME_AFK:      c_p = "NAME";       break;
      case NAMES_AFK:     c_p = "NAMES";      break;
      case NMTOKEN_AFK:   c_p = "NMTOKEN";    break;
      case NMTOKENS_AFK:  c_p = "NMTOKENS";   break;
      case NOTATION_AFK:  c_p = "NOTATION ";  break;
      case NUMBER_AFK:    c_p = "NUMBER";     break;
      case NUMBERS_AFK:   c_p = "NUMBERS";    break;
      case NUTOKEN_AFK:   c_p = "NUTOKEN";    break;
      case NUTOKENS_AFK:  c_p = "NUTOKENS";   break;
      case GROUP_AFK:     c_p = "";           break;
      }
      printf("\n\tAttribute: %s\n\t\tDeclared: %s", atd_p->name.p, c_p);
      if ((atd_p->kind == GROUP_AFK) || (atd_p->kind == NOTATION_AFK)) {
         printf("(%s)",atd_p->val.lit.p);
      }
      /*---------------------------------*/
      switch (atd_p->defv) {
      case REQUIRED_AFV:  c_p = "#REQUIRED"; break;
      case CURRENT_AFV:   c_p = "#CURRENT";  break;
      case CONREF_AFV:    c_p = "#CONREF";   break;
      case IMPLIED_AFV:   c_p = "#IMPLIED";  break;
      case FIXED_AFV:     c_p = "#FIXED: ";  break;
      case DEFLT_AFV:     c_p = "";          break;
      }
      printf("\n\t\tDefault: %s",c_p);
      if ((atd_p->defv == FIXED_AFV) || (atd_p->defv == DEFLT_AFV)) {
         /* whatever (atd_p->is.listed) or not */
          if IS_BITON(atd_p->is,DESC_AF) {
             ADLEN  *desc_p = atd_p->val.desc.p;
             uint    count = atd_p->val.desc.len;

             printf("(concatenation of):\n");
             for (c_p = (desc_p++)->p; --count; c_p += (desc_p++)->len) {
                printf(
                   "\t\t  %-10s=>\"%.*s\"\n",
                   desc_p->p ? ((ETY *)desc_p->p)->name.p : "#TEXT",
                   desc_p->len,c_p
                );
             }
         }else {
             printf("%.*s",atd_p->val.lit.len,atd_p->val.lit.p);
         }
      }
   }while (!IS_BITON((atd_p++)->is, LAST_AF));
   printf("\n");
}

/*STATIC---------------------------------------------------sb_get_dcl_content-+
|                                                                             |
+----------------------------------------------------------------------------*/
static uchar *sb_get_dcl_content(ELT *elt_p)
{
   if (elt_p->is.any)              return("ANY");
   if (elt_p->is.empty)            return("EMPTY");
   switch (elt_p->is.dcdata) {
   case NONR_DCDATA:               return("CDATA");
   case RPLC_DCDATA:               return("RCDATA");
   default:                        return("");
   }
}

/*STATIC----------------------------------------------------------sb_show_mdl-+
|                                                                             |
+----------------------------------------------------------------------------*/
static void sb_show_mdl(MDL *mdl_p, uint count, int recur_lvl)
{
   uchar *c_p;

   while (count--) {
      switch(mdl_p->occurence) {
      case PLUS_OCCUR: c_p = "(+)"; break;
      case REP_OCCUR:  c_p = "(*)"; break;
      case OPT_OCCUR:  c_p = "(?)"; break;
      default:         c_p = "(1)"; break;
      }
      printf("%*s",3*recur_lvl,c_p);  /* indent 3 blanks per recur_lvl */
      if (mdl_p->connector) {          /* not a leave */
         switch(mdl_p->connector) {
         case SEQ_CONN:  c_p = " SEQ";    break;
         case AND_CONN:  c_p = " AND";    break;
         case OR_CONN:   c_p = " OR";     break;
         default:        c_p = "???????"; break;
         }
         printf("%d tokens %s_connected\n",mdl_p->l.mdl.num,c_p);
         sb_show_mdl(mdl_p+mdl_p->l.mdl.rx,mdl_p->l.mdl.num,recur_lvl+1);
      }else {
         if (mdl_p->is_pcdata) {
            printf("%-10s","#PCDATA");
         }else if (mdl_p->is_datatag) {
            printf("%-10s","DATATAG");
            sb_show_datatag(mdl_p->l.dtp.p);
         }else {
            printf("%-10s %s",
               mdl_p->l.elt.p->name.p, sb_get_dcl_content(mdl_p->l.elt.p));
         }
         printf("\n");
      }
      ++mdl_p;
   }
}

/*-------------------------------------------------------------------show_elt-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_elt(ELT *elt_p)
{
   EX *ex_p;

   if (!elt_p) return;
   printf("\n-----------------------------------%-10s %s",
      elt_p->name.p, sb_get_dcl_content(elt_p));
   if (elt_p->mex.p) {
      printf(" M:");
      ex_p = elt_p->mex.p;
      do {
         printf(" %s ",ex_p->p->name.p);
      }while ((++ex_p)->p);
   }
   if (elt_p->pex.p) {
      printf(" P:");
      ex_p = elt_p->pex.p;
      do {
         printf(" %s ",ex_p->p->name.p);
      }while ((++ex_p)->p);
   }
   printf("\n");
   if (elt_p->srm.p) {
      char *c_p = ((elt_p->srm.p)-1)->mapname.p;
      printf("-- Activates map %s\n",*c_p ? c_p : "#EMPTY");
   }
   if (elt_p->mdl.p) sb_show_mdl(elt_p->mdl.p,1,1);
   sb_show_ad(elt_p->atd.p);
}

/*---------------------------------------------------------------show_elt_dcl-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_elt_dcl(ELT *elt_p)
{
   if (!elt_p) return;
   printf("\n---------------------------------  %-10s %s",
      elt_p->name.p, sb_get_dcl_content(elt_p));
}

/*-------------------------------------------------------------------show_avs-+
| Show a TRUE attribute value specification                                   |
+----------------------------------------------------------------------------*/
void show_avs(ATD *atd_p, ushort incnt)
{
   uchar *c_p;
   ETY **ety_pp;
   uint i;

   if (atd_p) do {
      i = 0;
      if IS_BITON(atd_p->is,LINK_AF)          c_p = "*lnk*";  /* link */
      else if IS_BITON(atd_p->is,BAD_AF)      c_p = "*bad*";  /* bad */
      else if IS_BITON(atd_p->is,EXM_AF)      c_p = "*set*";  /* set */
      else                               i=1, c_p = "*dfl*";  /* default */
      printf(
         "%*.s%s %s%c", incnt," ", c_p,
         atd_p->name.p ? atd_p->name.p : (uchar *)"?",
         IS_BITON(atd_p->is,OMITNAME_AF) ? ':' : '='
      );
      if (i) {
         switch (atd_p->defv) {
         case IMPLIED_AFV:
            printf("(#IMPLIED)\n");
            continue;
         case CONREF_AFV:
            printf("(#CONREF)\n");
            continue;
         default:
            break;
         }
      }
      switch(atd_p->kind) {
      case ENTITIES_AFK:
      case ENTITY_AFK:
         printf("(entit%s):\n", atd_p->kind & 1 ? "ies" : "y");
         ety_pp=atd_p->val.ety.pp;
         i=atd_p->val.ety.count + 1;
         while (--i) {
            show_ety(*(ety_pp++),incnt+10);
         }
         break;
      case NOTATION_AFK:
         show_ncb(atd_p->val.ncb_p, incnt+6);
         break;
      default:
         if (atd_p->val.lit.len != -1) {
            if IS_BITON(atd_p->is,DESC_AF) {
               ADLEN  *desc_p = atd_p->val.desc.p;
               uint    count = atd_p->val.desc.len;

               printf("(concatenation of):\n");
               for (c_p = (desc_p++)->p; --count; c_p += (desc_p++)->len) {
                  printf(
                     "%*.s%-10s=>\"%.*s\"\n",
                     incnt+6+5," ",
                     desc_p->p ? ((ETY *)desc_p->p)->name.p : "#TEXT",
                     desc_p->len,c_p
                  );
               }
            }else {
               printf("%.*s\n",atd_p->val.lit.len,atd_p->val.lit.p);
            }
         }
         break;
      }
   }while (!IS_BITON((atd_p++)->is, LAST_AF));
}

/*-------------------------------------------------------------------show_ety-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_ety(
   ETY *ety_p,
   ushort incnt)     /* indention */
{
   uchar *c_p;

   printf("%*.s",incnt," ");
   if (!ety_p) {
      printf(" *unknown*\n");
   }else {
      switch(ety_p->kind) {
      case TEXT_EFK:     c_p="TEXT";         break;
      case CDATA_EFK:    c_p="CDATA";        break;
      case SDATA_EFK:    c_p="SDATA";        break;
      case PI_EFK:       c_p="PI";           break;
      case STARTTAG_EFK: c_p="STARTTAG";     break;
      case ENDTAG_EFK:   c_p="ENDTAG";       break;
      case MS_EFK:       c_p="MS";           break;
      case MD_EFK:       c_p="MD";           break;
      case NDATA_EFK:    c_p="NDATA";        break;
      case SUBDOC_EFK:   c_p="SUBDOC";       break;
      case SGML_EFK:     c_p="SGML";         break;
      default:           c_p="***?????***";  break;
      }
      printf("\"%s\" type: %s, %sternal %s\n%*.sValue ",
         ety_p->name.p,
         IS_BITON(ety_p->is,PARAMETER_EF) ? "parameter" : "general",
         IS_BITON(ety_p->is,EXTERNAL_EF) ? "ex" : "in",
         c_p,
         incnt+6," "
      );
      if (!IS_BITON(ety_p->is,EXTERNAL_EF)) {
         printf(": \"%.*s\"\n",ety_p->val.lit.len,ety_p->val.lit.p);
      }else {
         NAD *nad_p;
         printf("in \"%s\"\n%*.sInterpreter: ",
            ety_p->val.ext._.exid.p->idhl.p,incnt+6," "
         );
         if ((nad_p = ety_p->val.ext.nad.p) == (NAD *)0) {
            printf("**unknown**\n");
         }else {
            printf("(%s) \"%s\"\n",
               nad_p->ncb.p->exid.name.p,
               nad_p->ncb.p->exid.idhl.p
            );
            show_avs(nad_p->atd.p,incnt+6+10);
         }
      }
   }
}

/*---------------------------------------------------------------show_ety_dcl-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_ety_dcl(
   ETY *ety_p,
   ushort incnt)     /* indention */
{
   uchar *c_p;
   EXID *exid_p = ety_p->val.ext._.exid.p;

   printf("%*.s",incnt," ");
   if (!ety_p) {
      printf(" *unknown*\n");
   }else {
      switch(ety_p->kind) {
      case TEXT_EFK:     c_p="TEXT";         break;
      case CDATA_EFK:    c_p="CDATA";        break;
      case SDATA_EFK:    c_p="SDATA";        break;
      case PI_EFK:       c_p="PI";           break;
      case STARTTAG_EFK: c_p="STARTTAG";     break;
      case ENDTAG_EFK:   c_p="ENDTAG";       break;
      case MS_EFK:       c_p="MS";           break;
      case MD_EFK:       c_p="MD";           break;
      case NDATA_EFK:    c_p="NDATA";        break;
      case SUBDOC_EFK:   c_p="SUBDOC";       break;
      case SGML_EFK:     c_p="SGML";         break;
      default:           c_p="***?????***";  break;
      }
      printf("\"%s\" type: %s, %sternal %s\n%*.sValue ",
         ety_p->name.p,
         IS_BITON(ety_p->is,PARAMETER_EF) ? "parameter" : "general",
         IS_BITON(ety_p->is,EXTERNAL_EF) ? "ex" : "in",
         c_p,
         incnt+6," "
      );
      if (!IS_BITON(ety_p->is,EXTERNAL_EF)) {
         printf(": \"%.*s\"\n",ety_p->val.lit.len,ety_p->val.lit.p);
      }else {
         printf("unknown but in ");
         printf(
            "PUBLIC \"%.*s\" SYSTEM \"%.*s\"\n",
             exid_p->pid.len,
             (uchar *)exid_p->val.p + exid_p->pid.rel,
             exid_p->sid.len,
             (uchar *)exid_p->val.p + exid_p->sid.rel
         );
      }
   }
}

/*-------------------------------------------------------------------show_ncb-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_ncb(NCB *ncb_p, ushort incnt)
{
   printf("(Notation):\n%*.sInterpreter: ",incnt+6," ");
   if (!ncb_p) {
      printf("**unknown**\n");
   }else {
      printf("(%s) ",ncb_p->exid.name.p);
      printf("\"%s\"\n", ncb_p->exid.idhl.p);
      if (ncb_p->exid.is & SOLVED_XF) {   /* FIND_PFC has been issued */
         if (ncb_p->exid.is & INVALID_XF) {
            printf("*unresolved*");
         }else {
            printf("\"%s\"\n", ncb_p->exid.idhl.p);  /* set by FIND_PFC */
         }
      }else {                             /* FIND_PFC has not been issued */
         printf(
            "%.*s %.*s\n",
             ncb_p->exid.pid.len,
             (uchar *)ncb_p->exid.val.p + ncb_p->exid.pid.rel,
             ncb_p->exid.sid.len,
             (uchar *)ncb_p->exid.val.p + ncb_p->exid.sid.rel
         );
      }
      show_avs(ncb_p->atd.p,incnt+6+10);
   }
}

/*---------------------------------------------------------------show_ncb_dcl-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_ncb_dcl(NCB *ncb_p, ushort incnt)
{
   printf(" %s ",ncb_p->exid.name.p);
   printf("\"%s\" ", ncb_p->exid.idhl.p);
   if (ncb_p->exid.is & SOLVED_XF) {   /* FIND_PFC has been issued */
      if (ncb_p->exid.is & INVALID_XF) {
         printf("*unresolved*");
      }else {
         printf("\"%s\"\n", ncb_p->exid.idhl.p);  /* set by FIND_PFC */
      }
   }else {                             /* FIND_PFC has not been issued */
      printf(
         "PUBLIC \"%.*s\" SYSTEM \"%.*s\"\n",
          ncb_p->exid.pid.len,
          (uchar *)ncb_p->exid.val.p + ncb_p->exid.pid.rel,
          ncb_p->exid.sid.len,
          (uchar *)ncb_p->exid.val.p + ncb_p->exid.sid.rel
      );
   }
}

/*-------------------------------------------------------------------show_dlm-+
|                                                                             |
+----------------------------------------------------------------------------*/
void show_dlm(uchar **c_pp)
{
   printf("COM     is %s\n",c_pp[COM_ix]);
   printf("CRO     is %s\n",c_pp[CRO_ix]);
   printf("ERO     is %s\n",c_pp[ERO_ix]);
   printf("ETAGO   is %s\n",c_pp[ETAGO_ix]);
   printf("LIT     is %s\n",c_pp[LIT_ix]);
   printf("LITA    is %s\n",c_pp[LITA_ix]);
   printf("MDC     is %s\n",c_pp[MDC_ix]);
   printf("MDO     is %s\n",c_pp[MDO_ix]);
   printf("MINUS   is %s\n",c_pp[MINUS_ix]);
   printf("PERO    is %s\n",c_pp[PERO_ix]);
   printf("PIC     is %s\n",c_pp[PIC_ix]);
   printf("PIO     is %s\n",c_pp[PIO_ix]);
   printf("REFC    is %s\n",c_pp[REFC_ix]);
   printf("RNI     is %s\n",c_pp[RNI_ix]);
   printf("STAGO   is %s\n",c_pp[STAGO_ix]);
   printf("TAGC    is %s\n",c_pp[TAGC_ix]);
   printf("VI      is %s\n",c_pp[VI_ix]);
   printf("MDO_DSO is %s\n",c_pp[MDO_DSO_ix]);
   printf("MSC_MDC is %s\n",c_pp[MSC_MDC_ix]);
}

/*-------------------------------------------------------------------show_cap-+
| Show current capacities reached                                             |
+----------------------------------------------------------------------------*/
void show_cap(ulong *cnt_p, uint *point_p, ulong *max_p)
{
   static uchar *MSG0 =
       "%6lu entities defined with %lu characters of text.\n";
   static uchar *MSG1 =
       "%6lu data tag patterns defined with %lu characters of text.\n";
   static uchar *MSG2 =
       "%6lu element types defined with %lu model tokens and\n";
   static uchar *MSG3 = "       %lu exception groups with %lu names.\n";
   static uchar *MSG4 =
       "%6lu attributes defined with %lu group members and\n";
   static uchar *MSG5 = "       %lu characters of text.\n";
   static uchar *MSG6 =
       "%6lu IDs and %lu ID references specified.\n";
   static uchar *MSG7 =
       "%6lu data content notations defined with %lu characters of text.\n";
   static uchar *MSG8 =
       "%6lu short reference maps defined with %lu short references in each.\n";
   static uchar *MSG9 =
       "%6lu link defined with %lu names.\n";
   static uchar *MSGA =
       "%6lu capacity points required (%u%% of %lu permitted).\n";
   ulong total;
   int i;

   printf(MSG0,cnt_p[ENTCAP_ix],    cnt_p[ENTCHCAP_ix]);
   printf(MSG1,cnt_p[DTACAP_ix],    cnt_p[DTACHCAP_ix]);
   printf(MSG2,cnt_p[ELEMCAP_ix],   cnt_p[GRPCAP_ix]);
   printf(MSG3,cnt_p[EXGRPCAP_ix],  cnt_p[EXNMCAP_ix]);
   printf(MSG4,cnt_p[ATTCAP_ix],    cnt_p[AVGRPCAP_ix]);
   printf(MSG5,cnt_p[ATTCHCAP_ix]);
   printf(MSG6,cnt_p[IDCAP_ix],     cnt_p[IDREFCAP_ix]);
   printf(MSG7,cnt_p[NOTCAP_ix],    cnt_p[NOTCHCAP_ix]);
   /* cnt_p[TOTALCAP_ix] which is irrelevant, contains in fact the SR count */
   if (cnt_p[TOTALCAP_ix]) {    /* Careful ! */
      printf(MSG8,cnt_p[MAPCAP_ix]/cnt_p[TOTALCAP_ix], cnt_p[TOTALCAP_ix]);
   }
   printf(MSG9,cnt_p[LKSETCAP_ix],  cnt_p[LKNMCAP_ix]);
   for (total=0L, i=CAP_MAX_SIZE; --i >= 0; total += cnt_p[i] * point_p[i]);
   printf(MSGA,total,(uint)((total*100)/max_p[TOTALCAP_ix]),max_p[TOTALCAP_ix]);

   printf("\nATTCAP:   %lu\n", cnt_p[ATTCAP_ix] * point_p[ATTCAP_ix]);
   printf("ATTCHCAP: %lu\n", cnt_p[ATTCHCAP_ix] * point_p[ATTCHCAP_ix]);
   printf("AVGRPCAP: %lu\n", cnt_p[AVGRPCAP_ix] * point_p[AVGRPCAP_ix]);
   /* printf("DTACAP:   %lu\n", cnt_p[DTACAP_ix] * point_p[DTACAP_ix]); */
   /* printf("DTACHCAP: %lu\n", cnt_p[DTACHCAP_ix] * point_p[DTACHCAP_ix]); */
   printf("ELEMCAP:  %lu\n", cnt_p[ELEMCAP_ix] * point_p[ELEMCAP_ix]);
   printf("ENTCAP:   %lu\n", cnt_p[ENTCAP_ix] * point_p[ENTCAP_ix]);
   printf("ENTCHCAP: %lu\n", cnt_p[ENTCHCAP_ix] * point_p[ENTCHCAP_ix]);
   printf("EXGRPCAP: %lu\n", cnt_p[EXGRPCAP_ix] * point_p[EXGRPCAP_ix]);
   printf("EXNMCAP:  %lu\n", cnt_p[EXNMCAP_ix] * point_p[EXNMCAP_ix]);
   printf("GRPCAP:   %lu\n", cnt_p[GRPCAP_ix] * point_p[GRPCAP_ix]);
   printf("IDCAP:    %lu\n", cnt_p[IDCAP_ix] * point_p[IDCAP_ix]);
   printf("IDREFCAP: %lu\n", cnt_p[IDREFCAP_ix] * point_p[IDREFCAP_ix]);
   printf("LKNMCAP:  %lu\n", cnt_p[LKNMCAP_ix] * point_p[LKNMCAP_ix]);
   printf("LKSETCAP: %lu\n", cnt_p[LKSETCAP_ix] * point_p[LKSETCAP_ix]);
   printf("MAPCAP:   %lu\n", cnt_p[MAPCAP_ix] * point_p[MAPCAP_ix]);
   printf("NOTCAP:   %lu\n", cnt_p[NOTCAP_ix] * point_p[NOTCAP_ix]);
   printf("NOTCHCAP: %lu\n", cnt_p[NOTCHCAP_ix] * point_p[NOTCHCAP_ix]);
}

/*--------------------------------------------------------------------show_sr-+
| Show ShortRef strings                                                       |
+----------------------------------------------------------------------------*/
void show_sr(uint sr_number, SRTBE *srtbe_p)
{
   uint count;
   uchar *c_p;

   for (count=1; count<=sr_number; ++count, ++srtbe_p) {
      printf("ShortRef number %3d: \"", count);
      for (c_p=srtbe_p->p; *c_p; ++c_p) {
         printf((isprint(*c_p)) ? "%c" : "&#%d;",*c_p);
      }
      printf("\"\n");
   }
}

/*-------------------------------------------------------------------show_fct-+
| Show Function Characters                                                    |
+----------------------------------------------------------------------------*/
void show_fct(uint fct_number, FNCR *fncr_p)
{
   uint count;
   uchar *class;

   for (count=1; count<=fct_number; ++count, ++fncr_p) {
      switch (fncr_p->fctcls) {
      case RE_FCTCLS:       class ="RE";        break;
      case RS_FCTCLS:       class ="RS";        break;
      case SPACE_FCTCLS:    class ="SPACE";     break;
      case FUNCHAR_FCTCLS:  class ="FUNCHAR";   break;
      case MSICHAR_FCTCLS:  class ="MSICHAR";   break;
      case MSOCHAR_FCTCLS:  class ="MSOCHAR";   break;
      case MSSCHAR_FCTCLS:  class ="MSSCHAR";   break;
      case SEPCHAR_FCTCLS:  class ="SEPCHAR";   break;
      default:              class ="???";       break;
      }
      printf(
        "Char nmbr: %3d, function: \"%s\", class: %s\n",
        fncr_p->ch_nb, fncr_p->s.p, class
      );
   }
}

/*-------------------------------------------------------------------show_qty-+
| Show Quantities                                                             |
+----------------------------------------------------------------------------*/
void show_qty(uint *qty_p)
{
   printf("ATTCNT   is %d\n",qty_p[ATTCNT_ix]);
   printf("ATTSPLEN is %d\n",qty_p[ATTSPLEN_ix]);
   printf("BSEQLEN  is %d\n",qty_p[BSEQLEN_ix]);
   printf("DTAGLEN  is %d\n",qty_p[DTAGLEN_ix]);
   printf("DTEMPLEN is %d\n",qty_p[DTEMPLEN_ix]);
   printf("ENTLVL   is %d\n",qty_p[ENTLVL_ix]);
   printf("GRPCNT   is %d\n",qty_p[GRPCNT_ix]);
   printf("GRPGTCNT is %d\n",qty_p[GRPGTCNT_ix]);
   printf("GRPLVL   is %d\n",qty_p[GRPLVL_ix]);
   printf("LITLEN   is %d\n",qty_p[LITLEN_ix]);
   printf("NAMELEN  is %d\n",qty_p[NAMELEN_ix]);
   printf("NORMSEP  is %d\n",qty_p[NORMSEP_ix]);
   printf("PILEN    is %d\n",qty_p[PILEN_ix]);
   printf("TAGLEN   is %d\n",qty_p[TAGLEN_ix]);
   printf("TAGLVL   is %d\n",qty_p[TAGLVL_ix]);
}

/*-------------------------------------------------------------------show_opt-+
| Show Enabled Options / Features                                             |
+----------------------------------------------------------------------------*/
void show_opt(OPT *opt_p)
{
   static char oui[]   = "YES";         /*   :-)   */
   static char voila[] = "YES %d";      /*   :-)   */
   static char non[]   = "NO";          /*   :-)   */

   printf("Feature code: %04d, meaning the features:",opt_p->ft);

   printf("\n\tMINIMIZE:");
   printf("\n\t\tDATATAG  %s",(opt_p->ft & DATATAG_FT)  ? oui : non);
   printf("\n\t\tOMITTAG  %s",(opt_p->ft & OMITTAG_FT)  ? oui : non);
   printf("\n\t\tRANK     %s",(opt_p->ft & RANK_FT)     ? oui : non);
   printf("\n\t\tSHORTTAG %s",(opt_p->ft & SHORTTAG_FT) ? oui : non);

   printf("\n\tLINK:");
   printf("\n\t\tSIMPLE   ");
   (opt_p->ft & SIMPLE_FT)   ? printf(voila,opt_p->max_simple)   : printf(non);
   printf("\n\t\tIMPLICIT %s",(opt_p->ft & IMPLICIT_FT) ? oui : non );
   printf("\n\t\tEXPLICIT ");
   (opt_p->ft & EXPLICIT_FT) ? printf(voila,opt_p->max_explicit) : printf(non);

   printf("\n\tOTHER:");
   printf("\n\t\tCONCUR   ");
   (opt_p->ft & CONCUR_FT)   ? printf(voila,opt_p->max_concur)   : printf(non);
   printf("\n\t\tSUBDOC   ");
   (opt_p->ft & SUBDOC_FT)   ? printf(voila,opt_p->max_subdoc)   : printf(non);
   printf("\n\t\tFORMAL   %s",(opt_p->ft & FORMAL_FT)   ? oui : non );

   printf("\nOther options:");
   printf("\n\tNAMECASE:");
   printf("\n\t\tGENERAL  %s",(opt_p->ot & GENERAL_CASE_OT)  ? oui : non);
   printf("\n\t\tENTITY   %s",(opt_p->ot & ENTITY_CASE_OT)   ? oui : non);
   printf("\n\tSCOPE    %s\n",
         (opt_p->ot & INSTANCE_SCOPE_OT) ? "INSTANCE" : "DOCUMENT");
   printf("\nAPPINFO: ");
   if (!opt_p->appinfo.p) {
      printf("(NONE)\n");
   }else {
      printf("\"%s\"\n",opt_p->appinfo.p);
   }
}
/*****************************************************************************/
