home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / unix / sgmlh / ndsgmlio.src < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-03  |  23.2 KB  |  464 lines

  1. /******************************************************************************/
  2. /* SGMLIO: Ideas for non-DOS environments.                                    */
  3. /* Includes both stream I/O and low-level I/O (stream tested for MSC only).   */
  4. /******************************************************************************/
  5. #include "vmincl.h"           /* Include files for VM. */
  6. #include "vmxtrn.h"           /* Declarations for VM public variables. */
  7. /******************************************************************************/
  8. #ifdef IBMC                   /* Stream I/O for IBMC (mainframe) only. */
  9. #define STREAMIO
  10. #else
  11. #define LOWLEVIO
  12. #endif /* def IBMC */
  13. #ifdef STREAMIO
  14. #define OKIO(rc) ((UNIV)(rc)>NULL)  /* OPEN return: 1=good; 0=error. */
  15. #define OPENREAD "rb"         /* Stream I/O: binary read (for MSC stream).  */
  16. #define close fclose          /* Stream I/O: equivalent function. */
  17. #define lseek fseek           /* Stream I/O: equivalent function. */
  18. #define open  fopen           /* Stream I/O: equivalent function. */
  19. #define tell  ftell           /* Stream I/O: equivalent function. */
  20. #define eof   feof            /* Stream I/O: equivalent function. */
  21. #else                         /* If low-level I/O: */
  22. #define OKIO(rc) ((rc)>0)     /* OPEN return: 1=good; 0=error. */
  23. #define OPENREAD (int)(O_RDONLY|O_BINARY) /* Low-level I/O: binary read. */
  24. #endif /* def STREAMIO */
  25. /******************************************************************************/
  26. /* Functions used in this module only.
  27. */
  28. struct iofcb *fcbgen(char *);
  29. void fcbnext(struct iofcb *);
  30. void readeof(struct iofcb *, char *, int *);
  31. int readcat(struct iofcb *);
  32. int readfrst(struct iofcb *, char *);
  33. /******************************************************************************/
  34. /* SGMLIO: Text processor I/O services for SGML.
  35.    SGML must see a file in which RE and RS (CR/LF) are present between records,
  36.    and EOFCHAR (Ctl-Z) is present at the end.  SGMLIO must supply these
  37.    characters if they are not naturally present in the file.
  38.    SGML will open two files at a time: when an entity is nested, the
  39.    new file is opened before closing the old in order to make sure the
  40.    open is successful. If it is, the original open file is closed temporarily
  41.    (FILEPEND); when the stack is popped, the new file is closed and the original
  42.    file is re-opened (FILECONT). SGML will check error returns
  43.    for the initial open of a file and all reads, and for re-openings when the
  44.    stack is popped, but not for closes.  Setting io.ipbrc<0 indicates
  45.    an error; 0 or more is a successful operation,
  46.    except for READ where io.ipbrc is the number of characters read, and must
  47.    exceed 0 to be successful.  The first READ must always be successful, and
  48.    normally consists of just priming the buffer with EOBCHAR (or RS EOBCHAR).
  49.    SGMLIO must assure that there is an EOBCHAR at the end of each block read,
  50.    except for the last block of the entity, which must have an EOFCHAR.
  51.  
  52.    SGML views an entity as a contiguous whole, without regard to its
  53.    actual form of storage.  SGMLIO supports entities that are equivalent
  54.    to a single file of one or more records, or to a concatenation of
  55.    files (e.g., "profile.gml;main.gml").  It also recognizes
  56.    an initial code that indicates whether prefixing of an RS and/or trimming
  57.    of a trailing RE/RS are wanted (e.g., "3=profile.gml;main.gml").
  58.    If the code is 1 or 3 (the default), RS is prefixed to the first
  59.    record read for a file.  If 2 or 3 (the default), an RE/RS sequence
  60.    occurring at the end of a file (before the EOF) will be trimmed.  Many
  61.    editors insert such a sequence to allow file concatenation, but it can
  62.    cause an extraneous space to occur when formatting.
  63.    A default setting is contained in boundsw, which can be gotten from the
  64.    command line or a processing instruction.  A code of 4 in a system identifier
  65.    means to use the default value for that file, just as if no code were
  66.    specified.  A code of 0 means that no special treatment is wanted.
  67. */
  68. VOID sgmlio(io)
  69. struct ipbfile *io;           /* IPB: file I/O services. */
  70. {
  71.      struct iofcb *f;         /* Active file control block. */
  72.      int fnum;                /* READ: Return code from DOS. */
  73.      char *flast;             /* READ: Last char read into buffer. */
  74.  
  75.      switch (io->ipbtype) {
  76.      case FILENM:             /* Generate fileid from name & external ID. */
  77.           io->ipbn = (UNIV)savestr(xidgen((struct fpi *)io->ipbn));
  78.           return;
  79.      case FILEOPEN:           /* Open new file for binary read-only. */
  80.           f = fcbgen((UNCH *)io->ipbn);             /* Generate FCB. */
  81.           io->ipbn = (UNIV)f;                       /* Return its pointer. */
  82.           fcbnext(f);                               /* Make it next file. */
  83.           f->fcbfd =  open(f->fcbfile+1, OPENREAD); /* Open file. */
  84.           io->ipbrc = OKIO(f->fcbfd) ? 1 : -1;      /* Normalize return code. */
  85.           f->fcbfirst = 1;                          /* Next read is first. */
  86.           return;
  87.      case FILEREAD:           /* Read file at current location. */
  88.           f = (struct iofcb *)io->ipbn;      /* Get FCB pointer. */
  89.           if (f->fcbfirst) {                 /* Fake first READ of an entity. */
  90.                fnum = readfrst(f, io->ipbbuf);
  91.                goto readrtrn;
  92.           }
  93.           if (f->fcbcatsw && readcat(f)) {   /* Open catenated file, if due. */
  94.                fnum = -1; goto readrtrn;     /* Return if can't open it. */
  95.           }
  96.           f->fcboff = tell(f->fcbfd);        /* Location of START of block.*/
  97. #ifdef LOWLEVIO
  98.           if (eof(f->fcbfd)) {               /* File ended on previous READ. */
  99.                *io->ipbbuf = EOFCHAR;        /* Fake read of Ctl-Z. */
  100.                fnum = 1;
  101.           }
  102.           else fnum =  read(f->fcbfd, io->ipbbuf, readcnt); /* Read the file. */
  103.           if (fnum<0) goto readrtrn;         /* Return if read error. */
  104.           flast = io->ipbbuf + fnum-1;       /* Last character read. */
  105.           if (*flast==EOFCHAR || fnum<readcnt) readeof(f, flast, &fnum);
  106.           else *(io->ipbbuf + fnum++) = EOBCHAR;  /* Add EOB char. */
  107. #else /* def STREAMIO */
  108.          if (eof(f->fcbfd)) {                /* File ended on previous READ. */
  109.                *io->ipbbuf = EOFCHAR;        /* Fake read of Ctl-Z. */
  110.                *(io->ipbbuf+1) = EOS;        /* End the string. */
  111.           }
  112.          else
  113.           fgets(io->ipbbuf, (int)readcnt, f->fcbfd); /* Read the next block. */
  114.           if (ferror(f->fcbfd)) {
  115.                fnum = -1; goto readrtrn;     /* Return if read error. */
  116.           }
  117.           fnum = (int)strlen(io->ipbbuf);    /* Length of record read. */
  118.                /* TO DO: Insert RE,RS in front of record if needed. */
  119.                /* If appended, fix READEOF to avoid it on EOF. */
  120.           flast = io->ipbbuf + fnum;         /* Point after last char read. */
  121.           if (*(--flast)==EOFCHAR) {         /* File ended with this READ. */
  122.                readeof(f, flast, &fnum);
  123.           }
  124.           else {
  125.                ++fnum; ++flast;              /* Include EOB char in count. */
  126.                *flast = EOBCHAR;             /* Add EOB char. */
  127.                /* TO DO: Insert RE,RS in front of record if needed. */
  128.                /* If appended, fix READEOF avoid it on EOF. */
  129.           }
  130. #endif /* def STREAMIO */
  131.           readrtrn:
  132.           io->ipbrc = fnum;                                /* Do return code.*/
  133.           return;
  134.      case FILEPEND:           /* Close file temporarily. */
  135.           (f = IPBFCB)->fcbcatsw = 0;                   /*Resume in same file.*/
  136.           lseek(f->fcbfd, f->fcboff, SEEK_SET);         /* Start of block. */
  137.           lseek(f->fcbfd, (long)io->ipboff, SEEK_CUR);  /* Current char. */
  138.           f->fcboff =  tell(f->fcbfd);                  /* Save location. */
  139.            close(f->fcbfd);
  140.           return;
  141.      case FILECONT:           /* Reopen file; position to saved location. */
  142.           f->fcbfd =  open((f = IPBFCB)->fcbfile+1, OPENREAD);
  143.           io->ipbrc = OKIO(f->fcbfd) ? 1 : -1;
  144.           if (io->ipbrc>0)
  145.               io->ipbrc = (int)lseek(f->fcbfd, f->fcboff, SEEK_SET);
  146.           return;
  147.      case FILECLOS:           /* Close file permanently. */
  148.            close(IPBFCB->fcbfd);
  149.           free((UNIV)IPBFCB);
  150.           return;
  151.      }
  152. }
  153. /******************************************************************************/
  154. /* READEOF: Process end of file.  There are three possibilities:
  155.             1. Data and Ctl-Z read.
  156.             2. Data only read.
  157.             3. Ctl-Z only read.
  158. */
  159. void readeof(f, flast, pfnum)
  160. struct iofcb *f;              /* Pointer to file control block. */
  161. char *flast;                  /* Last char read into buffer. */
  162. int *pfnum;                   /* Number of chars read. */
  163. {
  164.      int eofsw = 0;           /* 1=EOFCHAR present; 0=supply one. */
  165.  
  166.      if (*flast==EOFCHAR) eofsw = 1;    /* Set switch if EOF present. */
  167.      else {++flast; ++*pfnum;}          /* Prepare for EOF or EOB. */
  168.      if (f->fcbnext) {                  /* Another file in this entity? */
  169.           f->fcbcatsw = 1;              /* For next READ. */
  170.           *flast = EOBCHAR;             /* Not entity end. */
  171.      }
  172.      else {                             /* Entity ended: */
  173.           if (!eofsw)                   /* If no EOF char? */
  174.                *flast = EOFCHAR;        /* Add EOF char. */
  175.           else if ( f->fcbRE            /* EOF was there: is RE trim wanted? */
  176.             && *pfnum>=3                /* At least 2 chars before EOF? */
  177.             && *(--flast)==0x0A         /* Is RS there? */
  178.             && *(--flast)==0x0D )       /* Is RE there? */
  179.                {*flast = EOFCHAR; *pfnum -= 2;}    /* Cut them off. */
  180.      }
  181. }
  182. /******************************************************************************/
  183. /* READCAT: Open concatenated file in current entity.
  184.             Returns 1 if open was successful, 0 if not.
  185. */
  186. int readcat(f)
  187. struct iofcb *f;              /* Pointer to file control block. */
  188. {
  189.      f->fcbcatsw = 0;         /* Next read will not be new concatenated file. */
  190.       close(f->fcbfd);        /* Close old file.*/
  191.      fcbnext(f);              /* Find new file. */
  192.      f->fcbfd =  open(f->fcbfile+1, OPENREAD);
  193.      return (!OKIO(f->fcbfd));
  194. }
  195. /******************************************************************************/
  196. /* READFRST: Simulate first READ of entity in order to handle RS insertion
  197.              and guarantee an error-free return.
  198. */
  199. int readfrst(f, ipbbuf)
  200. struct iofcb *f;              /* Pointer to file control block. */
  201. char *ipbbuf;                 /* IPBFILE: Ptr to SGML read buffer. */
  202. {
  203.      f->fcbfirst = 0;                   /* Next read will no longer be first. */
  204.      if (f->fcbRS) {                    /* RS prefix wanted? */
  205.         *((STRING)ipbbuf) = RSCHAR;     /* Put RS in buffer. */
  206.         *((STRING)ipbbuf+1) = EOBCHAR;  /* And end block. */
  207.         return(2);                      /* Successful "read" */
  208.      }
  209.      /* else */
  210.         *((STRING)ipbbuf) = EOBCHAR;    /* Put EOB in buffer. */
  211.         return(1);                      /* Successful "read" */
  212. }
  213. /******************************************************************************/
  214. /* FCBGEN: Generates a file control block from an external identifier.
  215. */
  216. struct iofcb *fcbgen(x)
  217. UNCH *x;                      /* Ptr to external ID (len+EOS). */
  218. {
  219.      struct iofcb *f;         /* Ptr to new fcb. */
  220.  
  221.      f = (struct iofcb *)vmalloc((UNS)sizeof(struct iofcb));
  222.      f->fcbxid = x;
  223.      f->fcbRS = (int)*(x+1)-'0' & 1;
  224.      f->fcbRE = (int)*(x+1)-'0' & 2;
  225.      f->fcbnext = x+3;
  226.      return(f);
  227. }
  228. /******************************************************************************/
  229. /* FCBNEXT: Generates next full system fileid for a file control block.
  230. */
  231. VOID fcbnext(f)
  232. struct iofcb *f;              /* Pointer to file control block. */
  233. {
  234.      UNS i;                   /* Work variable. */
  235.      UNCH *p, *n;             /* Work variable. */
  236.  
  237.      if ((p = f->fcbnext)==0) return;   /* Return if no more files for entity.*/
  238.      f->fcbnext = 0;                    /* Assume this file is the last. */
  239.      if ((n = strchr(p, ';'))!=0) {     /* If ; found, there is still another.*/
  240.           *n = EOS;                     /* Temporary EOS for strlen to use. */
  241.           f->fcbnext = n+1;             /* Location of next file after this. */
  242.      }
  243.      i = strlen(p);                     /* Get length of this file name. */
  244.      memcpy(pd+1, p, ++i);              /* Move to buffer to work on it. */
  245.      *pd = (char)++i;                   /* Prefix length to it. */
  246.      p = xidpath(pd);                   /* Complete the fileid (if necessary).*/
  247.      memcpy(f->fcbfile, p, *p);         /* Save full fileid in fcb. */
  248.      if (f->fcbnext) *n = ';';          /* Put the ; back in the xid. */
  249. }
  250. /******************************************************************************/
  251. /* XIDGEN: Generates a system identifier (fileid) from a name,
  252.            and possibly a public or system identifier as well.
  253.            It returns a ptr to the fileid in the fpi or in the pd buffer.
  254.            Note 1: This routine assumes that an installation assigns
  255.            reserved entity names that correspond to public identifiers, so it
  256.            ignores the actual public identifier; in a more general approach,
  257.            a table would be checked for the corresponding system ID.
  258.            For version-dependent public entities, a real application
  259.            would use different tables, depending on the display device
  260.            (or different suffixes, in a scheme like that used here).
  261.            If this routine is modified so that, under some conditions,
  262.            it cannot generate a fileid, it should return 0 in those cases.
  263.            FILEOPEN should check for the 0 and return an error code to SGML
  264.            at that time.
  265.            Note 2: This routine allows boundary treatment codes for data
  266.            content notation files (f->fpistore==6) even though such files
  267.            are not parsed.  VM strips the code before displaying the file
  268.            identifier (which is analagous to a text processor stripping it
  269.            before passing it to an application).  Alternatively, this
  270.            routine could be modified so that the code is never inserted
  271.            in the first place.
  272.            Note 3: This is the place to check that system identifiers are
  273.            valid for your environment, and that the boundary code (if
  274.            specified) is valid.  SGML does not check such things because
  275.            it knows nothing about the environment.
  276. */
  277. UNCH *xidgen(f)
  278. struct fpi *f;                /* Pointer to fpi control block. */
  279. {
  280.      UNS i, j;                /* Work variables. */
  281.      UNCH *p;                 /* Work pointer. */
  282.  
  283.      *pd = 4;                 /* Starting length of constructed ID. */
  284.      pd[1] = (char)boundsw;   /* Use default boundary treatment. */
  285.      pd[2] = '=';             /* Boundary treatment delimiter. */
  286.      p = pd+3;                /* Pt after boundary treatment delimiter. */
  287.      /* If a complete system ID was specified, use it all.
  288.         If only the boundary treatment was specified (n=), use it
  289.         when constructing the system ID.
  290.         If the boundary treatment was omitted, append the system ID to
  291.         the default boundary treatment code.
  292.      */
  293.      if (f->fpisysl) {
  294.           if (*(p = f->fpisysis+2)=='=') {
  295.                if (*(--p)>'3' || *p<'0') *p = (char)boundsw;
  296.                if (*(p+2)==EOS) {
  297.                     memcpy(pd, f->fpisysis, 3);
  298.                     p = pd+3;
  299.                }
  300.                else return(f->fpisysis);
  301.           }
  302.           else {
  303.                memcpy(pd+3, f->fpisysis+1, f->fpisysl-1);
  304.                *pd = f->fpisysl+2;
  305.                return(pd);
  306.           }
  307.      }
  308.      /* If not, add a suffix to the entity name to produce a system ID. */
  309.      memcpy(p, f->fpinm+1, (i = f->fpinml-2));
  310.      j = (f->fpipubl ? 1 : 0)*(f->fpiversw>0 ? 2 : 1)*6+f->fpistore;
  311.      memcpy(p+i, genext[j], 5);    /* Add extension.*/
  312.      *pd += (char)(i + 4);         /* Add entity name and extension lengths. */
  313.      return(pd);
  314. }
  315. /******************************************************************************/
  316. /******************************************************************************/
  317. #ifdef IBMC
  318. /******************************************************************************/
  319. /* XIDPATH: The path buffer is used to store the completed fileid.
  320.             TO DO: If mode is omitted, default it to the current drive,
  321.                    or to * if cdirsw says path searching is wanted.
  322. */
  323. UNCH *xidpath(pt)
  324. UNCH *pt;                     /* Ptr to fileid in temporary storage (len+EOS).*/
  325. {
  326.       /* If path is to be searched, get the actual fileid. */
  327.      if (filefind(pt+1, path+1)) {
  328.           *path = (char)(strlen(path+1)+2);  /* Get len of actual fileid. */
  329.           pt = path;                         /* Return ptr to actual fileid. */
  330.      }
  331.      return(pt);
  332. }
  333. /******************************************************************************/
  334. /* FILEFIND: Returns 1 if a file exists, 0 if not.
  335.              If it exists, the complete fileid is returned in caller's buffer.
  336.              TO DO: Return the full fileid found by STATE.
  337. */
  338. /******************************************************************************/
  339.      char statebuf[27] = "STATE ";
  340. /******************************************************************************/
  341. int filefind(filename, buffer)
  342. char *filename;               /* File to be searched for (with EOS). */
  343. char *buffer;                 /* Buffer for found filename (with EOS). */
  344. {
  345.      if (strlen(filename)>20) return (0);    /* Return if invalid fileid.*/
  346.      strcat(statebuf, filename);
  347.      if (system(statebuf)) return (0);       /* Return if no file found. */
  348.      strcpy(buffer, filename);
  349.      return (1);
  350. }
  351. /******************************************************************************/
  352. /******************************************************************************/
  353. #else /* if ndef IBMC */
  354. /******************************************************************************/
  355. /******************************************************************************/
  356. /* XIDPATH: Prefixes a path to a system identifier (DOS fileid) if
  357.             path searching is wanted.
  358.             The path buffer is used to build the prefixed fileid.
  359. */
  360. UNCH *xidpath(pt)
  361. UNCH *pt;                     /* Ptr to fileid in temporary storage (len+EOS).*/
  362. {
  363.      UNS i;                   /* Work variable. */
  364.  
  365.       /* If path is to be searched, get the full path name and fileid. */
  366.      if (!cdirsw && ((i = filefind(pt+1, path+1))>1) ) {
  367.           *path = *pt += (char)i;  /* Add len of path to fileid len. */
  368.           pt = path;               /* Return offset of path+fileid. */
  369.      }
  370.      return(pt);
  371. }
  372. /******************************************************************************/
  373. /* FILEFIND: This is the routine to locate a file, using SRCHPATH.
  374.              If the file is found in the current directory, 1 is returned.
  375.              If found in another directory on the environment path list,
  376.              the length of the path name (no EOS) is returned; otherwise 0.
  377. */
  378. /******************************************************************************/
  379. #ifdef TURBOC
  380.   #define srchpath(s) searchpath(s)
  381. #else
  382.   static char *srchpath(char *);
  383.   static int testopen(char *);
  384. #endif /* def TURBOC */
  385. /******************************************************************************/
  386. int filefind(filename, buffer)
  387. char *filename;               /* File to be searched for (with EOS). */
  388. char *buffer;                 /* Buffer for found filename (with EOS). */
  389. {
  390.      char *fptr;              /* Pointer to found filename. */
  391.      unsigned fnlen;          /* Length of filename (+EOS). */
  392.  
  393.      _fmode = (int)O_BINARY;       /* Default file I/O is binary mode. */
  394.      if ((fptr = srchpath(filename))==0) return (0);/*Return if no file found.*/
  395.      memcpy( buffer , fptr, (fnlen = (unsigned)strlen(fptr)) );
  396.      if (strlen(filename)==fnlen) return (1);     /* In current directory. */
  397.      buffer[fnlen] = '\0';                        /* Somewhere on path. */
  398.      return ((int)(fnlen+1));
  399. }
  400. #ifndef TURBOC
  401. /******************************************************************************/
  402. /* SRCHPATH: This file contains the routine to locate a file, utilizing the PATH
  403.              environment variable for the directories to search.
  404.              If the file is found in the current directory, a pointer to
  405.              the filename argument is returned.  If the filename
  406.              is found in another directory on the environment path list,
  407.              the path name (with EOS) is stored in a static buffer, and a
  408.              pointer to it is returned; if not found, NULL is returned.
  409.              NOTE: DOS 2.0 or greater only; stack requirements: ~300 bytes.
  410. */
  411. /******************************************************************************/
  412. char tar_et[80];              /* Buffer for path (if any) + filename (+EOS). */
  413. /******************************************************************************/
  414. char *srchpath(filename)
  415. char *filename;               /* File to be searched for (with EOS). */
  416. {
  417.      char paths[256];         /* Buffer for PATHS environment variable. */
  418.      char *pptr;              /* Pointer into paths. */
  419.      char *tptr;              /* Pointer into tar_et. */
  420.      unsigned fnlen;          /* Length of filename (+EOS). */
  421.  
  422.      /* First check in the local directory */
  423.      if (testopen(filename)>0) return(filename);
  424.      /* No luck; search the path list from the environment. */
  425.      if ((pptr = getenv("PATH"))==0) return (0);
  426.      /* else */ strcpy(paths, pptr);
  427.      fnlen = (unsigned)strlen(filename)+1;
  428.      pptr = paths;
  429.      while (*pptr != 0) {
  430.           /* copy the directory name */
  431.           tptr = tar_et;
  432.           while (*pptr != ';' && *pptr != 0) {
  433.                *tptr++ = *pptr++;
  434.           }
  435.           if (*pptr) pptr++;       /* beyond the ';' (ready for next try) */
  436.           if (*(tptr-1) != '/' && *(tptr-1) != '\\')
  437.                *tptr++ = '\\';
  438.           /* Concatenate the filename to the path. */
  439.           memcpy(tptr, filename, fnlen);
  440.           if (testopen(tar_et)>0) return (tar_et);
  441.      }
  442.      return (0);                   /* can't find one */
  443. }
  444. /******************************************************************************/
  445. /* TESTOPEN: Test whether a file can be opened.
  446. */
  447. int testopen(pathname)
  448. char *pathname;               /* File to be tested (with EOS). */
  449. {
  450.      int fid;                 /* File handle returned by open; work variable. */
  451.  
  452.      if ((fid = open(pathname, O_RDONLY))>0) {
  453.           close(fid);
  454.           return (1);
  455.      }
  456.      /* else */ return(0);
  457. }
  458. /******************************************************************************/
  459. #endif /* ndef TURBOC */
  460. /******************************************************************************/
  461. #endif /* def IBMC */
  462. /******************************************************************************/
  463. /******************************************************************************/
  464.