summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SNIP/xfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'reference/C/CONTRIB/SNIP/xfile.c')
-rwxr-xr-xreference/C/CONTRIB/SNIP/xfile.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/reference/C/CONTRIB/SNIP/xfile.c b/reference/C/CONTRIB/SNIP/xfile.c
new file mode 100755
index 0000000..7be9d51
--- /dev/null
+++ b/reference/C/CONTRIB/SNIP/xfile.c
@@ -0,0 +1,200 @@
+/* xfile.c -- implementation for fast line buffered files
+**
+** Currently (Sat 06-15-1991) XFILEs are for reading CR-LF terminated lines
+** from MS-DOS text files. Period. It's not that the method can't be used
+** as well for output buffering, or (in some form) for binary files, it's
+** that such are handled fast enough to suit me already, whereas text mode
+** input performance leaves me wishing for more speed. This attempts to
+** solve that problem.
+**
+** Sun 06-16-1991 -- CR-LF accepted, but so is bare LF now; the extracted
+** line does NOT have a NEWLINE at the end anymore (which will likely be
+** a mixed blessing...)
+**
+** The code should be fairly portable: if/when I get around to polishing it
+** (and that won't be until I've used it some and am sure it's stable) I'll
+** be aiming for near-ANSI portability; for now I'm not pushing so very hard
+** for that.
+**
+** The semantics are a bit odd: the lines are returned in a buffer that the
+** XFILE owns, and may be altered by a call to xgetline or xclose. For
+** applications that resent this, XFILEs probably aren't a big win anyway,
+** but there might be some cases where using XFILE and copying (some) lines
+** is still a good idea. The performance with long lines is good: it can
+** handle lines the size of the buffer, though it may truncate up to one
+** QUANTUM less one bytes "early": this depends on the location of the start
+** of the line in the buffer when we begin scanning. In practice, XBUFSIZE
+** is probably larger than you'd set for a line buffer size anyway...
+**
+** INTERNALS:
+**
+** Reading the first buffer's worth at open time makes the EOF case easier to
+** detect.
+**
+** TO DO:
+**
+** clean up xgetline!
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "xfile.h"
+
+#if !defined(__ZTC__) && !defined(__TURBOC__)
+ static int DOS_OPEN(const char *name, int mode, ...)
+ {
+ int hdl;
+
+ if (0 == _dos_open(name, mode, &hdl))
+ return hdl;
+ else return -1;
+ }
+
+ static int READ(int fd, void *buf, size_t len)
+ {
+ unsigned count;
+
+ if (0 == _dos_read(fd, buf, len, &count))
+ return count;
+ else return -1;
+ }
+#endif
+
+#ifndef XBUFN /* set default # of quanta in buffer, allow -D */
+ #define XBUFN 8
+#endif
+
+#define QUANTUM 512
+#define XBUFSIZE (XBUFN * QUANTUM)
+
+
+/* xopen -- allocate and open an XFILE
+**
+** NB: currently I'm designing these for READ-ONLY TEXT FILES only: the xopen
+** interface may have to be changed...
+**
+** returns pointer to XFILE of opened file or null pointer on error
+**
+** ? should it leave a better error description somewhere ?
+*/
+
+XFILE *xopen(char const *name)
+{
+ XFILE *f = malloc(sizeof(XFILE) + XBUFSIZE + 1);
+ int n;
+
+ if (f == 0)
+ goto error0;
+ f->buf = (char *)f + sizeof(XFILE);
+
+ if ((f->fd = DOS_OPEN(name, O_RDONLY)) < 0)
+ goto error1;
+
+ if ((n = READ(f->fd, f->buf, XBUFSIZE)) < 0)
+ goto error2;
+
+ f->buf[n] = 0;
+ f->nextChar = f->buf;
+ return f;
+
+error2:
+ CLOSE(f->fd);
+error1:
+ free(f);
+error0:
+ return 0;
+}
+
+
+/*
+** xclose -- close and deallocate an XFILE
+*/
+
+void xclose(XFILE *f)
+{
+ CLOSE(f->fd);
+ free(f);
+}
+
+
+/*
+** xgetline -- get the next text line into memory
+**
+** returns a pointer to the line (a NUL-terminated string) or a null pointer
+*/
+
+char *xgetline(XFILE *f)
+{
+ char *s = f->nextChar, *p;
+ int n;
+
+ for (p = s; *p != 0; ++p)
+ {
+ if (*p == '\n')
+ {
+ if (s < p && p[-1] == '\r')
+ p[-1] = 0;
+ else *p = 0;
+ f->nextChar = p + 1;
+ return s;
+ }
+ }
+
+ /*
+ ** end of line not found in buffer -- p points to the sentinel NUL
+ */
+
+ if (p == f->buf) /* iff empty, EOF */
+ return 0;
+
+ /*
+ ** move prefix of line to bottom of buffer
+ */
+
+ if (s != f->buf)
+ {
+ for (p = f->buf; (*p = *s) != 0; ++p, ++s)
+ ;
+ s = f->buf;
+ }
+
+ n = XBUFSIZE - (p - f->buf);
+
+ if (n < QUANTUM) /* insufficent room, break line */
+ {
+ f->nextChar = p;
+ return s;
+ }
+
+ n = (n / QUANTUM) * QUANTUM; /* quantize: count to read */
+ n = READ(f->fd, p, n);
+
+ /*
+ ** read error is sort of ignored here... same return as EOF.
+ ** we'll see if this proves to be sufficent...
+ */
+
+ if (n < 0)
+ {
+ f->nextChar = f->buf;
+ f->buf[0] = 0;
+ return 0;
+ }
+
+ p[n] = 0;
+
+ for ( ; *p != 0; ++p)
+ {
+ if (*p == '\n')
+ {
+ if (s < p && p[-1] == '\r')
+ p[-1] = 0;
+ else *p = 0;
+ ++p;
+ break;
+ }
+ }
+
+ f->nextChar = p;
+ return p == s ? 0 : s;
+}