home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / unix / sgmlc / vm2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-03  |  15.1 KB  |  351 lines

  1. /******************************************************************************/
  2. #include "sgmlapi.h"          /* SGML application programming interface. */
  3. /******************************************************************************/
  4. /* VM (Validate Markup): Analyze and validate SGML markup.
  5.    SGMLAPI is used for normal text processor services.
  6.    Parser control blocks are accessed directly for additional VM information.
  7. */
  8. #include "vmincl.h"           /* Include files for VM. */
  9. #include "vmxtrn.h"           /* Declarations for VM public variables. */
  10. extern int TPisVM;            /* Set to 1 by TP if it is markup validator. */
  11. static char vmomsg[] =        /* Text for invalid option error message. */
  12.      "/c10 /s";
  13. static char teattspc[] = "\n     ";             /* Tag/link att spacing. */
  14. static char deattspc[] = "\n                     "; /* Data att spacing. */
  15. static char *attspc = teattspc;  /* Initial spacing is for tag/link atts. */
  16. static char *typetab [] = {   /* Text for printing data entity type. */
  17.      "CDATA",                 /* 1  Internal character data entity. */
  18.      "SDATA",                 /* 2  Internal specific character data entity. */
  19.      "CDATA",                 /* 3  External character data entity. */
  20.      "NDATA",                 /* 4  Non-SGML data entity. */
  21.      "SDATA",                 /* 5  External specific character data entity. */
  22.      "SUBDOC"                 /* 6  SGML subdocument entity (NOT SUPPORTED). */
  23. };
  24. static void docproc(void);    /* Main loop for processing document. */
  25. static void getatts(void);    /* Get attribute list (tag or data). */
  26. static void proctkn(unsigned, char *); /* Process attribute token by type. */
  27. static void getde(void);      /* Get data entity control block. */
  28. /******************************************************************************/
  29. VOID main(argc, argv)
  30. int argc;
  31. UNCH **argv;
  32. {
  33.      UNCH *fileid = 0;        /* Primary file identifier. */
  34.      int i;                   /* Loop control. */
  35.      unsigned msgcnt;         /* Number of messages issued by parser. */
  36.  
  37.      /* PARSE ARGUMENTS
  38.      */
  39.      /* SGMLOPT handles common parser options.  We handle the other args. */
  40.      sgmloset();              /* Initialize for SGML option processing. */
  41.      suppsw = 1;              /* Assume no parsing information is wanted. */
  42.      for (i = 0; ++i<argc;) {
  43.           if (argv[i][0]!='/') fileid = argv[i];
  44.           else if (sgmlopt(argv[i])!=0) switch (toupper((int)argv[i][1])) {
  45.           case 'C':           /* Data or PI chars to print: 0 or more. */
  46.                prntmax = atoi(&argv[i][2]);
  47.                continue;
  48.           case 'S':           /* Show parsing information. */
  49.                suppsw = 0;
  50.                continue;
  51.           default:
  52.                printf(
  53. "\nVM001-> \"%s\" option switch is incorrect; usage is: %s %s",
  54.                argv[i], vmomsg, sgmlomsg);
  55.                exit(001);
  56.           }
  57.      }
  58.      if (fileid==0 || *fileid=='?') {
  59.           printf(
  60. "\nVM002-> No primary file specified; usage is: %s %s [profile;]file",
  61.           vmomsg, sgmlomsg);
  62.           exit(002);
  63.      }
  64.      /* IDENTIFY THE SGML DOCUMENT ENTITY
  65.      */
  66.      /* Define specified external file(s) as document entity. */
  67.      if (docent(fileid)) {
  68.           printf(
  69. "\nVM005-> SGML document entity system ID (%s) exceeds 240 characters.",
  70.           fileid);
  71.           exit(005);
  72.      }
  73.      /* INITIALIZE THE RUN
  74.      */
  75.      TPisVM = 1;                   /* Signal that validator is here. */
  76.      sgmlset();                    /* Initialize the SGML parser. */
  77.      while (++te.pass<=te.passes) {
  78.           /* INITIALIZE THE PASS
  79.           */
  80.           if (sgmlpset()) {
  81.                printf(
  82. "\nVM006-> Could not open SGML document entity in file: %s", fileid);
  83.                exit(006);
  84.           }
  85.           /* RUN THE PASS
  86.           */
  87.           printf(
  88. "\nVM105-> Pass %d of %d.", te.pass, te.passes);
  89.           docproc();
  90.      }
  91.      /* END OF RUN: Report message count and capacity statistics.
  92.      */
  93.      msgcnt = sgmlend();
  94.      printf(
  95. "\nVM106-> Processing completed; %u messag%s issued.",
  96.      msgcnt, (msgcnt==1) ? "e" : "es");
  97.      if (!suppsw) prtstat((struct stat *)srcbp);
  98.      exit(0);
  99. }
  100. /******************************************************************************/
  101. /* DOCPROC: Process the returns from SGMLNEXT.
  102. */
  103. void docproc()
  104. {
  105.      int rc;                  /* Return code from SGMLNEXT. */
  106.  
  107.      while ((rc = sgmlnext())!=TPEOD) switch (rc) {
  108.      case TPNDATA:            /* Non-SGML data entity reference. */
  109.           location(10);
  110.           printf("Non-SGML data entity");
  111.           if (CONTERSW) printf(" (out of context)");
  112.           printf("\n     %-8s = \"%s", "*ENTITY", de.ename);
  113.           getde();
  114.           continue;
  115.  
  116.      case TPNSGML:            /* Non-SGML character reference. */
  117.           location(10);
  118.           printf("Non-SGML character%s %d [%c]: [%c%c]",
  119.                  (CONTERSW ? " (out of context)" : ""),
  120.                  te.nonsgml, ZAPEOL(te.nonsgml), te.data[0], te.data[1]);
  121.           continue;
  122.  
  123.      case TPPCDATA:           /* Parsed character data found. */
  124.      case TPCDATA:            /* Character data entity reference. */
  125.      case TPSDATA:            /* System data entity reference. */
  126.           location(10);
  127.           printf("%d data characte%s%s%s%s: [",
  128.                  te.datalen, ((te.datalen==1) ? "r" : "rs"),
  129.                  (rc==TPCDATA ? " in CDATA entity" : ""),
  130.                  (rc==TPSDATA ? " in SDATA entity" : ""),
  131.                  (CONTERSW ? " (out of context)" : ""));
  132.           if (prntmax<te.datalen) printf("%.*s] ...", prntmax, te.data);
  133.           else printf("%.*s]", te.datalen, te.data);
  134.           continue;
  135.  
  136.      case TPSTAG:             /* Start-tag. */
  137.           location(11);
  138.           if (TAGMIN==MINNONE) {
  139.                printf("%s start-tag found%s.",
  140.                      te.data,  CONTERSW ? " (out of context)" :
  141.                             PEXSW    ? " (inclusion)" : "" );
  142.                if (ETISW)
  143.                      printf("\b; NET delimiter enabled (%d total).", ETICTR);
  144.           }
  145.           else if (TAGMIN==MINSTAG) {
  146.                printf("%s start-tag implied by %s%s", te.data,
  147.                      (TAGREAL<MINPTR ? realmsg[(UNS)TAGREAL]
  148.                                      : TAGRLNM+1),
  149.                      (TAGREAL==ETDCDATA ? "." : " start-tag."));
  150.           }
  151.           else printf("Short (no GI) %s start-tag found.", te.data);
  152. #ifdef V2
  153.           printf(" (Format %s.)", formats[te.format]);
  154. #endif
  155.           if (SRMNM) printf(" SHORTREF map is \"%s\".", SRMNM+1);
  156.           else if (srmsw) printf(" SHORTREF map is empty.");
  157. /*        if (te.gidata) printf(" [GIDATA = \"%s\" in %04x]", te.gidata);*/
  158.           if (te.alcnt) getatts();
  159.           continue;
  160.  
  161.      case TPETAG:             /* End-tag found. */
  162.           location(12);
  163.           if (MTYSW) printf("%s end-tag implied by empty content;", te.data);
  164.           else if (TAGMIN==MINSTAG || TAGMIN==MINETAG) {
  165.                printf("%s end-tag implied by %s%s", te.data,
  166.                      (TAGREAL<MINPTR ? realmsg[(UNS)TAGREAL]
  167.                                      : TAGRLNM+1),
  168.                      (TAGREAL==ETDCDATA ? ";" :
  169.                           (TAGMIN==MINSTAG ? " start-tag;" : " end-tag;")));
  170.           }
  171.           else printf(eminmsg[TAGMIN], te.data);
  172.           if (PEXSW) printf(" (Inclusion ended.)");
  173.           if (ETISW) printf(" NET delimiter disabled (%u left);", ETICTR);
  174.           printf(" %s element resumed.", OLDGI+1);
  175. #ifdef V2
  176.           printf(" (Ending format %s.)", formats[te.format]);
  177. #endif
  178.           if (SRMNM) printf(" SHORTREF map is \"%s\".", SRMNM+1);
  179.           else if (srmsw) printf(" SHORTREF map is empty.");
  180. /*        if (te.gidata) printf(" [gidata = \"%s\" in %04x]", te.gidata);*/
  181.           continue;
  182.  
  183.      case TPPI:               /* Processing instruction. */
  184.      case TPPIENT:            /* Processing instruction entity. */
  185.           if (suppsw) continue;
  186.           location(13);
  187.           printf("%d character processing instruction%s: [",
  188.                te.datalen, (rc==TPPIENT ? " in PI entity" : ""));
  189.           if (prntmax<te.datalen) printf("%.*s] ...", prntmax, te.data);
  190.           else printf("%.*s]", te.datalen, te.data);
  191.           continue;
  192.  
  193.      case TPRE:               /* Significant record end. */
  194.           if (suppsw) continue;
  195.           location(14);
  196.           printf("Record end%s.", (CONTERSW ? " (out of context)" : ""));
  197.           continue;
  198.  
  199.      case TPSDTD:             /* Document type definition started. */
  200.           location(15);
  201.           printf("Document type definition started for %s.", te.data);
  202.           continue;
  203.  
  204.      case TPEDTD:             /* Document type definition completed. */
  205.           location(16);       /* GISET and GIGET can now be done. */
  206.           printf("Document type definition completed for %s; ", te.data);
  207.           printf("%d SHORTREF map%s defined.",
  208.                  SRMCNT, (SRMCNT==1) ? "" : "s");
  209.           srmsw = SRMCNT>0;   /* Short reference maps are in use. */
  210.           /* Store GIDATA for element start-tags and end-tags here. */
  211.           /* GISET returns non-zero for undefined elements. */
  212.           /* TESTING ONLY: Store GIDATA for document type element. */
  213. /*        giset("DUMMYGI",         /* Dummy GI. */
  214. /*              "start-data",      /* Phoney GIDATA for start-tag. */
  215. /*              "end-data");       /* Phoney GIDATA for start-tag. */
  216.           /* END OF TEST */
  217.           continue;
  218.  
  219.      case TPMV:                    /* Markup validator information. */
  220.           if (suppsw) continue;
  221.           location(17);
  222.           printf("USEMAP declaration:");
  223.           if (CDATA) {
  224.                printf(" SHORTREF map is \"%s\".", CDATA+1);
  225.           }
  226.           else printf(" SHORTREF map is empty.");
  227.           continue;
  228.  
  229.      default:
  230.           continue;
  231.      }
  232.      /*   TPEOD:                 End of document. */
  233.      return;
  234. }
  235. /******************************************************************************/
  236. /* GETATTS: Retrieve attribute specifications, one by one, and print them.
  237. */
  238. void getatts()
  239. {
  240.      while (alnext()) {
  241.           /* No value specified for #IMPLIED or #REQUIRED.
  242.           */
  243.           if (CA.astatus==TPAIMPLY || CA.astatus==TPANOREQ) {
  244.                printf("\n     %-8s = [NONE]", CA.aname);
  245.                if (CA.astatus==TPANOREQ) printf(" [INVALID]");
  246.                return;
  247.           }
  248.           /* Value specified or defaulted.
  249.           */
  250.           printf(attspc);
  251.           printf("%-8s = \"", CA.aname);
  252.           switch (CA.atype) {
  253.           case TPALIST:            /* Value is list of tokens. */
  254.                avnext();           /* First token is on same line. */
  255.                printf("%.*s", CA.tokenlen, CA.token);
  256.                proctkn(CA.tokenlen, CA.token);
  257.                while (avnext()) {  /* New lines for any other tokens. */
  258.                     printf(attspc);
  259.                     printf("            %.*s", CA.tokenlen, CA.token);
  260.                     proctkn(CA.tokenlen, CA.token);
  261.                }
  262.                printf("\"");
  263.                break;
  264.           case TPACDATA:           /* Value is string.*/
  265.           case TPATOKEN:           /* Value is single token.*/
  266.                printf("%.*s", CA.avallen, CA.aval);
  267.                proctkn(CA.avallen, CA.aval);
  268.                printf("\"");
  269.                break;
  270.           }
  271.           if (CA.astatus==TPAERROR) printf(" [ERROR]");
  272.           else if (CA.astatus==TPAINVAL) printf(" [INVALID]");
  273.           else if (!GET(CA.aflags, ASPEC)) printf(" [DEFAULT]");
  274.           else if (GET(CA.aflags, ACURRENT)) printf(" [NEW DEFAULT]");
  275.           if (CA.aconref) printf(" [CONREF]");
  276.      }
  277.      if (attspc==deattspc) attspc = teattspc;
  278. }
  279. /******************************************************************************/
  280. /* PROCTKN: Process a single token or list member according to its type.
  281. */
  282. void proctkn(tokenlen, token)
  283. UNS tokenlen;                 /* Length of token. */
  284. UNCH *token;                  /* The token itself. */
  285. {
  286.      switch (CA.adata) {
  287.      case TPANOTE:                 /* dcnid, dcnidlen */
  288.           printf("=>%s", CA.dcnid);
  289.           break;
  290.      case TPAENTIT:                /* neid,dcnnm,dcnid+len; alcnt */
  291.           getent(tokenlen, token); /* Set up rcbde for this entity. */
  292.           getde();
  293.           break;
  294.      case TPAIDREF:                /* idrstat */
  295.           idrnext();
  296.           if (!CA.idrstat) printf(" [INVALID]");
  297.           break;
  298.      }
  299. }
  300. /******************************************************************************/
  301. /* GETDE: Get control block information for data entity named in
  302.           AENTITY attribute or external data entity reference.
  303. */
  304. void getde()
  305. {
  306.      if (de.detype<=TPISDATA) {
  307.           printf("=>%s [internal %s]", de.detxt, typetab[de.detype-1]);
  308.           return;
  309.      }
  310.      printf("=>%s [%s]; notation is %s=>%s.",
  311.           de.detxt+2, typetab[de.detype-1],
  312.           (de.dcnnm!=0) ? de.dcnnm   : "[UNDEFINED]",
  313.           (de.dcnid!=0) ? de.dcnid+2 : "[UNDEFINED]");
  314.      if (de.alcnt) {attspc = deattspc; getatts();}
  315. }
  316. /******************************************************************************/
  317. /* PRTSTAT: Print capacity statistics from the stat structure (verbosely).
  318. */
  319. void prtstat(ps)
  320. struct stat *ps;              /* Pointer to SGML stat structure. */
  321. {
  322.      printf("\n         %3u entit%s declared with %u character%s of text.",
  323.             ps->ecbcnt, (ps->ecbcnt==1) ? "y" : "ies",
  324.             ps->ecbtext, (ps->ecbtext==1) ? "" : "s");
  325.      printf("\n         %3u element typ%s declared",
  326.             ps->etdcnt, (ps->etdcnt==1) ? "e" : "es");
  327.      if (ps->etdercnt) printf(
  328.            " (plus %u undeclared)", ps->etdercnt);
  329.     printf(",\n             with %u model token%s and %u exception group%s",
  330.             ps->modcnt, (ps->modcnt==1) ? "" : "s",
  331.             ps->pmexgcnt, (ps->pmexgcnt==1) ? "" : "s");
  332.      if (ps->pmexcnt) printf(
  333.            " with %u name%s", ps->pmexcnt, (ps->pmexcnt==1) ? "" : "s");
  334.     printf(".\n         %3u attribute%s with %u group member%s",
  335.             ps->attcnt, (ps->attcnt==1) ? "" : "s",
  336.             ps->attgcnt, (ps->attgcnt==1) ? "" : "s");
  337.      printf("\n             and %u character%s of value text.",
  338.             ps->attdef, (ps->attdef==1) ? "" : "s");
  339.      printf("\n         %3u ID%s and %u ID reference%s specified.",
  340.             ps->idcnt, (ps->idcnt==1) ? "" : "s",
  341.             ps->idrcnt, (ps->idrcnt==1) ? "" : "s");
  342.      printf("\n         %3u data content notation%s with %u text character%s.",
  343.             ps->dcncnt, (ps->dcncnt==1) ? "" : "s",
  344.             ps->dcntext, (ps->dcntext==1) ? "" : "s");
  345.      printf("\n         %3u short reference map%s declared.",
  346.             ps->srcnt, (ps->srcnt==1) ? "" : "s");
  347.      printf("\n         %lu capacity points required (%lu%% of %lu permitted).",
  348.             ps->capused, ps->capused*100/ps->capacity, ps->capacity);
  349. }
  350. /******************************************************************************/
  351.