/* National Institute of Standards and Technology (NIST)
/* National Computer System Laboratory (NCSL)
/* Office Systems Engineering (OSE) Group
/* ********************************************************************
/*                            D I S C L A I M E R
/*                              (March 8, 1989)
/*  
/* There is no warranty for the NIST NCSL OSE SGML parser and/or the NIST
/* NCSL OSE SGML parser validation suite.  If the SGML parser and/or
/* validation suite is modified by someone else and passed on, NIST wants
/* the parser's recipients to know that what they have is not what NIST
/* distributed, so that any problems introduced by others will not
/* reflect on our reputation.
/* 
/* Policies
/* 
/* 1. Anyone may copy and distribute verbatim copies of the SGML source
/* code as received in any medium.
/* 
/* 2. Anyone may modify your copy or copies of SGML parser source code or
/* any portion of it, and copy and distribute such modifications provided
/* that all modifications are clearly associated with the entity that
/* performs the modifications.
/* 
/* NO WARRANTY
/* ===========
/* 
/* NIST PROVIDES ABSOLUTELY NO WARRANTY.  THE SGML PARSER AND VALIDATION
/* SUITE ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
/* EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
/* THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
/* WITH YOU.  SHOULD THE SGML PARSER OR VALIDATION SUITE PROVE DEFECTIVE,
/* YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
/* 
/* IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL NIST BE LIABLE FOR
/* DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
/* INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
/* INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
/* BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
/* FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
/* NIST) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF
/* SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
*/

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define    COMMA      -21
#define    AND        -22
#define    OR         -23

#define NAMELEN 8
#define NUMELTS 256
#define NUMCOLS NUMELTS
#define NUMROWS NUMELTS
int errflag = 0;
void saferead(), doread(), showmatrix(), heading(), setcell(), error(),
analyze();
/* ================================================================ */

typedef struct {
   char Rcol[NUMCOLS];
}ROW;

typedef struct {
   int  Smin;
   char Sname[8];
   int  Snbr;
}SYMBOL;

typedef struct {
   int Dtoken;
   int Doi;
   int Dcontreq;
} DTDREC;
/* ================================================================ */
SYMBOL symbol[NUMROWS];
ROW Rrow[NUMROWS];
unsigned char debug;
/* ================================================================ */
main(argc, argv)
int argc;
char *argv[];
{

   int infile,numtokens,roottoken;
   register int j;
   char fname[128];

   infile = doinit(argc, argv, fname);
   saferead(infile, &numtokens, sizeof(numtokens));
   if (numtokens >= NUMROWS)
      error("too many tokens for closure tables");
   saferead(infile, &roottoken, sizeof(roottoken));
   /* read in all the symbols */
   for (j = 0; j < numtokens; j++){
      saferead(infile, &symbol[j], sizeof(SYMBOL));
   }
   for (j = 0; j < numtokens; j++)
      doread(infile, j, symbol);
   close(infile);
   showmatrix(numtokens);
   for (j = 0; ; j++){
      if (doclosure(numtokens) == 0)
         break;
   }
   showmatrix(numtokens);
   analyze(roottoken, numtokens, symbol);
   exit(0);
}
/* ================================================================ */
void doread(infile, tokennbr, symbol)
int infile, tokennbr;
SYMBOL symbol[];
{
   DTDREC tokeninfo;
   int andcount;

   saferead(infile, &tokeninfo, sizeof(tokeninfo)) ;
   switch(tokeninfo.Dtoken) {
   case COMMA:
   case OR:
      doread(infile, tokennbr, symbol);
      doread(infile, tokennbr, symbol);
      break;
   case AND:
      saferead(infile, &andcount, sizeof(andcount));
      while(andcount--)
         doread(infile, tokennbr, symbol);
      break;
   default:
      setcell(tokennbr, tokeninfo.Dtoken, symbol);
   }
}
/* ================================================================ */
void setcell(row, col, symbol)
int row;
register int col;
SYMBOL symbol[];
{
   register char *temp = Rrow[row].Rcol;
#ifdef JJJ
   if (col == 0) {
      strncpy(temp, symbol[row].Sname, NAMELEN);
      *(temp + NAMELEN) = 0;
      fprintf(stdout,"element '%s' contains root element as subelement\n",
          temp);
      return;
   }
#endif
   if (col < 0)
      col = 0;
   *(temp + col) = 1;
}

