diff -c2N ../arcsgml/Makefile ./Makefile
*** ../arcsgml/Makefile
--- ./Makefile	Sun Aug  4 10:56:31 1991
***************
*** 0 ****
--- 1,93 ----
+ # Makefile for vm2 on Unix.
+ CC=gcc
+ CFLAGS=-g -funsigned-char -W -O
+ LDFLAGS=-g
+ LIBS=
+ BINDIR=/local/bin
+ MSGFILE=sgml.msg
+ INSTALL=install
+ # command to install MSGFILE
+ MSGINSTALL=install -m 0444
+ 
+ PROG=vm2
+ 
+ OBJS =  \
+   arclexrf.o \
+   arcpcbrf.o \
+   arcsynrf.o \
+   context.o \
+   modmd1.o \
+   modmd2.o \
+   modpars1.o \
+   modpars2.o \
+   modserv.o \
+   modsgml1.o \
+   modsgml2.o \
+   sgmlapi.o \
+   sgmlmem.o \
+   sgmlmsg.o \
+   sgmlxtrn.o \
+   traceset.o \
+   uxsgmlio.o \
+   vm2.o \
+   vmxtrn.o
+ 
+ all: $(PROG)
+ 
+ $(PROG): $(OBJS)
+ 	$(CC) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIBS)
+ 
+ install: $(PROG) $(MSGFILE)
+ 	$(INSTALL) $(PROG) $(BINDIR)
+ 	$(MSGINSTALL) $(MSGFILE) $(BINDIR)
+ 
+ clean:
+ 	-rm -f $(OBJS) $(PROG) core a.out
+ 
+ arclexrf.o : arclexrf.c entity.h tools.h synxtrn.h action.h adl.h lextoke.h
+ arcpcbrf.o : arcpcbrf.c entity.h tools.h action.h synxtrn.h adl.h
+ arcsynrf.o : arcsynrf.c entity.h tools.h synxtrn.h adl.h
+ context.o : context.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modmd1.o : modmd1.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modmd2.o : modmd2.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modpars1.o : modpars1.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modpars2.o : modpars2.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modserv.o : modserv.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modsgml1.o : modsgml1.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ modsgml2.o : modsgml2.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ sgmlapi.o : sgmlapi.c sgmlapi.h vmincl.h entity.h tools.h synxtrn.h \
+   source.h adl.h etype.h sgmlcb.h sgmlmain.h uxenvcb.h vmfnsm.h vmxtrn.h \
+   sgmlsubs.c
+ sgmlmem.o : sgmlmem.c vmincl.h entity.h tools.h synxtrn.h source.h adl.h \
+   etype.h sgmlcb.h sgmlmain.h uxenvcb.h vmfnsm.h vmxtrn.h
+ sgmlmsg.o : sgmlmsg.c vmincl.h entity.h tools.h synxtrn.h source.h adl.h \
+   etype.h sgmlcb.h sgmlmain.h uxenvcb.h vmfnsm.h vmxtrn.h
+ sgmlsubs.o : sgmlsubs.c
+ sgmlxtrn.o : sgmlxtrn.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ traceset.o : traceset.c sgmlincl.h entity.h tools.h action.h adl.h error.h \
+   etype.h keyword.h lextoke.h source.h sgmlcb.h synxtrn.h sgmlxtrn.h trace.h \
+   sgmlfnsm.h
+ uxsgmlio.o : uxsgmlio.c vmincl.h entity.h tools.h synxtrn.h source.h adl.h \
+   etype.h sgmlcb.h sgmlmain.h uxenvcb.h vmfnsm.h vmxtrn.h
+ vm2.o : vm2.c sgmlapi.h vmincl.h entity.h tools.h synxtrn.h source.h adl.h \
+   etype.h sgmlcb.h sgmlmain.h uxenvcb.h vmfnsm.h vmxtrn.h
+ vmxtrn.o : vmxtrn.c vmincl.h entity.h tools.h synxtrn.h source.h adl.h \
+   etype.h sgmlcb.h sgmlmain.h uxenvcb.h vmfnsm.h
diff -c2N ../arcsgml/modmd2.c ./modmd2.c
*** ../arcsgml/modmd2.c	Sun Jul 21 09:43:49 1991
--- ./modmd2.c	Sat Jul 20 17:33:37 1991
***************
*** 352,356 ****
  
       p = f->fpipubis;                   /* Point to start of identifier. */
