home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / misc / compsci / arcsgm.cpt / ARC SGML 1.0 / sgmlc / mcsgmlio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-12  |  18.4 KB  |  427 lines

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