/* 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:    DTDGRPS.C                                          */
/*   AUTHOR:         Jim Heath                                          */
/*                                                                      */
/*   DATE CREATED:                                                      */
/*   LAST MODIFIED:                                                     */
/*                                                                      */
/*                  REVISIONS                                           */
/*   WHEN      WHO            WHY                                       */
/************************************************************************/
#include <stdio.h>
#include <setjmp.h>
#include "qntyset.h"
#include "dtd.h"
#include "dtdfncs.h"
#include "dtdglbl.h"

typedef enum {
   sawGRPO, sawGRPC, inNAME, endofNAME, sawOI, sawCONNECTOR, sawEE, endGRP}
STATES;
STATES state = sawGRPO;
static char cm[1024];
static char *cmptr = cm;
int nestlvl, namelength;

/* ============================================================ */
#define NAMEGROUP 0
#define CONTENTMODEL 1

char *getagroup( flag)
int flag;    /* 0 => namegroup, 1 => contentmodel */
{
   register int count = 0, c;

   FUNCTRACE("getagroup");
   cmptr = cm;
   nestlvl = 0;
   memset(cm, '\0', sizeof(cm));

   state = sawGRPO;
   for (count = 0; ;count++) {
      if (count != 0)
         if (nestlvl == 0)
            break;
      switch(state) {
      case sawGRPO:
         state = (STATES) dosawGRPO();
         break;
      case sawGRPC:
         state = (STATES) dosawGRPC();
         break;
      case endGRP:
         state = (STATES) doendGRP();
         break;
      case inNAME:
         state = (STATES) doinNAME();
         break;
      case sawOI:
         if (flag == NAMEGROUP)
            syntxerr("illegal character in name token group");
         state = (STATES) dosawOI();
         break;
      case sawCONNECTOR:
         state = (STATES) dosawCONNECTOR();
         break;
      case endofNAME:
         state = (STATES) doendofNAME();
         break;
      case sawEE:
         state = (STATES) dosawEE();
         break;
      default:
         terminate(1, "illegal state in getagroup");
      }
   }
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1, "EOF in element declaration");
   if (isoi(c)) {
      ADDCHAR(c);
      *cmptr++ = c;
   }
   else
      jungetc(c);
   return(cm);
}
/* ============================================================ */
int dosawGRPO()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   if (issepchar(c))
      return(sawGRPO);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPO){
      nestlvl++;
      return(sawGRPO);
   }
   if (c == RNI || (isnmchar(c))) {
      namelength = 1;
      return(inNAME);
   }
   syntxerr("syntxerr in group model");
}
/* ============================================================ */
int dosawGRPC()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(endGRP);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPC){
      nestlvl--;
      return(sawGRPC);
   }
   if (isoi(c))
      return(sawOI);
   if (isconnector(c))
      return(sawCONNECTOR);
   if ((char) c == EE)
      return(sawEE);
   syntxerr("syntxerr in group");
}
/* ============================================================ */
int doendGRP()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(endGRP);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPC){
      nestlvl--;
      return(sawGRPC);
   }
   if (isconnector(c))
      return(sawCONNECTOR);
   if ((char) c == EE)
      return(sawEE);
   syntxerr("syntxerr in group");
}
/* ============================================================ */
int doinNAME()
{
   register int c;
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(endofNAME);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPC){
      nestlvl--;
      return(sawGRPC);
   }
   if (isoi(c))
      return(sawOI);
   if (isconnector(c))
      return(sawCONNECTOR);
   if (issepchar(c))
      return(endofNAME);
   if (isnmchar(c)) {
      if (++namelength > NAMELEN)
         syntxerr("name too long in group");
      return(inNAME);
   }
   if ((char) c == EE)
      return(sawEE);
   syntxerr("syntxerr in group");
}
/* ============================================================ */
dosawOI()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(sawOI);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPC){
      nestlvl--;
      return(sawGRPC);
   }
   if (isconnector(c))
      return(sawCONNECTOR);
   printf("unexpected character = %04x\n", c);
   syntxerr("syntx error in group");
}

/* ============================================================ */
dosawCONNECTOR()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(sawCONNECTOR);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPO){
      nestlvl++;
      return(sawGRPO);
   }
   if (c == RNI || (isnmchar(c))) {
      namelength = 1;
      return(inNAME);
   }
   syntxerr("syntxerr in group");
}
/* ============================================================ */
doendofNAME()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(endofNAME);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPC){
      nestlvl--;
      return(sawGRPC);
   }
   if (isconnector(c))
      return(sawCONNECTOR);
   syntxerr("syntxerr in group");
}
/* ============================================================ */
dosawEE()
{
   register int c;
   INPTS();
   if ((c = TOUPPER(jgetc())) == EOF)
      terminate(1,"EOF in declaration");
   c &= 0xFF;
   if (issepchar(c))
      return(sawEE);
   ADDCHAR(c);
   *cmptr++ = c;
   if (c == GRPC){
      nestlvl--;
      return(sawGRPC);
   }
   if (isconnector(c))
      return(sawCONNECTOR);
   syntxerr("syntxerr in group");
}
/* ============================================================ */
INPTS()
{
   char namearray[NAMELEN + 1], *nameptr = namearray;
   char *resptr;
   register int c, synkey;
   do {
      if ((c = jgetc()) == EOF)
         return(EOF);
   }   while (issepchar(c));
   c &= 0xFF;
   if (c != PERO) {
      jungetc(c);
      return;
   }
   /* input the parameter entity name */
   if (INPNAME(&nameptr, NAMELEN - 1, noxlat) < GOOD)
      syntxerr("syntxerr while processing group");
   nameptr = namearray;
   synkey = search(PARM_ENT_NAME, nameptr, &resptr);
   if (synkey != NULL)
      syntxerr("syntxerr while processing group");
   if((c = jgetc()) == EOF)
      terminate(1, "End of File found while resolving parameter entity reference");
   if(c != REFC)
      jungetc(c);
   /* unget parameter literal */
   ckts(resptr);
   ungetreslv(resptr);
   /* indicate we are within an entity */
   SETFLAG(IN_ENTITY);
}
/* ============================================================ */
void ckts(ptr)
char *ptr;
{
   register char *tptr;
   register int nestlvl = 0;

   /* first scan through cking that GRPO's balance GRPC's */
   for (tptr = ptr, nestlvl = 0; *tptr != '\0'; tptr++) {
      if (*tptr == GRPO)
         nestlvl++;
      else if (*tptr == GRPC)
         nestlvl--;
      if (nestlvl < 0)
         syntxerr("unbalanced GRPO's/GRPC's parameter entity reference");
   }
   if (nestlvl != 0)
      syntxerr("syntxerr in parameter entity");
}
/* ============================================================ */
int issepchar(c)
char c;
{
   switch (c) {
   case ' ':
   case CR:
   case LF:
   case TAB:
      return(TRUE);
   }
   return(FALSE);
}
/* ============================================================ */
/* ============================================================ */
/* ============================================================ */
/* ============================================================ */
/* ============================================================ */
/* ============================================================ */
/* ============================================================ */
/* ============================================================ */
