/* 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:    DETUTIL.C                                          */
/*   AUTHOR:         Michael Garris                                     */
/*                                                                      */
/*   DATE CREATED:                                                      */
/*   LAST MODIFIED:                                                     */
/*                                                                      */
/*                  REVISIONS                                           */
/*   WHEN      WHO            WHY                                       */
/************************************************************************/
#include <stdio.h>
#include "detdefs.h"
#include "detglbl.h"
char *malloc();
/************************************************************************/
/************************************************************************/
/* NESTLEVEL inputs an expression at "iptr" and calculates the number of*/
/* nested levels of "()" in the expression, returning the calculation   */
/************************************************************************/
int nestlevel(iptr)
register ITEM *iptr;/* points to the expression */
{
   register int nest = 0;/* nest level */
   register int cntr = 0;/* current level */

   /* if iptr is not at a GRPO then a synchronization error has occurred */
   if(iptr++->itoken != GRPO){
      return(0);
   }
   /* otherwise a GRPO has been found and the nesting level gets bumped */
   ++nest;
   /* also a counter gets bumped for each GRPO found and decremented */
   /* for each GRPC found */
   ++cntr;
   /* while the counter is not 0 ==> not at the end of the expression ...*/
   while(cntr > 0){
      /* while neither a GRPO or a GRPC has been found ...*/
      while((iptr->itoken != GRPO) && (iptr->itoken != GRPC)){
         /* if a FSAid pointer is found in the expression, skip it */
         if(iptr->itoken == POINTER){
            /* invokes a procedure which moves iptr the size of a pointer */
            /*          commented out by Michael D. Garris on 11/23/87 */
            /*          due to the introduction of ITEM type           */
            /*            skippointer(&iptr);                          */
            iptr += 2;
            continue;
         }
         /* if not a pointer, GRPO, or GRPC then skip it */
         ++iptr;
      }
      /* if a GRPO is found ... */
      if(iptr->itoken == GRPO){
         /* bump the nesting level */
         ++nest;
         /* bump the current level */
         ++cntr;
      }
      /* if a GRPC is found ... */
      if(iptr->itoken == GRPC){
         /* decrement the current level */
         --cntr;
      }
      /* continue looking in the expression */
      ++iptr;
   }
   /* once the end of the expression is found, then return the */
   /* value in nestin level */
   return(nest);
}
/************************************************************************/
/************************************************************************/
/* GETLOWGRP takes an expression and scans it left to right until "nest"*/
/* number of "(" have been found, setting the expression pointer to that*/
/* location                                                             */
/************************************************************************/
void getlowgrp(ptrin, nest)
ITEM **ptrin;
register int nest;
{
   register ITEM *iptr = *ptrin;
   register int i;

   for(i = 0; i < nest; ++i){
      while(iptr++->itoken != GRPO);
   }
   *ptrin = --iptr;
}
/************************************************************************/
/************************************************************************/
/* SKIPPOINTER takes a pointer to a FSAid in an expression and moves the*/
/* pointer to just past the FSAid pointer                               */
/************************************************************************/
void skippointer(ptrin)
ITEM **ptrin;
{
   register ITEM *iptr = *ptrin;

   /* bump iptr by the size of a token, skipping the "-1" which */
   /* is in font of all FSAid pointers in the expression */
   ++iptr;
   /* increment iptr the size of a pointer, skipping the actual */
   /* FSAid pointer*/
   ++iptr;
   *ptrin = iptr;
}
/************************************************************************/
/************************************************************************/
/* GETTOKEN inputs a pointer to a token in an expression and returns the*/
/* token, extracting the space occupied by the token from the expression*/
/************************************************************************/
int gettoken(iptr)
register ITEM *iptr;
{
   register int token;

   /* if iptr is pointing to a valid token ...*/
   if((iptr->itoken > 0x10) && (iptr->itoken < 0xFF))
      /* then assign token what iptr is pointing to */
      token = iptr->itoken;
   else
      /* otherwise a synchronization error has occurred */
      myexit(1,"Token not found in group");
   /* invokes a procedure which removes the space the size of an int */
   /* from the expression at iptr */
   stripunit(INT,iptr);
   /* returns the token */
   return(token);
}
/************************************************************************/
/************************************************************************/
/* GETOCCIND takes a pointer to an occurance indicator in an expression */
/* and returns the occurance indicator, extracting the space occupied   */
/* by the occurance indicator from the expression .                     */
/************************************************************************/
int getoccind(iptr)
ITEM *iptr;
{
   int occind;

   switch(iptr->itoken){
      /* if iptr points to an optional occurance indicator ...*/
   case OPT:
      occind = OPT;
      break;
      /* if iptr points to an optional-repeatable occ. indicator ...*/
   case REP:
      occind = REP;
      break;
      /* if iptr points to a required-repeatable occ. indicator ...*/
   case PLUS:
      occind = PLUS;
      break;
      /* if iptr points to a required occurance indicator ... */
   case REQ:
      occind = REQ;
      break;
   }
   /* invokes a procedure which removes the space the size of an int */
   /* from the expression at iptr */
   stripunit(INT,iptr);
   /* return the occurance indicator */
   return(occind);
}
/************************************************************************/
/************************************************************************/
/* BUILDSTATE allocates memory for a structure called a state, returning*/
/* a pointer to the allocated memory and setting all components of the  */
/* structure to NULL.                                                   */
/* A state is made of a left and right pointer pointing to other state  */
/* structures, a left and right label marking each respective pointer,  */
/* and a left and right instance number for each respective label.      */
/************************************************************************/
STATE *buildstate()
{
   register STATE *state;/* pointer memory will be allocated to */

   /* allocate memory to "state" the size of a state structure */
   state = mymalloc(sizeof(STATE));
   /* if malloc returned 0 then a memory allocation has occurred */
   if(state == 0)
      myexit(1, "Memory allocation error");
   /* set all the fields of the components of the structure to NULL */
   state -> lptr = NULL;
   state -> llabel = NULL;
   state -> linst = NULL;
   state -> rptr = NULL;
   state -> rlabel = NULL;
   state -> rinst = NULL;
   /* return a pointer to the allocated memory */
   return(state);
}
/************************************************************************/
/************************************************************************/
/* BUILDID allocates memory to a structure called a FSAid, returning a  */
/* pointer to the allocated memory and setting all components of the    */
/* structure to NULL.                                                   */
/* A FSAid is made of two pointers to state structures. The startptr    */
/* points to the start state of an FSA, and the finalptr points to the  */
/* final state of the same FSA.                                         */
/************************************************************************/
STATEID *buildid()
{
   register STATEID *stateid;

   /* allocate memory the size of a FSAid structure to the */
   /* pointer "stateid" */
   stateid = (STATEID *)malloc(sizeof(STATEID));
   /* if malloc returns 0 then a memory allocation error occurred */
   if(stateid == 0)
      myexit(1,"Memory allocation error");
   /* set both pointers of the FSAid structure to NULL */
   stateid -> startptr = NULL;
   stateid -> finalptr = NULL;
   /* return the pointer to the allocated memory */
   return(stateid);
}
/************************************************************************/
/************************************************************************/
/* INSERTPOINTER takes a pointer to a location within an expression and */
/* inserts space for the inputted FSAid, placing the FSAid into the     */
/* expression.                                                          */
/************************************************************************/
void insertpointer(ptrin,stateid)
ITEM **ptrin;
STATEID *stateid;
{
   register ITEM *iptr = *ptrin;

   /* invoke procedure to insert space the size of an int into */
   /* the expression at location iptr */
   makeroom(INT,iptr);
   /* place a "-1" flagging, FSAid pointer following, */
   /* into the expression */
   iptr++->itoken = POINTER;
   /* invokes a procedure to insert space the size of a FSAid */
   /* pointer into the expression */
   makeroom(PTR,iptr);
   /* place the FSAid pointer into the expression */
   iptr++->ptoken = stateid;
   *ptrin = iptr;
}
/************************************************************************/
/************************************************************************/
/* MAKEROOM takes a pointer to an expression and insets space the size  */
/* indicated by "type" at the location of the pointer.                  */
/************************************************************************/
void makeroom(type,iptr)
int type;
ITEM *iptr;
{
   int dif;
   register int j;
   register char *src, *dest;
   char temp[400];

   /* assign "dif" the difference from the current location */
   /* in the expression "iptr" to the end of the expression */
   j = dif = (endbuf - iptr) * sizeof(ITEM);
   /* move the section of expression from the current pointer on */
   /* to the right the distance of "size" */
   src = (char *) iptr;
   dest = temp;
   while (j--)
      *dest++ = *src++;
   src = temp;
   dest = (char *)(iptr + 1);
   while(dif--)
      *dest++ = *src++;
#ifdef OLD
   memcpy((char *)(iptr + 1), (char *)iptr, dif);
#endif
   /* calculate a new end of expression */
   endbuf++;
}
/************************************************************************/
/************************************************************************/
/* FINDENDOFGRP takes a pointer to the current location in an expression*/
/* along with the current number of nested levels and scans to the right*/
/* of the pointer until the end of the expression is found, retruning   */
/* a pointer to the end of the expression.                              */
/************************************************************************/
ITEM *findendofgrp(iptr,nest)
register ITEM *iptr;
int nest;
{
   register int cntr;/* will be the current level of nesting */

   /* assign "cntr" the current level of nesting */
   cntr = nest;
   /* while current level of nesting is > 0 ==> not end of expression ...*/
   while(cntr > 0){
      /* while neither a GRPO or a GRPC is found ...*/
      while((iptr->itoken != GRPO) && (iptr->itoken != GRPC)){
         /* if iptr is pointing to an FSAid pointer ...*/
         if(iptr->itoken == POINTER){
            /* invokes a procedure to move the expression pointer */
            /* just past the FSAid pointer */
            iptr += 2;
            /*            changed by Michael D. Garris 11/23/87        */
            /*            commented out with the addition of ITEM type */
            /*            skippointer(&iptr);                          */
            continue;
         }
         /* continue looking right in expression */
         ++iptr;
      }
      /* if GRPO found ...*/
      if(iptr->itoken == GRPO){
         /* bump nesting level and current nesting level */
         ++nest;
         ++cntr;
      }
      /* if GRPC found ...*/
      if(iptr->itoken == GRPC){
         /* decrement current nesting level */
         --cntr;
      }
      /* continue scanning to the right */
      ++iptr;
   }
   /* return pointer to end of expression */
   return(iptr+1);
}
/************************************************************************/
/************************************************************************/
/* STRIPUNIT takes a pointer to an expression and removes a location the*/
/* size indicated by "type" from the expression at the pointer          */
/************************************************************************/
void stripunit(type,iptr)
int type;
ITEM *iptr;
{
   int dif;

   /* assign "dif" the difference from the current expression */
   /* pointer to the end of the expression */
   dif = (endbuf - iptr + 1) * sizeof(ITEM);
   /* move the section of expression from the current pointer plus */
   /* the size of the unit being stripped on to the current pointer*/
   memcpy((char *)iptr,(char *)(iptr + 1),dif);
   /* calculate a new end of expression pointer */
   endbuf -= 1;
}
/************************************************************************/
/************************************************************************/
/* COPY takes a section of expression at "scr" of length "len" and moves*/
/* it to location "dest" in the expression.                             */
/************************************************************************/
void copy(dest,src,len)
register char *dest,*src;
register int len;
{
   /* if section being moved is to the right of the destination ...*/
   if(src >= dest){
      /* while "length" units have not yet been moved ...*/
      while((len--) > 0){
         /* copy contents of source to destination and continue */
         *dest++ = *src++;
      }
   }
   /* otherwise section being moved is to the left of the destination */
   /* and a left to right transfer of contents could result in valid   */
   /* data being over-written */
   else{
      /* if destination is to the right of the source ...*/
      if(dest > src)
         /* while "length" units have not yet been move ...*/
         while(len-- > 0){
            /* copy contents of source to destination right to left */
            /* from the end of the source */
            *(dest + len) = *(src + len);
         }
   }
}
/************************************************************************/
/************************************************************************/
/* GETCONNECTOR inputs a pointer to a connector in an expression and    */
/* returns the connector, extracting the space occupied by the connector*/
/* from the expression.                                                 */
/************************************************************************/
int getconnector(iptr)
ITEM *iptr;
{
   int connector;

   /* assign "connector" the contents of the expression pointer */
   connector = iptr->itoken;
   /* invokes a procedure to extract the space of an int from */
   /* the expression at location "iptr"*/
   stripunit(INT,iptr);
   /* returns the connector */
   return(connector);
}
/************************************************************************/
/************************************************************************/
/* MYEXIT inputs an error code and an error message, printing the       */
/* message and exiting on the error code.                               */
/************************************************************************/
void myexit(code,msg)
int code;
char *msg;
{
   printf("%s\n",msg);
   exit(code);
}
/************************************************************************/
/************************************************************************/
/* SEARCHTOKEN searches a list of tokens,"tokseen", for matches on the  */
/* value "token", returning the number of matches which occurred.       */
/************************************************************************/
int searchtoken(token,tokseen,tokptr)
register int token;
ITEM *tokseen,*tokptr;
{
   register ITEM *ptr = tokseen;/* set "ptr" to beginning of token list */
   int inst = 0;/* will be the number of matches which occur */

   /* while not end of the token list ...*/
   while(ptr != tokptr){
      /* if a match on the "token" occurs...*/
      if(ptr++->itoken == token)
         /* bump the instance counter */
         ++inst;
   }
   /* return the number of matches */
   return(inst);
}
/************************************************************************/
/************************************************************************/
/****** M Y M A L L O C *************************************************/
/*  this will create a linked list to track all malloc's ****************/
/************************************************************************/
STATE *mymalloc(size)
int size;
{
   STATE *statetemp;
   register MEMNODE *memtemp,*curmem;
   curmem = head;
   if ((statetemp = (STATE *)malloc(size)) == NULL) {
      printf("Memory Allocation Error\n");
      exit(99);
   }
   if ((memtemp = (MEMNODE *)malloc(sizeof(MEMNODE))) == NULL) {
      printf("Memory Allocation Error\n");
      exit(99);
   }
   (*memtemp).stateptr = statetemp;
   (*memtemp).memnodeptr = NULL;
   if ( head == NULL )
      head = memtemp;   /* head is null; first time thru */
   else {
      while ( (*curmem).memnodeptr != NULL )
         curmem = (*curmem).memnodeptr;  /* find the end of list */
      (*curmem).memnodeptr = memtemp;
   }
   return((*memtemp).stateptr);
}
/************************************************************************/
/** F R E E F S A *******************************************************/
/************************************************************************/
freeFSA()
{
   register MEMNODE *curmem,*temp;

   curmem = head;
   if ( head == NULL )
      return;
   while ( curmem != NULL ){
      temp = (*curmem).memnodeptr;
      free((char *) ((*curmem).stateptr));
      free((char *) curmem);
      curmem = temp;
   }
}
/************************************************************************/