/* ================================================================ */
void showmatrix(count)
register int count;
{
   register int j, k;
   return;
   for (j = 0; j < count; j++){
      for (k = 0; k < count; k++)
         printf("[%02x]", Rrow[j].Rcol[k]);
      printf("\n");
   }
   printf("\n\n");
}

/* ================================================================ */
int doclosure(count)
int count;
{
   int row;
   int chgdsomething = 0;
   register col, tempcol;
   for(row = 0; row < count; row++) {
      for(col = 1; col < count ;col++) {
         if (debug == 'Y')
            printf("<row = %d, col = %d>\n", row, col);
         if(Rrow[row].Rcol[col] == 1) {
            for(tempcol = 0; tempcol < count; tempcol++)
            {
               if (debug == 'Y')
                  printf("Rrow[%d].Rcol[%d] = [%d]\n",
                      col, tempcol, Rrow[col].Rcol[tempcol]);
               if(Rrow[col].Rcol[tempcol] == 1) {
                  if (Rrow[row].Rcol[tempcol] != 1)
                     chgdsomething++;
                  Rrow[row].Rcol[tempcol] = 1;
                  if (debug == 'Y')
                     showmatrix(count);
               }
            }
         }
      }
   }
   return(chgdsomething);
}
/* ================================================================ */
void saferead(file, buf, len)
int file;
unsigned char *buf;
unsigned len;
{
   int j;
   static int readcount = 0;
   readcount++;
   if ((j = read(file, buf, len)) != len) {
      error("read failure\n");
      j = j;
   }
}
/* ================================================================ */
void error(msg)
unsigned char *msg;
{
   printf(msg);
   exit(1);
}
/* ================================================================ */
doinit(argc, argv, fname)
int argc;
unsigned char *argv[];
unsigned char *fname;
{
   int infile;
   char temp[128];

   strcpy(fname, "dtdfile.sgm");
   if ((infile = open(fname, O_RDONLY)) == -1){
      sprintf(temp,"unable to open %s", fname);
      error(temp);
   }
   return(infile);
}
/* ================================================================ */
void analyze(root, count, symbol)
int root;
register int count;
SYMBOL symbol[];
{
   register int j;
   char temp[128];
   ;
   for(j = 0; j < count; j++)
      if (Rrow[root].Rcol[j] != 1){
         if (j == root)
            continue;
         strncpy(temp, symbol[j].Sname, NAMELEN);
         *(temp + NAMELEN) = '\0';
         fprintf(stdout, "element %s may not have path to root element\n", temp);
#ifdef JJJ
         printf("Press ENTER to continue\n");
         getchar();
#endif
         errflag = 1;
      }
   for (j = 0; j < count; j++)
      if (Rrow[j].Rcol[0] != 1) {
         strncpy(temp, symbol[j].Sname, NAMELEN);
         *(temp + NAMELEN) = '\0';
         fprintf(stdout,"element %s may not have path to a terminal element\n",
             temp);
#ifdef JJJ
         printf("Press ENTER to continue\n");
         getchar();

#endif
         errflag = 1;
      }
}
/* ================================================================ */

/*----------------------------------------------*/
/*         HEADING         */
/* Simply prints a informatory heading */
/* when the document parser is invoked */
/* describing the document name to be  */
/* parsed.              */
/*----------------------------------------------*/

void heading()
{
   printf("\n                               CLOSURE\n");
   printf("                      Determine Closure of Elements\n");
   printf("          --------------------------------------------------\n");
   printf("                      10FEB87      Version 1.02\n");
   printf("          --------------------------------------------------\n\n");
   return;
}
