home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / XFILE.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  5KB  |  204 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*  xfile.c -- implementation for fast line buffered files
  4. **
  5. **  Currently (Sat  06-15-1991) XFILEs are for reading CR-LF terminated lines
  6. **  from MS-DOS text files.  Period.  It's not that the method can't be used
  7. **  as well for output buffering, or (in some form) for binary files, it's
  8. **  that such are handled fast enough to suit me already, whereas text mode
  9. **  input performance leaves me wishing for more speed.  This attempts to
  10. **  solve that problem.
  11. **
  12. **  Sun  06-16-1991 -- CR-LF accepted, but so is bare LF now; the extracted
  13. **  line does NOT have a NEWLINE at the end anymore (which will likely be
  14. **  a mixed blessing...)
  15. **
  16. **  The code should be fairly portable: if/when I get around to polishing it
  17. **  (and that won't be until I've used it some and am sure it's stable) I'll
  18. **  be aiming for near-ANSI portability; for now I'm not pushing so very hard
  19. **  for that.
  20. **
  21. **  The semantics are a bit odd: the lines are returned in a buffer that the
  22. **  XFILE owns, and may be altered by a call to xgetline or xclose.  For
  23. **  applications that resent this, XFILEs probably aren't a big win anyway,
  24. **  but there might be some cases where using XFILE and copying (some) lines
  25. **  is still a good idea.  The performance with long lines is good: it can
  26. **  handle lines the size of the buffer, though it may truncate up to one
  27. **  QUANTUM less one bytes "early": this depends on the location of the start
  28. **  of the line in the buffer when we begin scanning.  In practice, XBUFSIZE
  29. **  is probably larger than you'd set for a line buffer size anyway...
  30. **
  31. **  INTERNALS:
  32. **
  33. **  Reading the first buffer's worth at open time makes the EOF case easier to
  34. **  detect.
  35. **
  36. **  TO DO:
  37. **
  38. **  clean up xgetline!
  39. */
  40.  
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <fcntl.h>
  44. #include "xfile.h"
  45.  
  46. #if !defined(__ZTC__) && !defined(__TURBOC__)
  47.  static int DOS_OPEN(const char *name, int mode, ...)
  48.  {
  49.        int hdl;
  50.  
  51.        if (0 == _dos_open(name, mode, &hdl))
  52.              return hdl;
  53.        else  return -1;
  54.  }
  55.  
  56.  static int READ(int fd, void *buf, size_t len)
  57.  {
  58.        unsigned count;
  59.  
  60.        if (0 == _dos_read(fd, buf, len, &count))
  61.              return count;
  62.        else  return -1;
  63.  }
  64. #endif
  65.  
  66. #ifndef XBUFN               /* set default # of quanta in buffer, allow -D */
  67.  #define XBUFN 8
  68. #endif
  69.  
  70. #define QUANTUM 512
  71. #define XBUFSIZE (XBUFN * QUANTUM)
  72.  
  73.  
  74. /*  xopen -- allocate and open an XFILE
  75. **
  76. **  NB: currently I'm designing these for READ-ONLY TEXT FILES only: the xopen
  77. **      interface may have to be changed...
  78. **
  79. **  returns pointer to XFILE of opened file or null pointer on error
  80. **
  81. **  ? should it leave a better error description somewhere ?
  82. */
  83.  
  84. XFILE *xopen(char const *name)
  85. {
  86.       XFILE *f = malloc(sizeof(XFILE) + XBUFSIZE + 1);
  87.       int n;
  88.  
  89.       if (f == NULL)
  90.             goto error0;
  91.       f->buf = (char *)f + sizeof(XFILE);
  92.  
  93.       if ((f->fd = DOS_OPEN(name, O_RDONLY)) < 0)
  94.             goto error1;
  95.  
  96.       if ((n = READ(f->fd, f->buf, XBUFSIZE)) < 0)
  97.             goto error2;
  98.  
  99.       f->buf[n] = 0;
  100.       f->nextChar = f->buf;
  101.       return f;
  102.  
  103. error2:
  104.       CLOSE(f->fd);
  105. error1:
  106.       free(f);
  107. error0:
  108.       return NULL;
  109. }
  110.  
  111.  
  112. /*
  113. **  xclose -- close and deallocate an XFILE
  114. */
  115.  
  116. void xclose(XFILE *f)
  117. {
  118.       CLOSE(f->fd);
  119.       free(f);
  120. }
  121.  
  122.  
  123. /*
  124. **  xgetline -- get the next text line into memory
  125. **
  126. **  returns a pointer to the line (a NUL-terminated string) or a null pointer
  127. */
  128.  
  129. char *xgetline(XFILE *f)
  130. {
  131.       char *s = f->nextChar, *p;
  132.       int n;
  133.  
  134.       for (p = s; *p != 0; ++p)
  135.       {
  136.             if (*p == '\n')
  137.             {
  138.                   if (s < p && p[-1] == '\r')
  139.                         p[-1] = 0;
  140.                   else  *p = 0;
  141.                   f->nextChar = p + 1;
  142.                   return s;
  143.             }
  144.       }
  145.  
  146.       /*
  147.       **  end of line not found in buffer -- p points to the sentinel NUL
  148.       */
  149.  
  150.       if (p == f->buf)                    /* iff empty, EOF */
  151.             return NULL;
  152.  
  153.       /*
  154.       **  move prefix of line to bottom of buffer
  155.       */
  156.  
  157.       if (s != f->buf)
  158.       {
  159.             for (p = f->buf; (*p = *s) != 0; ++p, ++s)
  160.                   ;
  161.             s = f->buf;
  162.       }
  163.  
  164.       n = XBUFSIZE - (p - f->buf);
  165.  
  166.       if (n < QUANTUM)                    /* insufficient room, break line */
  167.       {
  168.             f->nextChar = p;
  169.             return s;
  170.       }
  171.  
  172.       n = (n / QUANTUM) * QUANTUM;        /* quantize: count to read */
  173.       n = READ(f->fd, p, n);
  174.  
  175.       /*
  176.       **  read error is sort of ignored here... same return as EOF.
  177.       **  we'll see if this proves to be sufficient...
  178.       */
  179.  
  180.       if (n < 0)
  181.       {
  182.             f->nextChar = f->buf;
  183.             f->buf[0] = 0;
  184.             return NULL;
  185.       }
  186.  
  187.       p[n] = 0;
  188.  
  189.       for ( ; *p != 0; ++p)
  190.       {
  191.             if (*p == '\n')
  192.             {
  193.                   if (s < p && p[-1] == '\r')
  194.                         p[-1] = 0;
  195.                   else  *p = 0;
  196.                   ++p;
  197.                   break;
  198.             }
  199.       }
  200.  
  201.       f->nextChar = p;
  202.       return p == s ? NULL : s;
  203. }
  204.