/******************************************************************************/
#include "sgmlapi.h"          /* SGML application programming interface. */
/******************************************************************************/
/* APIMODEL.C: Model program to demonstrate use of SGMLAPI.
   This program merely prints information as it is returned
   by the API.  However the shell can be used as a model for
   your own text processor or dedicated application.
*/
static void docproc(void);    /* Main loop for processing document. */
static void getatts(void);    /* Get attribute list (tag or data). */
static void proctkn(unsigned, char *); /* Process attribute token by type. */
static void getde(void);      /* Get data entity control block. */
/******************************************************************************/
/*lint -e528                     Suppress unreferenced function messages. */
void main(int ,char * *); /* Main function. */
void main(argc, argv)
int argc;
char **argv;
{
/*lint +e528                     Restore unreferenced function messages. */
     char *fileid = 0;        /* Primary file identifier. */
     int i;                   /* Loop control. */
     unsigned msgcnt;         /* Number of messages issued by parser. */

     /* PARSE ARGUMENTS
     */
     /* SGMLOPT handles common parser options.  We handle the other args. */
     sgmloset();              /* Initialize for SGML option processing. */
     for (i = 0; ++i<argc;) {
          if (argv[i][0]!='/') fileid = argv[i];
          else if (sgmlopt(argv[i])!=0) {
               printf(
"\nTP001-> \"%s\" option switch is incorrect; usage is: %s",
               argv[i], sgmlomsg);
               exit(001);
          }
     }
     if (fileid==0 || *fileid=='?') {
          printf(
"\nTP002-> No primary file specified; usage is: %s [profile;]file",
          sgmlomsg);
          exit(002);
     }
     /* IDENTIFY THE SGML DOCUMENT ENTITY
     */
     /* Define specified external file(s) as document entity. */
     if (docent(fileid)) {
          printf(
"\nTP005-> SGML document entity system ID (%s) exceeds 240 characters.",
          fileid);
          exit(005);
     }
     /* INITIALIZE THE RUN
     */
     sgmlset();                    /* Initialize the SGML parser. */
     while (++te.pass<=te.passes) {
          /* INITIALIZE THE PASS
          */
          if (sgmlpset()) {
               printf(
"\nTP006-> Could not open SGML document entity in file: %s", fileid);
               exit(006);
          }
          /* RUN THE PASS
          */
          printf(
"\nTP105-> Pass %d of %d.", te.pass, te.passes);
          docproc();
     }
     /* END OF RUN: Report message count and capacity statistics.
     */
     msgcnt = sgmlend();
     printf(
"\nTP106-> Processing completed; %u messag%s issued.",
     msgcnt, (msgcnt==1) ? "e" : "es");
     exit(0);
}
/******************************************************************************/
/* DOCPROC: Process the returns from SGMLNEXT.
*/
void docproc()
{
     int rc;                  /* Return code from SGMLNEXT. */

     while ((rc = sgmlnext())!=TPEOD) switch (rc) {
     case TPNDATA:            /* Non-SGML data entity reference. */
          location(10);
          printf("Non-SGML data entity %s", de.ename);
          getde();
          continue;

     case TPNSGML:            /* Non-SGML character reference. */
          location(10);
          printf("Non-SGML character %d", te.nonsgml);
          continue;

     case TPPCDATA:           /* Parsed character data found. */
     case TPCDATA:            /* Character data entity reference. */
     case TPSDATA:            /* System data entity reference. */
          location(10);
          printf("%d data characte%s%s: [",
                 te.datalen,
                 (rc==TPCDATA ? " in CDATA entity" : ""),
                 (rc==TPSDATA ? " in SDATA entity" : ""));
          printf("%.*s]", te.datalen, te.data);
          continue;

     case TPSTAG:             /* Start-tag. */
          location(11);
          printf("%s start-tag found or implied.", te.data);
/*        if (te.gidata) printf(" [GIDATA = \"%s\"]", te.gidata);*/
          if (te.alcnt) getatts();
          continue;

     case TPETAG:             /* End-tag found. */
          location(12);
          printf("%s end-tag found or implied.", te.data);
/*        if (te.gidata) printf(" [GIDATA = \"%s\"]", te.gidata);*/
          continue;

     case TPPI:               /* Processing instruction. */
     case TPPIENT:            /* Processing instruction entity. */
          location(13);
          printf("%d character processing instruction%s: [%.*s]",
               te.datalen, (rc==TPPIENT ? " in PI entity" : ""),
               te.datalen, te.data);
          continue;

     case TPRE:               /* Significant record end. */
          location(14);
          printf("Record end.");
          continue;

     case TPEDTD:             /* Document type definition completed. */
          location(16);       /* GISET and GIGET are now allowed. */
          printf("Document type definition completed for %s; ", te.data);
          /* Store GIDATA for element start-tags and end-tags here. */
          /* GISET returns non-zero for undefined elements. */
/*        giset("MODELGI",    /* Generic Identifier. */
/*              strtproc,     /* Ptr to procedure for start-tag. */
/*              endproc);     /* Ptr to procedure for start-tag. */
          continue;

     default:
          continue;
     }
     /*   TPEOD:                 End of document. */
     return;
}
/******************************************************************************/
/* GETATTS: Retrieve attribute specifications, one by one, and print them.
*/
void getatts()
{
     while (alnext()) {
          /* No value specified for #IMPLIED or #REQUIRED.
          */
          if (CA.astatus==TPAIMPLY || CA.astatus==TPANOREQ) {
               printf("\n     %-8s = [NONE]", CA.aname);
               if (CA.astatus==TPANOREQ) printf(" [INVALID]");
               return;
          }
          /* Value specified or defaulted.
          */
          printf("\n");
          printf("%-8s = \"", CA.aname);
          switch (CA.atype) {
          case TPALIST:            /* Value is list of tokens. */
               avnext();           /* First token is on same line. */
               printf("%.*s", CA.tokenlen, CA.token);
               proctkn(CA.tokenlen, CA.token);
               while (avnext()) {  /* New lines for any other tokens. */
                    printf("\n");
                    printf("            %.*s", CA.tokenlen, CA.token);
                    proctkn(CA.tokenlen, CA.token);
               }
               printf("\"");
               break;
          case TPACDATA:           /* Value is string.*/
          case TPATOKEN:           /* Value is single token.*/
               printf("%.*s", CA.avallen, CA.aval);
               proctkn(CA.avallen, CA.aval);
               printf("\"");
               break;
          }
          if (CA.astatus==TPAERROR) printf(" [ERROR]");
          else if (CA.astatus==TPAINVAL) printf(" [INVALID]");
          if (CA.aconref) printf(" [CONREF]");
     }
}
/******************************************************************************/
/* PROCTKN: Process a single token or list member according to its type.
*/
void proctkn(tokenlen, token)
unsigned tokenlen;            /* Length of token. */
char *token;                  /* The token itself. */
{
     switch (CA.adata) {
     case TPANOTE:                 /* dcnid, dcnidlen */
          printf("=>%s", CA.dcnid);
          break;
     case TPAENTIT:                /* neid,dcnnm,dcnid+len; alcnt */
          getent(tokenlen, token); /* Set up rcbde for this entity. */
          getde();
          break;
     case TPAIDREF:                /* idrstat */
          idrnext();
          if (!CA.idrstat) printf(" [INVALID]");
          break;
     }
}
/******************************************************************************/
/* GETDE: Get control block information for data entity named in
          AENTITY attribute or external data entity reference.
*/
void getde()
{
     printf("=>%s [type %d]", de.detxt, de.detype);
     if (de.detype<=TPISDATA) return;
     printf("; notation is %s=>%s.",
          (de.dcnnm!=0) ? de.dcnnm   : "[UNDEFINED]",
          (de.dcnid!=0) ? de.dcnid+2 : "[UNDEFINED]");
     if (de.alcnt) getatts();
}
/******************************************************************************/