!      l = *p + p++ -1;                   /* Point to EOS of identifier. */
       if (*p=='+' || *p=='-') {          /* If owner registered, unregistered. */
            f->fpiot = *p;                /* Save owner type. */
--- 352,359 ----
  
       p = f->fpipubis;                   /* Point to start of identifier. */
!      l = *p + p -1;                   /* Point to EOS of identifier. */
!      /* Do this as a separate statement so as to avoid depending on order of
! 	evaluation. */
!      p++;
       if (*p=='+' || *p=='-') {          /* If owner registered, unregistered. */
            f->fpiot = *p;                /* Save owner type. */
diff -c2N ../arcsgml/modpars2.c ./modpars2.c
*** ../arcsgml/modpars2.c	Sun Jul 21 09:43:50 1991
--- ./modpars2.c	Sun Aug  4 10:52:16 1991
***************
*** 173,178 ****
               adding an offset to it (sw.addnonch) modulo 256.
  */
! UNCH shiftnon(nonchar)
! UNCH nonchar;                 /* Non-SGML character. */
  {
       return (UNCH)((nonchar+sw.addnonch) % 256);
--- 173,178 ----
               adding an offset to it (sw.addnonch) modulo 256.
  */
! UNCH shiftnon(
! UNCH nonchar)                 /* Non-SGML character. */
  {
       return (UNCH)((nonchar+sw.addnonch) % 256);
***************
*** 654,662 ****
               TODO: Return 1 if CDATA, SDATA or NONSGML occurred.
  */
! VOID parselit(tbuf, pcb, maxlen, del)
! UNCH *tbuf;                   /* Work area for tokenization (parmlen+1). */
! struct parse *pcb;            /* Current parse control block. */
! UNS maxlen;                   /* Maximum length of token. */
! UNCH del;                     /* Literal delimiter: LIT LITA PIC EOS */
  {
       UNCH *pt = tbuf;         /* Current pointer into tbuf. */
--- 654,662 ----
               TODO: Return 1 if CDATA, SDATA or NONSGML occurred.
  */
! VOID parselit(
! UNCH *tbuf,                   /* Work area for tokenization (parmlen+1). */
! struct parse *pcb,            /* Current parse control block. */
! UNS maxlen,                   /* Maximum length of token. */
! UNCH del)                     /* Literal delimiter: LIT LITA PIC EOS */
  {
       UNCH *pt = tbuf;         /* Current pointer into tbuf. */
***************
*** 992,1000 ****
  */
  /*lint +fvr                      Returned value may be ignored. */
! UNCH *parsetkn(tbuf, scope, maxlen)
  /*lint -fvr                      Restore normal LINT processing. */
- UNCH   *tbuf;                 /* Buffer for token: >=maxlen+2. */
- UNCH   scope;                 /* Minimum lexical class allowed. */
- int    maxlen;                /* Maximum length of a token. */
  {
       UNCH   len;              /* Length of token (incl EOS & length byte). */
--- 992,1000 ----
  */
  /*lint +fvr                      Returned value may be ignored. */
! UNCH *parsetkn(
! UNCH   *tbuf,                 /* Buffer for token: >=maxlen+2. */
! UNCH   scope,                 /* Minimum lexical class allowed. */
! int    maxlen)                /* Maximum length of a token. */
  /*lint -fvr                      Restore normal LINT processing. */
  {
       UNCH   len;              /* Length of token (incl EOS & length byte). */
***************
*** 1041,1049 ****
              Returns a pointer to the created name.
  */
! UNCH *s2valnm(n, s, scope, nc)
! UNCH *n;                      /* Name to be created. */
! UNCH *s;                      /* Source string to be parsed as name. */
! UNCH scope;                   /* Minimum lexical class allowed. */
! int nc;                       /* Namecase translation: 1=yes; 0=no. */
  {
       UNCH len = 0;            /* Length of name (incl EOS and length). */
--- 1041,1049 ----
              Returns a pointer to the created name.
  */
! UNCH *s2valnm(
! UNCH *n,                      /* Name to be created. */
! UNCH *s,                      /* Source string to be parsed as name. */
! UNCH scope,                   /* Minimum lexical class allowed. */
! int nc)                       /* Namecase translation: 1=yes; 0=no. */
  {
       UNCH len = 0;            /* Length of name (incl EOS and length). */
diff -c2N ../arcsgml/modsgml1.c ./modsgml1.c
*** ../arcsgml/modsgml1.c	Sun Jul 21 09:43:51 1991
--- ./modsgml1.c	Sat Jul 20 16:38:04 1991
***************
*** 73,77 ****
                      rcbdaf.data = tags[ts].tsrm!=SRMNULL
                                    ? tags[ts].tsrm[0]->ename : 0;
!                     rcbdaf.datalen = *rcbdaf.data;
                      rcbdaf.sgmles = es;    /* Current level in scb stack. */
                      scbset();              /* Update location in current scb. */
--- 73,77 ----
                      rcbdaf.data = tags[ts].tsrm!=SRMNULL
                                    ? tags[ts].tsrm[0]->ename : 0;
!                     rcbdaf.datalen = rcbdaf.data ? *rcbdaf.data : 0;
                      rcbdaf.sgmles = es;    /* Current level in scb stack. */
                      scbset();              /* Update location in current scb. */
***************
*** 301,305 ****
  
       memcpy((UNIV)&it, (UNIV)ipb, sizeof(it));
!      memcpy(iname, it.itnm, sizeof(iname));
       switch (it.ipbtype) {
  
--- 301,306 ----
  
       memcpy((UNIV)&it, (UNIV)ipb, sizeof(it));
!      if (it.itnm)
!        memcpy(iname, it.itnm, sizeof(iname));
       switch (it.ipbtype) {
  
diff -c2N ../arcsgml/modsgml2.c ./modsgml2.c
*** ../arcsgml/modsgml2.c	Sun Jul 21 09:43:51 1991
--- ./modsgml2.c	Sat Jul 20 18:40:26 1991
***************
*** 228,233 ****
  VOID scbset(void)
  {
!      CC = *FPOS;
!      CCO = (UNS)(FPOS+1-FBUF);
       return;
  }
--- 228,235 ----
  VOID scbset(void)
  {
!      if (FBUF) {
!        CC = *FPOS;
!        CCO = (UNS)(FPOS+1-FBUF);
!      }
       return;
  }
diff -c2N ../arcsgml/sgmlapi.h ./sgmlapi.h
*** ../arcsgml/sgmlapi.h	Sun Jul 21 09:43:52 1991
--- ./sgmlapi.h	Sat Jul 20 12:23:01 1991
***************
*** 116,120 ****
  void sgmloset(void);          /* Initialize for SGML option processing. */
  void sgmlset(void);           /* Initialize the parser for the run. */
! int docent(unsigned char *);  /* Initialize the SGML document entity. */
  int sgmlpset(void);           /* Initialize pass; open document entity. */
  int sgmlnext(void);           /* Get next SGML event: data, tag, etc. */
--- 116,120 ----
  void sgmloset(void);          /* Initialize for SGML option processing. */
  void sgmlset(void);           /* Initialize the parser for the run. */
! int docent(char *);	      /* Initialize the SGML document entity. */
  int sgmlpset(void);           /* Initialize pass; open document entity. */
  int sgmlnext(void);           /* Get next SGML event: data, tag, etc. */
diff -c2N ../arcsgml/sgmlfnsm.h ./sgmlfnsm.h
*** ../arcsgml/sgmlfnsm.h	Sun Jul 21 09:43:52 1991
--- ./sgmlfnsm.h	Sun Aug  4 10:53:31 1991
***************
*** 9,13 ****
  /******************************************************************************/
  void           adlval(int,struct etd *);
! void           aenttst(int, unsigned char *);
  int            allhit(struct thdr *,long,int,int);
  int            amemget(struct ad *,int,char *);
--- 9,13 ----
  /******************************************************************************/
  void           adlval(int,struct etd *);
! void           aenttst(int, char *);
  int            allhit(struct thdr *,long,int,int);
  int            amemget(struct ad *,int,char *);
diff -c2N ../arcsgml/sgmlmsg.c ./sgmlmsg.c
*** ../arcsgml/sgmlmsg.c	Sun Jul 21 09:43:53 1991
--- ./sgmlmsg.c	Sun Jul 21 00:53:02 1991
***************
*** 7,13 ****
  #include "vmxtrn.h"           /* Declarations for VM public variables. */
  /******************************************************************************/
! #define REALEOF '\032'        /* Ctl-Z is read as part of file in binary mode.*/
! #define FOPENRD "rb"          /* Binary not default: specify it. */
! #define MTRUNC 2              /* Truncate trailing CR/LF from msgs and parms. */
  /******************************************************************************/
  #define MAXARGLN FILESPEC     /* Maximum length of an argument in a msg. */
--- 7,11 ----
  #include "vmxtrn.h"           /* Declarations for VM public variables. */
  /******************************************************************************/
! #define MTRUNC 1              /* Truncate trailing LF from msgs and parms. */
  /******************************************************************************/
  #define MAXARGLN FILESPEC     /* Maximum length of an argument in a msg. */
***************
*** 58,62 ****
       for (i = 0; ++i<=margc;) {                   /* Get args from SGML. */
            margpos[i-1] -= '0';                    /* Convert to number. */
!           memcpy( margv[i] , ie->eparm[i-1], (UNS)MAXARGLN );
            margv[i][MAXARGLN] = '\0';              /* Truncate for safety. */
       }
--- 56,60 ----
       for (i = 0; ++i<=margc;) {                   /* Get args from SGML. */
            margpos[i-1] -= '0';                    /* Convert to number. */
!           strncpy( margv[i] , ie->eparm[margpos[i-1] - 1], (UNS)MAXARGLN );
            margv[i][MAXARGLN] = '\0';              /* Truncate for safety. */
       }
***************
*** 111,118 ****
            exit(007);
       }
!      msgfp = fopen(pd, FOPENRD);
  
       /* Place offsets in message number array. */
!      for (offset = 0; fgets(pd, MAXMSGLN+1, msgfp) && *pd!=REALEOF;
            offset = ftell(msgfp)) {
            /* Skip blank lines and those with * as first nonblank. */
--- 109,117 ----
            exit(007);
       }
!      /* Don't use binary mode. */
!      msgfp = fopen(pd, "r");
  
       /* Place offsets in message number array. */
!      for (offset = ftell(msgfp); fgets(pd, MAXMSGLN+1, msgfp);
            offset = ftell(msgfp)) {
            /* Skip blank lines and those with * as first nonblank. */
Common subdirectories: ../arcsgml/test and ./test
diff -c2N ../arcsgml/tools.h ./tools.h
*** ../arcsgml/tools.h	Sun Jul 21 09:43:55 1991
--- ./tools.h	Sun Jul 21 00:55:36 1991
***************
*** 8,12 ****
--- 8,18 ----
  
  #define VOID void             /* For compilers that don't support void yet. */
+ #ifdef unix
+ /* Strings have a byte representing the length at the beginning, so they can't be
+ longer than this. */
+ #define FILESPEC (255)
+ #else
  #define FILESPEC 2+64+1+8+4+(2)  /* DOS: Maximum length of a file id + (2). */
+ #endif
  #define ZAPEOL(cc) ((cc!=0&&cc!=9&&cc!=10&&cc!=13&&cc!=26&&cc!=28) ? cc : 168)
  
diff -c2N ../arcsgml/uxenvcb.h ./uxenvcb.h
*** ../arcsgml/uxenvcb.h
--- ./uxenvcb.h	Sat Jul 20 22:38:22 1991
***************
*** 0 ****
--- 1,22 ----
+ /******************************************************************************/
+ /* ENVCB.H: Control blocks used by text processor environment.                */
+ /******************************************************************************/
+ /* Define I/O types for document files (message files are always stream I/O). */
+ /******************************************************************************/
+ typedef FILE * HANDLE;      /* Stream I/O: handle is control block ptr. */
+ /******************************************************************************/
+ struct iofcb {                /* I/O file control block. */
+      HANDLE fcbfd;            /* DOS file handle. */
+      long fcboff;             /* Offset in file of current read block. */
+      char *fcbxid;            /* External ID string. */
+      char *fcbnext;           /* Next file in fcbxid (NULL if no more). */
+      char fcbfile[FILESPEC+2];/* Full system fileid (length + EOS). */
+      int fcbcatsw;            /* 1=catenate next file on next read; 0=no. */
+      int fcbRS;               /* 1=prefix RS to first file of entity; 0=no. */
+      int fcbRE;               /* 1=strip RE from last file of entity; 0=no. */
+      int fcbfirst;            /* 1=next read will be the first; 0=no. */
+      int fcbpend;	      /* 1=prefix RS to next read; 0=no. */
+ };
+ #define IPBFCB ((struct iofcb *)io->ipbn)      /* IPBFILE: Ptr to SGMLIO fcb. */
+ #define FLID (((struct iofcb *)SCBFCB)->fcbfile)/* Actual fileid of file. */
+ /******************************************************************************/
diff -c2N ../arcsgml/uxsgmlio.c ./uxsgmlio.c
*** ../arcsgml/uxsgmlio.c
--- ./uxsgmlio.c	Sun Jul 21 11:35:45 1991
***************
*** 0 ****
--- 1,441 ----
+ /******************************************************************************/
+ /* SGMLIO: Unix version, based on ndsgmlio.src.                                */
+ /******************************************************************************/
+ 
+ /* Uses only stream I/O. Only srchpath() and xidgen() should need to
+ be changed when porting to another ANSI C environment. */
+ 
+ #include "vmincl.h"           /* Include files for VM. */
+ #include "vmxtrn.h"           /* Declarations for VM public variables. */
+ /******************************************************************************/
+ #define OKIO(handle) ((handle) != NULL)  /* OPEN return: 1=good; 0=error. */
+ /******************************************************************************/
+ /* Functions used in this module only.
+ */
+ struct iofcb *fcbgen(char *);
+ void fcbnext(struct iofcb *);
+ void readeof(struct iofcb *, char *, int *);
+ int readcat(struct iofcb *);
+ int readfrst(struct iofcb *, char *);
+ char *srchpath(char *);
+ int testopen(char *);
+ void lwrcpy(char *, char *, int);
+ /******************************************************************************/
+ /* SGMLIO: Text processor I/O services for SGML.
+    SGML must see a file in which RE and RS (CR/LF) are present between records,
+    and EOFCHAR (Ctl-Z) is present at the end.  SGMLIO must supply these
+    characters if they are not naturally present in the file.
+    SGML will open two files at a time: when an entity is nested, the
+    new file is opened before closing the old in order to make sure the
+    open is successful. If it is, the original open file is closed temporarily
+    (FILEPEND); when the stack is popped, the new file is closed and the original
+    file is re-opened (FILECONT). SGML will check error returns
+    for the initial open of a file and all reads, and for re-openings when the
+    stack is popped, but not for closes.  Setting io.ipbrc<0 indicates
+    an error; 0 or more is a successful operation,
+    except for READ where io.ipbrc is the number of characters read, and must
+    exceed 0 to be successful.  The first READ must always be successful, and
+    normally consists of just priming the buffer with EOBCHAR (or RS EOBCHAR).
+    SGMLIO must assure that there is an EOBCHAR at the end of each block read,
+    except for the last block of the entity, which must have an EOFCHAR.
+ 
+    SGML views an entity as a contiguous whole, without regard to its
+    actual form of storage.  SGMLIO supports entities that are equivalent
+    to a single file of one or more records, or to a concatenation of
+    files (e.g., "profile.gml;main.gml").  It also recognizes
+    an initial code that indicates whether prefixing of an RS and/or trimming
+    of a trailing RE/RS are wanted (e.g., "3=profile.gml;main.gml").
+    If the code is 1 or 3 (the default), RS is prefixed to the first
+    record read for a file.  If 2 or 3 (the default), an RE/RS sequence
+    occurring at the end of a file (before the EOF) will be trimmed.  Many
+    editors insert such a sequence to allow file concatenation, but it can
+    cause an extraneous space to occur when formatting.
+    A default setting is contained in boundsw, which can be gotten from the
+    command line or a processing instruction.  A code of 4 in a system identifier
+    means to use the default value for that file, just as if no code were
+    specified.  A code of 0 means that no special treatment is wanted.
+ */
+ VOID sgmlio(io)
+ struct ipbfile *io;           /* IPB: file I/O services. */
+ {
+      struct iofcb *f;         /* Active file control block. */
+      int fnum;                /* READ: Return code from DOS. */
+      char *flast;             /* READ: Last char read into buffer. */
+      int cnt;
+      char *p;
+ 
+      switch (io->ipbtype) {
+      case FILENM:             /* Generate fileid from name & external ID. */
+           io->ipbn = (UNIV)savestr(xidgen((struct fpi *)io->ipbn));
+           return;
+      case FILEOPEN:           /* Open new file for binary read-only. */
+           f = fcbgen((UNCH *)io->ipbn);             /* Generate FCB. */
+           io->ipbn = (UNIV)f;                       /* Return its pointer. */
+           fcbnext(f);                               /* Make it next file. */
+           f->fcbfd = fopen(f->fcbfile+1, "r"); /* Open file. */
+           io->ipbrc = OKIO(f->fcbfd) ? 1 : -1;      /* Normalize return code. */
+           f->fcbfirst = 1;                          /* Next read is first. */
+           return;
+      case FILEREAD:           /* Read file at current location. */
+           f = (struct iofcb *)io->ipbn;      /* Get FCB pointer. */
+           if (f->fcbfirst) {                 /* Fake first READ of an entity. */
+                fnum = readfrst(f, io->ipbbuf);
+                goto readrtrn;
+           }
+ 	  if (f->fcbpend) {
+ 	    io->ipbbuf[0] = RSCHAR;
+ 	    io->ipbbuf[1] = EOBCHAR;
+ 	    fnum = 2;
+ 	    f->fcbpend = 0;
+ 	    goto readrtrn;
+ 	  }
+           if (f->fcbcatsw && readcat(f)) {   /* Open catenated file, if due. */
+                fnum = -1;
+ 	       goto readrtrn;     /* Return if can't open it. */
+           }
+           f->fcboff = ftell(f->fcbfd);        /* Location of START of block.*/
+ 
+ 	  /* leave room for turning '\n' into '\r', '\n' */
+ 	  if (fgets(io->ipbbuf, (int)(readcnt - 1), f->fcbfd) == 0) {
+ 	    if (ferror(f->fcbfd)) {
+ 	      fnum = -1;
+ 	      goto readrtrn;     /* Return if read error. */
+ 	    }
+ 	    *io->ipbbuf = EOFCHAR;        /* Fake read of Ctl-Z. */
+ 	    fnum = 1;
+           }
+ 	  else {
+ 	    int c;
+ 
+ 	    fnum = (int)strlen(io->ipbbuf);    /* Length of record read. */
+ 	    if (io->ipbbuf[fnum - 1] == '\n') {
+ 	      io->ipbbuf[fnum - 1] = RECHAR;
+ 	      io->ipbbuf[fnum++] = RSCHAR;
+ 	    }
+ 	    c = getc(f->fcbfd);
+ 	    if (c == EOF)
+ 	      io->ipbbuf[fnum++] = EOFCHAR;
+ 	    else
+ 	      ungetc(c, f->fcbfd);
+ 	  }
+           flast = io->ipbbuf + fnum;         /* Point after last char read. */
+           if (*(--flast)==EOFCHAR) {         /* File ended with this READ. */
+                readeof(f, flast, &fnum);
+           }
+           else {
+                ++fnum; ++flast;              /* Include EOB char in count. */
+                *flast = EOBCHAR;             /* Add EOB char. */
+           }
+           readrtrn:
+           io->ipbrc = fnum;                                /* Do return code.*/
+           return;
+      case FILEPEND:           /* Close file temporarily. */
+           (f = IPBFCB)->fcbcatsw = 0;                   /* Resume in same file.*/
+           fseek(f->fcbfd, f->fcboff, SEEK_SET);         /* Start of block. */
+ 	  /* Avoid relying on position arithmetic. */
+ 	  cnt = io->ipboff;
+ 	  while (cnt > 0) {
+ 	    int c = getc(f->fcbfd);
+ 	    if (c == EOF)
+ 	      abort();
+ 	    if (c == '\n') {
+ 	      if ((cnt -= 2) < 0)
+ 		f->fcbpend = 1;	/* Can this happen? */
+ 	    }
+ 	    else
+ 	      --cnt;
+ 	  }
+           f->fcboff = ftell(f->fcbfd);                  /* Save location. */
+ 	  fclose(f->fcbfd);
+           return;
+      case FILECONT:           /* Reopen file; position to saved location. */
+           f->fcbfd =  fopen((f = IPBFCB)->fcbfile+1, "r");
+           io->ipbrc = OKIO(f->fcbfd) ? 1 : -1;
+           if (io->ipbrc>0)
+               io->ipbrc = (int)fseek(f->fcbfd, f->fcboff, SEEK_SET);
+           return;
+      case FILECLOS:           /* Close file permanently. */
+ 	  fclose(IPBFCB->fcbfd);
+           free((UNIV)IPBFCB);
+           return;
+      }
+ }
+ /******************************************************************************/
+ /* READEOF: Process end of file.  There are three possibilities:
+             1. Data and Ctl-Z read.
+             2. Data only read.
+             3. Ctl-Z only read.
+ */
+ void readeof(f, flast, pfnum)
+ struct iofcb *f;              /* Pointer to file control block. */
+ char *flast;                  /* Last char read into buffer. */
+ int *pfnum;                   /* Number of chars read. */
+ {
+      int eofsw = 0;           /* 1=EOFCHAR present; 0=supply one. */
+ 
+      if (*flast==EOFCHAR) eofsw = 1;    /* Set switch if EOF present. */
+      else {++flast; ++*pfnum;}          /* Prepare for EOF or EOB. */
+      if (f->fcbnext) {                  /* Another file in this entity? */
+           f->fcbcatsw = 1;              /* For next READ. */
+           *flast = EOBCHAR;             /* Not entity end. */
+      }
+      else {                             /* Entity ended: */
+           if (!eofsw)                   /* If no EOF char? */
+                *flast = EOFCHAR;        /* Add EOF char. */
+           else if ( f->fcbRE            /* EOF was there: is RE trim wanted? */
+             && *pfnum>=3                /* At least 2 chars before EOF? */
+             && *(--flast)==0x0A         /* Is RS there? */
+             && *(--flast)==0x0D )       /* Is RE there? */
+                {*flast = EOFCHAR; *pfnum -= 2;}    /* Cut them off. */
+      }
+ }
+ /******************************************************************************/
+ /* READCAT: Open concatenated file in current entity.
+             Returns 1 if open was successful, 0 if not.
+ */
+ int readcat(f)
+ struct iofcb *f;              /* Pointer to file control block. */
+ {
+      f->fcbcatsw = 0;         /* Next read will not be new concatenated file. */
+      fclose(f->fcbfd);        /* Close old file.*/
+      fcbnext(f);              /* Find new file. */
+      f->fcbfd =  fopen(f->fcbfile+1, "r");
+      return (!OKIO(f->fcbfd));
+ }
+ /******************************************************************************/
+ /* READFRST: Simulate first READ of entity in order to handle RS insertion
+              and guarantee an error-free return.
+ */
+ int readfrst(f, ipbbuf)
+ struct iofcb *f;              /* Pointer to file control block. */
+ char *ipbbuf;                 /* IPBFILE: Ptr to SGML read buffer. */
+ {
+      f->fcbfirst = 0;                   /* Next read will no longer be first. */
+      if (f->fcbRS) {                    /* RS prefix wanted? */
+         *((STRING)ipbbuf) = RSCHAR;     /* Put RS in buffer. */
+         *((STRING)ipbbuf+1) = EOBCHAR;  /* And end block. */
+         return(2);                      /* Successful "read" */
+      }
+      /* else */
+         *((STRING)ipbbuf) = EOBCHAR;    /* Put EOB in buffer. */
+         return(1);                      /* Successful "read" */
+ }
+ /******************************************************************************/
+ /* FCBGEN: Generates a file control block from an external identifier.
+ */
+ struct iofcb *fcbgen(x)
+ UNCH *x;                      /* Ptr to external ID (len+EOS). */
+ {
+      struct iofcb *f;         /* Ptr to new fcb. */
+ 
+      f = (struct iofcb *)vmalloc((UNS)sizeof(struct iofcb));
+      f->fcbxid = x;
+      f->fcbRS = (int)*(x+1)-'0' & 1;
+      f->fcbRE = (int)*(x+1)-'0' & 2;
+      f->fcbnext = x+3;
+      return(f);
+ }
+ /******************************************************************************/
+ /* FCBNEXT: Generates next full system fileid for a file control block.
+ */
+ VOID fcbnext(f)
+ struct iofcb *f;              /* Pointer to file control block. */
+ {
+      UNS i;                   /* Work variable. */
+      UNCH *p, *n;             /* Work variable. */
+ 
+      if ((p = f->fcbnext)==0) return;   /* Return if no more files for entity.*/
+      f->fcbnext = 0;                    /* Assume this file is the last. */
+      if ((n = strchr(p, ';'))!=0) {     /* If ; found, there is still another.*/
+           *n = EOS;                     /* Temporary EOS for strlen to use. */
+           f->fcbnext = n+1;             /* Location of next file after this. */
+      }
+      i = strlen(p);                     /* Get length of this file name. */
+      memcpy(pd+1, p, ++i);              /* Move to buffer to work on it. */
+      *pd = (char)++i;                   /* Prefix length to it. */
+      p = xidpath(pd);                   /* Complete the fileid (if necessary).*/
+      memcpy(f->fcbfile, p, *p);         /* Save full fileid in fcb. */
+      if (f->fcbnext) *n = ';';          /* Put the ; back in the xid. */
+ }
+ /******************************************************************************/
+ /* XIDGEN: Generates a system identifier (fileid) from a name,
+            and possibly a public or system identifier as well.
+            It returns a ptr to the fileid in the fpi or in the pd buffer.
+            Note 1: This routine assumes that an installation assigns
+            reserved entity names that correspond to public identifiers, so it
+            ignores the actual public identifier; in a more general approach,
+            a table would be checked for the corresponding system ID.
+            For version-dependent public entities, a real application
+            would use different tables, depending on the display device
+            (or different suffixes, in a scheme like that used here).
+            If this routine is modified so that, under some conditions,
+            it cannot generate a fileid, it should return 0 in those cases.
+            FILEOPEN should check for the 0 and return an error code to SGML
+            at that time.
+            Note 2: This routine allows boundary treatment codes for data
+            content notation files (f->fpistore==6) even though such files
+            are not parsed.  VM strips the code before displaying the file
+            identifier (which is analagous to a text processor stripping it
+            before passing it to an application).  Alternatively, this
+            routine could be modified so that the code is never inserted
+            in the first place.
+            Note 3: This is the place to check that system identifiers are
+            valid for your environment, and that the boundary code (if
+            specified) is valid.  SGML does not check such things because
+            it knows nothing about the environment.
+ */
+ UNCH *xidgen(f)
+ struct fpi *f;                /* Pointer to fpi control block. */
+ {
+      UNS i, j;                /* Work variables. */
+      UNCH *p;                 /* Work pointer. */
+ 
+      *pd = 4;                 /* Starting length of constructed ID. */
+      pd[1] = (char)boundsw;   /* Use default boundary treatment. */
+      pd[2] = '=';             /* Boundary treatment delimiter. */
+      p = pd+3;                /* Pt after boundary treatment delimiter. */
+      /* If a complete system ID was specified, use it all.
+         If only the boundary treatment was specified (n=), use it
+         when constructing the system ID.
+         If the boundary treatment was omitted, append the system ID to
+         the default boundary treatment code.
+      */
+      if (f->fpisysl) {
+           if (*(p = f->fpisysis+2)=='=') {
+                if (*(--p)>'3' || *p<'0') *p = (char)boundsw;
+                if (*(p+2)==EOS) {
+                     memcpy(pd, f->fpisysis, 3);
+                     p = pd+3;
+                }
+                else return(f->fpisysis);
+           }
+           else {
+                memcpy(pd+3, f->fpisysis+1, f->fpisysl-1);
+                *pd = f->fpisysl+2;
+                return(pd);
+           }
+      }
+      /* If not, add a suffix to the entity name to produce a system ID. */
+ 
+      /* Map to lower case unless it is an entity name, since entity
+      names are not subject to upper-case substitution in the reference
+      concrete syntax. */
+ 
+      if (f->fpistore == 2 || f->fpistore == 3)
+        memcpy(p, f->fpinm+1, (i = f->fpinml-2));
+      else
+        lwrcpy(p, f->fpinm+1, (i = f->fpinml-2));
+      j = (f->fpipubl ? 1 : 0)*(f->fpiversw>0 ? 2 : 1)*6+f->fpistore;
+      /* Always map extension to lower case. */
+      lwrcpy(p+i, genext[j], 5);    /* Add extension.*/
+      *pd += (char)(i + 4);         /* Add entity name and extension lengths. */
+ 
+      return(pd);
+ }
+ 
+ void lwrcpy(to, from, n)
+ char *to, *from;
+ int n;
+ {
+   for (; --n >= 0; to++, from++) {
+     if (isascii(*from) && isupper(*from))
+       *to = tolower(*from);
+     else
+       *to = *from;
+   }
+ }
+ /******************************************************************************/
+ /* XIDPATH: Prefixes a path to a system identifier (DOS fileid) if
+             path searching is wanted.
+             The path buffer is used to build the prefixed fileid.
+ */
+ UNCH *xidpath(pt)
+ UNCH *pt;                     /* Ptr to fileid in temporary storage (len+EOS).*/
+ {
+      UNS i;                   /* Work variable. */
+ 
+       /* If path is to be searched, get the full path name and fileid. */
+      if (!cdirsw && ((i = filefind(pt+1, path+1))>1) ) {
+           *path = *pt += (char)i;  /* Add len of path to fileid len. */
+           pt = path;               /* Return offset of path+fileid. */
+      }
+      return(pt);
+ }
+ /******************************************************************************/
+ /* FILEFIND: This is the routine to locate a file, using SRCHPATH.
+              If the file is found in the current directory, 1 is returned.
+              If found in another directory on the environment path list,
+              the length of the path name (no EOS) is returned; otherwise 0.
+ */
+ /******************************************************************************/
+ int filefind(filename, buffer)
+ char *filename;               /* File to be searched for (with EOS). */
+ char *buffer;                 /* Buffer for found filename (with EOS). */
+ {
+      char *fptr;              /* Pointer to found filename. */
+      unsigned fnlen;          /* Length of filename (+EOS). */
+ 
+      if ((fptr = srchpath(filename))==0) return (0);/*Return if no file found.*/
+      memcpy( buffer , fptr, (fnlen = (unsigned)strlen(fptr)) );
+      buffer[fnlen] = '\0';                        /* Somewhere on path. */
+      if (strlen(filename)==fnlen) return (1);     /* In current directory. */
+      return ((int)(fnlen+1));
+ }
+ 
+ /******************************************************************************/
+ /* SRCHPATH: This file contains the routine to locate a file, utilizing the PATH
+              environment variable for the directories to search.
+              If the file is found in the current directory, a pointer to
+              the filename argument is returned.  If the filename
+              is found in another directory on the environment path list,
+              the path name (with EOS) is stored in a static buffer, and a
+              pointer to it is returned; if not found, NULL is returned.
+ */
+ char *srchpath(filename)
+ char *filename;               /* File to be searched for (with EOS). */
+ {
+      static char tar_et[FILESPEC+1];
+      char *pptr;              /* Pointer into paths. */
+      char *tptr;              /* Pointer into tar_et. */
+ 
+      /* First check in the local directory */
+      if (testopen(filename))
+        return(filename);
+ 
+      /* No luck; search the path list from the environment. */
+      if ((pptr = getenv("PATH")) == 0)
+        return (0);
+ 
+      while (*pptr != 0) {
+           /* copy the directory name */
+           tptr = tar_et;
+ 	  /* XXX handle ~ and ~user here */
+           while (*pptr != ':' && *pptr != 0) {
+                *tptr++ = *pptr++;
+           }
+           if (*pptr) pptr++;       /* beyond the ':' (ready for next try) */
+           if (tptr[-1] != '/')
+                *tptr++ = '/';
+           /* Concatenate the filename to the path. */
+           strcpy(tptr, filename);
+           if (testopen(tar_et))
+ 	    return (tar_et);
+      }
+ 
+      return (0);                   /* can't find one */
+ }
+ /******************************************************************************/
+ /* TESTOPEN: Test whether a file can be opened.
+ */
+ int testopen(pathname)
+ char *pathname;               /* File to be tested (with EOS). */
+ {
+      HANDLE fid;              /* File handle returned by open; work variable. */
+ 
+      if ((fid = fopen(pathname, "r")) != 0) {
+           fclose(fid);
+           return (1);
+      }
+      /* else */ return(0);
+ }
+ /******************************************************************************/
diff -c2N ../arcsgml/vm2.c ./vm2.c
*** ../arcsgml/vm2.c	Sun Jul 21 09:43:56 1991
--- ./vm2.c	Sat Jul 20 22:28:23 1991
***************
*** 9,14 ****
--- 9,22 ----
  #include "vmxtrn.h"           /* Declarations for VM public variables. */
  extern int TPisVM;            /* Set to 1 by TP if it is markup validator. */
+ #ifdef unix
+ #define OPT_CHAR '-'
  static char vmomsg[] =        /* Text for invalid option error message. */
+      "-c10 -s";
+ #else
+ #define OPT_CHAR '/'
+ static char vmomsg[] =        /* Text for invalid option error message. */
       "/c10 /s";
+ #endif
+ 
  static char teattspc[] = "\n     ";             /* Tag/link att spacing. */
  static char deattspc[] = "\n                     "; /* Data att spacing. */
***************
*** 41,45 ****
       suppsw = 1;              /* Assume no parsing information is wanted. */
       for (i = 0; ++i<argc;) {
!           if (argv[i][0]!='/') fileid = argv[i];
            else if (sgmlopt(argv[i])!=0) switch (toupper((int)argv[i][1])) {
            case 'C':           /* Data or PI chars to print: 0 or more. */
--- 49,53 ----
       suppsw = 1;              /* Assume no parsing information is wanted. */
       for (i = 0; ++i<argc;) {
!           if (argv[i][0] != OPT_CHAR) fileid = argv[i];
            else if (sgmlopt(argv[i])!=0) switch (toupper((int)argv[i][1])) {
            case 'C':           /* Data or PI chars to print: 0 or more. */
diff -c2N ../arcsgml/vm2help.doc ./vm2help.doc
*** ../arcsgml/vm2help.doc	Sun Jul 21 10:09:19 1991
--- ./vm2help.doc	Sun Aug  4 11:21:19 1991
***************
*** 3,14 ****
  
  Requires: SGML.MSG in the same directory as VM2 or on the DOS path, unless
!           the exact pathname is specified with the /M switch (see below).
  
  Syntax: VMI [options] entity-id [options]
  
! Options: (syntax example: /d /e /f /g /mSGML.MSG /p1 /r /t3)
  
! /S  Show details of SGML parsing (default: error messages only, no details).
! /C  Data or PI chars to print if /S specified: 0 or more (default: 10).
  
      NOTE TO IMPLEMENTERS: The following options are supported by the
--- 3,14 ----
  
  Requires: SGML.MSG in the same directory as VM2 or on the DOS path, unless
!           the exact pathname is specified with the -M switch (see below).
  
  Syntax: VMI [options] entity-id [options]
  
! Options: (syntax example: -d -e -f -g -mSGML.MSG -p1 -r -t3)
  
! -S  Show details of SGML parsing (default: error messages only, no details).
! -C  Data or PI chars to print if -S specified: 0 or more (default: 10).
  
      NOTE TO IMPLEMENTERS: The following options are supported by the
***************
*** 15,26 ****
      SGML parser for all text processors.  (The preceding are unique to VM2.)
  
! /D  Report duplicate entity declarations (default: not reported).
! /E  Suppress entity stack trace in error msg (default: entity trace on).
! /F  Files located in current directory only (default: files anywhere on path).
! /G  Suppress GI stack trace in error messages (default: GI trace on).
! /M  Pathname of error message file (default: SGML.MSG).
! /P  Number of passes desired: 1 or more (default: 1 pass).
! /R  Give warning for defaulted entity references (default: no warning).
! /T  SGML wants an RS before each record and an RE after it.  DOS omits
      the RS from the first record of a file, but appends an RE after
      the end of file so that records are not merged when files are
--- 15,26 ----
      SGML parser for all text processors.  (The preceding are unique to VM2.)
  
! -D  Report duplicate entity declarations (default: not reported).
! -E  Suppress entity stack trace in error msg (default: entity trace on).
! -F  Files located in current directory only (default: files anywhere on path).
! -G  Suppress GI stack trace in error messages (default: GI trace on).
! -M  Pathname of error message file (default: SGML.MSG).
! -P  Number of passes desired: 1 or more (default: 1 pass).
! -R  Give warning for defaulted entity references (default: no warning).
! -T  SGML wants an RS before each record and an RE after it.  DOS omits
      the RS from the first record of a file, but appends an RE after
      the end of file so that records are not merged when files are
***************
*** 27,31 ****
      concatenated.  Other systems do not.  ARCSGML lets the user specify
      whether an RS should be inserted before the first record of an entity
!     (/T1), whether the trailing RE should be deleted (/T2), or both (/T3,
      the default).  (System identifiers in markup declarations can begin
      with "1=", "2=", or "3=" to accomplish the same thing for other
--- 27,31 ----
      concatenated.  Other systems do not.  ARCSGML lets the user specify
      whether an RS should be inserted before the first record of an entity
!     (-T1), whether the trailing RE should be deleted (-T2), or both (-T3,
      the default).  (System identifiers in markup declarations can begin
      with "1=", "2=", or "3=" to accomplish the same thing for other
diff -c2N ../arcsgml/vmincl.h ./vmincl.h
*** ../arcsgml/vmincl.h	Sun Jul 21 09:43:57 1991
--- ./vmincl.h	Sun Jul 21 09:50:19 1991
***************
*** 10,16 ****
--- 10,26 ----
  #include <string.h>           /* Memory and string functions. */
  #include <ctype.h>            /* Character type functions. */
+ 
+ #ifndef unix
  #include <fcntl.h>            /* Flag definitions for open() and _open(). */
  #include <io.h>               /* Low-level I/O functions. */
  #include <dir.h>              /* PC-DOS directory functions. */
+ #endif /* ndef unix */
+ 
+ #ifndef SEEK_SET
+ #define SEEK_SET 0
+ #define SEEK_CUR 1
+ #define SEEK_END 2
+ #endif
+ 
  /*lint -restore                  End of library function declarations. */
  /******************************************************************************/
***************
*** 27,31 ****
--- 37,45 ----
  #define RFT (*(struct rcbtag  *)srcbp) /* RCB: start-tag, end-tag. */
  #include "sgmlmain.h"         /* Main interface to SGML services. */
+ #ifdef unix
+ #include "uxenvcb.h"
+ #else
  #include "envcb.h"            /* Symbols for environment control block types. */
+ #endif
  /******************************************************************************/
  #include "vmfnsm.h"           /* ANSI C: Declarations for VM functions. */
diff -c2N ../arcsgml/vmxtrn.c ./vmxtrn.c
*** ../arcsgml/vmxtrn.c	Sun Jul 21 09:43:57 1991
--- ./vmxtrn.c	Sun Jul 21 00:51:51 1991
***************
*** 32,36 ****
  struct source tpscbs[ENTLVL+1] = {0}; /* Stack of open sources ("SCB stack"). */
  struct switches tpsw = {0};   /* Parser control switches set by text proc. */
! UNCH pd[2*LITLEN+FILESPEC+6] = {0}; /* Place for data copied from SGML space. */
   UNCH *ld = pd+LITLEN+2;       /* In pd: Buffer for copied literal. */
   UNCH *path = pd+2*LITLEN+4;   /* In pd: File ID buffer: len+path\fileid+EOS. */
--- 32,45 ----
  struct source tpscbs[ENTLVL+1] = {0}; /* Stack of open sources ("SCB stack"). */
  struct switches tpsw = {0};   /* Parser control switches set by text proc. */
! 
! #define MAX(a, b) ((a) > (b) ? (a) : (b))
! 
! /* See also defn of margv in sgmlmsg.c */
! #ifndef MAXMSGLN
! #define MAXMSGLN 200		/* more than enough */
! #endif
! 
! UNCH pd[MAX(2*LITLEN+FILESPEC+6, MAXMSGLN+1+3*(FILESPEC+1))]
! 	= {0}; /* Place for data copied from SGML space. */
   UNCH *ld = pd+LITLEN+2;       /* In pd: Buffer for copied literal. */
   UNCH *path = pd+2*LITLEN+4;   /* In pd: File ID buffer: len+path\fileid+EOS. */
***************
*** 69,75 ****
--- 78,92 ----
  UNCH *realmsg[] =             /* Real tag portion of minimization messages.*/
       {"short (no GI)", "data", "short (no GI)", "NET delimiter"};
+ 
+ #ifdef unix
+ UNCH *msgfptr = "sgml.msg";   /* Pointer to SGML message file id. */
+ UNCH options[] =              /* Text for invalid option error message. */
+      "-c10 -d -e -f -g -msgml.msg -p1 -r -s -t3";
+ #else
  UNCH *msgfptr = "SGML.MSG";   /* Pointer to SGML message file id. */
  UNCH options[] =              /* Text for invalid option error message. */
       "/c10 /d /e /f /g /mSGML.MSG /p1 /r /s /t3";
+ #endif
+ 
  /******************************************************************************/
  /* Conditional inclusions
