/* 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.
*/

/************************************************************************/
/*   TITLE:          SGML PARSER                                        */
/*   SYSTEM:         DTD PROCESSOR                                      */
/*   SUBSYSTEM:                                                         */
/*   SOURCE FILE:    DTDEXIT.C                                          */
/*   AUTHOR:         Jim Heath                                          */
/*                                                                      */
/*   DATE CREATED:                                                      */
/*   LAST MODIFIED:                                                     */
/*                                                                      */
/*                  REVISIONS                                           */
/*   WHEN      WHO            WHY                                       */
/************************************************************************/
#include <stdio.h>
#include <setjmp.h>
#include <fcntl.h>
#include <unistd.h>

#include "qntyset.h"
#include "dtd.h"
#include "dtdglbl.h"
#include "dtdfncs.h"
#include "dtddefs.h"

/* ============================================================ */
void bldsymbtbl()
{
   int temp, minrecs[MAXELTS], flag, rootgi = -1;
   int count, j;
   SYMBREC symbrec[MAXELTS];
   extern char symbfname[];

   FUNCTRACE("bldsymbtbl");
   symbfile = safeopen(symbfname, O_RDONLY, SYMBFILE);
   for (count = 0; count < MAXELTS; count++)
      memset((char *) &symbrec[count], ' ',sizeof(SYMBREC));
   for (count = 0; count < MAXELTS; count++) {
      temp = read(symbfile, (char *)&symbrec[count], sizeof(SYMBREC));
      if (temp <= 0)
         break;
      if ((symbrec[count].Sname[0] & (1 << 7)) == (1 << 7)) {
         symbrec[count].Sname[0] ^= (1 << 7);
         rootgi = count;
      }
      for (j = 0, flag = FALSE; j < NAMELEN; j++){
         if (symbrec[count].Sname[j] == '\0')
            flag = TRUE;
         if (flag == TRUE)
            symbrec[count].Sname[j] = ' ';
      }

      temp = read(symbfile, (char *)&minrecs[count], sizeof(int));
      if (temp <= 0)
         break;
      symbrec[count].Smin = minrecs[count];
   }
   /* now check all the attributes */
   safeclose(symbfile, "symbfile", SYMBFILE);
   safeunlink(symbfname);
   ckattributes(symbrec, count);
   inclfile = safeopen(inclfname, O_RDONLY, INCLFILE);
   xcptfile = safecreat(xcptfname, XCPTFILE);
   doincludes(symbrec, count);
   /*   safeunlink(inclfname, INCLFILE);*/
   exclfile = safeopen(exclfname, O_RDONLY, EXCLFILE);
   doexcludes(symbrec, count);
   /*   safeunlink(exclfname, EXCLFILE);*/
   safeclose(xcptfile, "xcptfile", XCPTFILE);
   bldtokentree(symbrec, minrecs, count, rootgi);
}
/* ============================================================ */
static void doincludes(srec, scount)
SYMBREC srec[];
int scount;
{
   REGISTER int j;
   int count = 0, inclcount, elttoken, k;
   char eltname[NAMELEN + 1], temp[128];
   REGISTER char *eptr;
   long position, lseek();

   safewrite(xcptfile, (char *) &count, sizeof(count));
   for (count = 0; ; count++) {
      if (read(inclfile, eltname, sizeof(eltname)) != sizeof(eltname)){
         safeclose(inclfile, "inclfile", INCLFILE);
         /* save current position */
         if ((position = lseek(xcptfile, 0L, SEEK_CUR)) == -1)
            terminate(1, "error on lseek on xcptfile");
         /* position to beginning of file */
         if (lseek(xcptfile, 0L, SEEK_SET) == -1)
            terminate(1, "error on lseek on xcptfile");
         safewrite(xcptfile, (char *) &count, sizeof(count));
         /* restore pointer to current position */
         if (lseek(xcptfile, position, SEEK_SET) == -1)
            terminate(1, "error on lseek on xcptfile");
         return;
      }
      for (j = 0, eptr = eltname; j < sizeof(eltname); j++, eptr++) {
         if (*eptr == '\0')
            *eptr = ' ';
      }
      if ((elttoken = find (eltname, srec, scount)) == -1) {
         memset(temp, '\0', sizeof(temp));
         strncpy(temp, eltname, sizeof(eltname));
         strcat(temp, " is found in inclusion but no element declaration exists");
         printf("%s\n", temp);
      }
      safewrite(xcptfile, (char *) &elttoken, sizeof(elttoken));

      if(read(inclfile, (char *) &inclcount, sizeof(inclcount)) != sizeof(inclcount))
         terminate(1, "error in reading inclusion file");
      safewrite(xcptfile, (char *) &inclcount, sizeof(inclcount));

      for (k = 0; k < inclcount; k++) {
         if (read(inclfile, eltname, sizeof(eltname)) != sizeof(eltname))
            terminate(1, "error in reading inclusion file");
         for (j = 0, eptr = eltname; j < sizeof(eltname); j++, eptr++) {
            if (*eptr == '\0')
               *eptr = ' ';
         }
         if ((elttoken = find (eltname, srec, scount)) == -1) {
            memset(temp, '\0', sizeof(temp));
            strncpy(temp, eltname, sizeof(eltname));
            strcat(temp, " is found in inclusion but no element declaration exists");
            printf("%s\n", temp);
         }
         safewrite(xcptfile, (char *) &elttoken, sizeof(elttoken));
      }
   }
}
/* ============================================================ */
static void doexcludes(srec, scount)
SYMBREC srec[];
int scount;
{
   REGISTER int j;
   int count = 0, exclcount, elttoken, k;
   char eltname[NAMELEN + 1], temp[128];
   REGISTER char *eptr;
   long position, lseek();

   /* save current position */
   if ((position = lseek(xcptfile, 0L, SEEK_CUR)) == -1)
      terminate(1, "error on lseek on xcptfile");
   safewrite(xcptfile, (char *) &count, sizeof(count));
   for (count = 0; ; count++) {
      if (read(exclfile, eltname, sizeof(eltname)) != sizeof(eltname)){
         safeclose(exclfile, "exclfile", EXCLFILE);
         if ((position = lseek(xcptfile, position, SEEK_SET)) == -1)
            terminate(1, "error on lseek on xcptfile");
         safewrite(xcptfile, (char *) &count, sizeof(count));
         return;
      }
      for (j = 0, eptr = eltname; j < sizeof(eltname); j++, eptr++) {
         if (*eptr == '\0')
            *eptr = ' ';
      }
      if ((elttoken = find (eltname, srec, scount)) == -1) {
         memset(temp, '\0', sizeof(temp));
         strncpy(temp, eltname, sizeof(eltname));
         strcat(temp, " is found in exclusion but no element declaration exists");
         printf("%s\n", temp);
      }
      safewrite(xcptfile, (char *) &elttoken, sizeof(elttoken));

      if(read(exclfile, (char *) &exclcount, sizeof(exclcount)) != sizeof(exclcount))
         terminate(1, "error in reading exclusion file");
      safewrite(xcptfile, (char *) &exclcount, sizeof(exclcount));

      for (k = 0; k < exclcount; k++) {
         if (read(exclfile, eltname, sizeof(eltname)) != sizeof(eltname))
            terminate(1, "error in reading exclusion file");
         for (j = 0, eptr = eltname; j < sizeof(eltname); j++, eptr++) {
            if (*eptr == '\0')
               *eptr = ' ';
         }
         if ((elttoken = find (eltname, srec, scount)) == -1) {
            memset(temp, '\0', sizeof(temp));
            strncpy(temp, eltname, sizeof(eltname));
            strcat(temp, " is found in exclusion but no element declaration exists");
            printf("%s\n", temp);
         }
         safewrite(xcptfile, (char *) &elttoken, sizeof(elttoken));
      }
   }
}
/* ============================================================ */
/*jstatic*/ void bldtokentree(srec, minrecs, count, rootgi)
SYMBREC srec[];
int minrecs[];
int count;
int rootgi;
{
   TREEREC trec;
   DTDREC drec;
   REGISTER int j, flag;
   int andcount;
   extern char treefname[], dtdfname[], attrfname[];
   char temp[128];

   FUNCTRACE("bldtokentree");
   dtdfile = safecreat(dtdfname, DTDFILE);

   treefile = safeopen(treefname, O_RDONLY, TREEFILE);
   safewrite(dtdfile, (char *)&count, sizeof(count));
   safewrite(dtdfile, (char *)&rootgi, sizeof(rootgi));
   for (j = 0; j < count; j++) {
      srec[j].Smin = minrecs[j];
      srec[j].Sid = j;
      safewrite(dtdfile, (char *)&srec[j], sizeof (SYMBREC));
   }

   while (read(treefile, (char *)&trec, sizeof(trec)) > 0) {
      if (trec.Toi == 'x')
         continue;

      for (j = 0, flag = FALSE; j < NAMELEN; j++){
         if (trec.Tinfo[j] == '\0')
            flag = TRUE;
         if (flag == TRUE)
            trec.Tinfo[j] = ' ';
      }
      drec.Dcontreq = trec.Tcontreq;
      if (trec.Tinfo[0] == ',')
         drec.Dtoken = COMMA;
      else if (trec.Tinfo[0] == '&') {
         drec.Dtoken = AMPERSAND;
      }
      else if (trec.Tinfo[0] == '|')
         drec.Dtoken = OR;
      else if (strncmp(trec.Tinfo, "#PCDATA", 7) == 0)
         drec.Dtoken = -1;
      else if (strncmp(trec.Tinfo, "rCDATA", 6) == 0)
         drec.Dtoken = -3;
      else if (strncmp(trec.Tinfo, "cDATA", 5) == 0)
         drec.Dtoken = -4;
      else if (strncmp(trec.Tinfo, "eMPTY", 5) == 0)
         drec.Dtoken = -5;
      else if (strncmp(trec.Tinfo, "aNY", 3) == 0)
         drec.Dtoken = -6;
      else if ((drec.Dtoken = find(trec.Tinfo, srec, count)) == -1){
         memset(temp, '\0', sizeof(temp));
         strncpy(temp, trec.Tinfo, NAMELEN);
         *(temp + NAMELEN) = '\0';
         printf("\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
         printf("%s found in content model but --\n", temp);
         printf("no ELEMENT declaration for %s was found\n", temp);
         if ((debug & WAITFORCR) != FALSE) {
            printf("\npress ENTER to continue -> \n");
            (void) getchar();
         }
         errflag = 1;
      }
      drec.Doi = trec.Toi;
      safewrite(dtdfile, (char *)&drec, sizeof (drec));
      if (drec.Dtoken == AMPERSAND) {
         read(treefile, (char *) &andcount, sizeof(andcount));
         safewrite(dtdfile, (char *) &andcount, sizeof(andcount));
      }
   }
   closeall();
   unlinkall(FALSE);
   exit(errflag);
}
/* ============================================================ */
int find(strng, srec, count)
char strng[];
SYMBREC srec[];
register int count;
{
   register int j;

   FUNCTRACE("find");
   for (j = 0; j <= count; j++) {
      if (strncmp(strng, srec[j].Sname, NAMELEN) == 0)
         return(j);
   }
   return(-1);
}

/* ============================================================ */
int find2(strng, srec, count, dupchk)
char strng[];
SYMBREC srec[];
REGISTER int count;
int dupchk;
{
   REGISTER int j;
   static char found[MAXELTS];
   char temp[128];

   FUNCTRACE("find");
   for (j = 0; j <= count; j++) {
      if (strncmp(strng, srec[j].Sname, NAMELEN) == 0) {
         if (dupchk == OFF)
            return(j);
         else {
            if (found[j] == 0) {
               found[j] = 1;
               return(j);
            }
            else {
               strcpy(temp, "Multiple ATTLISTS exist for:  ");
               strncat(temp, strng, NAMELEN);
               terminate(1, temp);
            }
         }
      }
   }
   return(-1);
}
/* ============================================================ */
void ckattributes(srec, count)
SYMBREC srec[];
int count;
{
   int j, i, minusone = -1, token, namecount, attrcount,
   declcode, dfltcode, grpcount, readstat, eltnum;
   REGISTER int k;

   char eltnames[GRPCNT * (NAMELEN + 1)];
   REGISTER char *tptr;
   char grpnames[NAMELEN + 1];
   char dfltval[LITLEN + 1], attrname[NAMELEN], dummy[128];

   FUNCTRACE("ckattributes");
   attrtemp = safeopen(attrtname, O_RDONLY, ATTRTEMP);
   attrfile = safecreat(attrfname, ATTRFILE);
   if (setjmp(Xenv) != 0)
      errflag = 1;
   for(eltnum = 1;;eltnum++) {
      readstat = read(attrtemp, (char *) &namecount, sizeof(namecount));
      if (readstat != sizeof(namecount))
         break;
      for (tptr = eltnames, k = 0; k < namecount; k++) {
         read(attrtemp, tptr, NAMELEN + 1);
         /*         printf("%d.%d ATTLIST for element %s\n", eltnum, k, tptr);*/
         tptr += (NAMELEN + 1);
      }
      for (tptr = eltnames, j = 0; j < sizeof(eltnames); tptr++, j++) {
         if(*tptr == '\0')
            *tptr = ' ';
      }
      readstat = read(attrtemp, (char *) &attrcount, sizeof(attrcount));
      safewrite(attrfile, (char *) &namecount, sizeof (namecount));
      for(k = 0, tptr = eltnames; k < namecount; k++) {
         if((token = find2(tptr, srec, count, ON)) == -1){
            strcpy(dummy, "ELEMENT ");
            strncat(dummy, tptr, NAMELEN);
            strcat(dummy," NOT FOUND but referenced in ATTLIST");
            terminate(1, dummy);
         }
         safewrite(attrfile, (char *) &token, sizeof(token));
         tptr += (NAMELEN + 1);
      }
      safewrite(attrfile, (char *) &attrcount, sizeof(attrcount));
      for (i = 0; i < attrcount; i++) {
         memset(attrname, '\0', sizeof(attrname));
         readstat = read(attrtemp, attrname, sizeof(attrname));
         safewrite(attrfile, attrname, sizeof(attrname));

         readstat = read(attrtemp, (char *) &declcode, sizeof(declcode));
         safewrite(attrfile, (char *) &declcode, sizeof(declcode));
         if (declcode == NOTATION) {
            for(k = 0, tptr = eltnames; k < namecount; k++) {
               token = find2(tptr, srec, count, OFF);
               if (srec[token].Smin & (1 << 7))
                  syntxerr("notation attribute for empty content");
               tptr += (NAMELEN + 1);
            }
         }
         readstat = read(attrtemp, (char *) &dfltcode, sizeof(dfltcode));
         if (dfltcode == A_CONREF) {
            for(k = 0, tptr = eltnames; k < namecount; k++) {
               token = find2(tptr, srec, count, OFF);
               if (srec[token].Smin & (1 << 7))
                  syntxerr("CONREF attribute for empty content");
               tptr += (NAMELEN + 1);
            }
         }
         safewrite(attrfile, (char *) &dfltcode, sizeof(dfltcode));

         memset(dfltval, '\0', sizeof(dfltval));
         readstat = read(attrtemp, dfltval, sizeof(dfltval));
         safewrite(attrfile, dfltval, strlen(dfltval) + 1);

         readstat = read(attrtemp, (char *) &grpcount, sizeof(grpcount));
         safewrite(attrfile, (char *) &grpcount, sizeof(grpcount));
         for(j = 0; j < grpcount; j++) {
            memset (grpnames, '\0', sizeof(grpnames));
            readstat = read(attrtemp, grpnames, sizeof(grpnames));
            if (declcode == NOTATION)
               cknotation(grpnames);
            for(k = 0; k < NAMELEN; k++) {
               if (grpnames[k] == '\0')
                  grpnames[k] = ' ';
            }
            safewrite(attrfile, grpnames, NAMELEN);
         }
      }
   }
   safeclose(attrtemp, "attrtemp", ATTRTEMP);
   safewrite(attrfile, (char *) &minusone, sizeof(minusone));
   safeclose(attrfile, "attrfile", ATTRFILE);
}
/* ============================================================ */
void closeall()
{
   if (filemask & TREEFILE)
      safeclose(treefile,"treefile", TREEFILE);
   if (filemask & SYMBFILE)
      safeclose(symbfile,"symbolfile", SYMBFILE);
   if (filemask & ATTRTEMP)
      safeclose(attrtemp,"attrtemp", ATTRTEMP);
   if (filemask & PREFFILE)
      safeclose(preffile,"preffile", PREFFILE);
   if (filemask & GREFFILE)
      safeclose(greffile,"greffile", GREFFILE);
   if (filemask & ATTRFILE)
      safeclose(attrfile,"attrfile", ATTRFILE);
   if (filemask & DOCFILE)
      safefclose(docfile,"docfile", DOCFILE);
   if (filemask & XCPTFILE)
      safeclose(xcptfile,"exception", XCPTFILE);
   if (filemask & DTDFILE)
      safeclose(dtdfile,"dtdfile", DTDFILE);
   if (filemask & INCLFILE)
      safeclose(inclfile,"inclfile", INCLFILE);
   if (filemask & EXCLFILE)
      safeclose(exclfile,"exclfile", EXCLFILE);
   if (filemask & CMFILE)
      safefclose(cmfile,"cmfile", CMFILE);

   filemask = 0;
}
/* ============================================================ */
/* ============================================================ */
void unlinkall(flag)
int flag;
{
   (void) unlink(treefname);
   (void) unlink(symbfname);
   (void) unlink(attrtname);
   (void) unlink(exclfname);
   (void) unlink(inclfname);
   if (flag == TRUE) {
      (void) unlink(cmfname);
      (void) unlink(preffname);
      (void) unlink(greffname);
      (void) unlink(attrfname);
      (void) unlink(xcptfname);
   }
}
/* ============================================================ */


