home *** CD-ROM | disk | FTP | other *** search
- /*
- * iop.c - do i/o related things.
- */
-
- /*
- * Copyright (C) 1986, 1988, 1989, 1991 the Free Software Foundation, Inc.
- *
- * This file is part of GAWK, the GNU implementation of the
- * AWK Progamming Language.
- *
- * GAWK is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * GAWK is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GAWK; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include "awk.h"
-
- #ifndef atarist
- #define INVALID_HANDLE (-1)
- #else
- #include <stddef.h>
- #include <fcntl.h>
- #define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1)
- #endif /* atarist */
-
-
- #ifdef TEST
- int bufsize = 8192;
- #endif
-
- int
- optimal_bufsize(fd)
- int fd;
- {
- struct stat stb;
-
- /*
- * System V doesn't have the file system block size in the
- * stat structure. So we have to make some sort of reasonable
- * guess. We use stdio's BUFSIZ, since that is what it was
- * meant for in the first place.
- */
- #ifdef BLKSIZE_MISSING
- #define DEFBLKSIZE BUFSIZ
- #else
- #define DEFBLKSIZE (stb.st_blksize ? stb.st_blksize : BUFSIZ)
- #endif
-
- #ifdef TEST
- return bufsize;
- #endif
- #ifndef atarist
- if (isatty(fd))
- #else
- /*
- * On ST redirected stdin does not have a name attached
- * (this could be hard to do to) and fstat would fail
- */
- if (0 == fd || isatty(fd))
- #endif /*atarist */
- return BUFSIZ;
- if (fstat(fd, &stb) == -1)
- fatal("can't stat fd %d (%s)", fd, strerror(errno));
- if (lseek(fd, 0L, 0) == -1)
- return DEFBLKSIZE;
- return (stb.st_size < DEFBLKSIZE ? stb.st_size : DEFBLKSIZE);
- }
-
- IOBUF *
- iop_alloc(fd)
- int fd;
- {
- IOBUF *iop;
-
- if (fd == INVALID_HANDLE)
- return NULL;
- emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
- iop->flag = 0;
- if (isatty(fd))
- iop->flag |= IOP_IS_TTY;
- iop->size = optimal_bufsize(fd);
- errno = 0;
- iop->fd = fd;
- emalloc(iop->buf, char *, iop->size + 2, "iop_alloc");
- iop->end = iop->off = iop->buf;
- iop->secsiz = iop->size < BUFSIZ ? iop->size : BUFSIZ;
- emalloc(iop->secbuf, char *, iop->secsiz+2, "iop_alloc");
- iop->cnt = -1;
- return iop;
- }
-
- int
- get_a_record(out, iop, rs)
- char **out;
- IOBUF *iop;
- register int rs;
- {
- register char *bp = iop->off;
- register char *end_data = iop->end; /* end of current data read */
- char *end_buf = iop->buf + iop->size; /* end of input buffer */
- char *start = iop->off; /* beginning of record */
- char *offset = iop->secbuf; /* end of data in secbuf */
- size_t size;
-
- if (iop->cnt == 0)
- return EOF;
-
- /* set up sentinels */
- if (rs == 0) {
- *end_data = *(end_data+1) = '\n';
- *end_buf = *(end_buf+1) = '\n';
- } else
- *end_data = *end_buf = rs;
-
- for (;;) { /* break on end of record, read error or EOF */
-
- if (bp == end_data) {
- if (bp == end_buf) { /* record spans buffer end */
- #ifdef atarist
- #define P_DIFF ptrdiff_t
- #else
- #define P_DIFF int
- #endif
- #define COPY_TO_SECBUF { \
- P_DIFF oldlen = offset - iop->secbuf; \
- P_DIFF newlen = bp - start; \
- \
- if (iop->secsiz < oldlen + newlen) { \
- erealloc(iop->secbuf, char *, \
- oldlen+newlen, "get_record"); \
- offset = iop->secbuf + oldlen; \
- } \
- memcpy(offset, start, newlen); \
- offset += newlen; \
- }
- COPY_TO_SECBUF
- start = bp = iop->buf;
- size = iop->size;
- } else
- size = end_buf - bp;
- iop->cnt = read(iop->fd, bp, size);
- if (iop->cnt == -1)
- fatal("error reading input");
- else if (iop->cnt == 0) {
- break;
- } else {
- end_data = bp + iop->cnt;
- if (rs == 0 && *bp == '\n'
- && offset > iop->secbuf
- && *(offset-1) == '\n') {
- bp++;
- break;
- }
- if (rs == 0) {
- *end_data = *(end_data+1) = '\n';
- *end_buf = *(end_buf+1) = '\n';
- } else
- *end_data = rs;
- }
- }
- if (rs == 0) {
- for (;;) {
- if (*bp++ == '\n' && *bp == '\n') {
- bp++;
- break;
- }
- }
- } else
- while (*bp++ != rs)
- ;
- if (bp <= end_data) /* end of record */
- break;
- bp = end_data;
- }
- if (offset == iop->secbuf && start == bp && iop->cnt == 0) {
- *out = start;
- return EOF;
- }
- iop->off = bp;
- iop->end = end_data;
- if (offset != iop->secbuf) {
- if (start != bp)
- COPY_TO_SECBUF
- start = iop->secbuf;
- bp = offset;
- }
- if (rs == 0) {
- if (*--bp == '\n') {
- *bp = '\0';
- if (*--bp == '\n')
- *bp = '\0';
- else
- bp++;
- } else
- bp++;
- } else if (*--bp == rs)
- ;
- else
- bp++;
- *bp = '\0';
- *out = start;
- return bp - start;
- }
-
- #ifdef TEST
- main(argc, argv)
- int argc;
- char *argv[];
- {
- IOBUF *iop;
- char *out;
- int cnt;
-
- if (argc > 1)
- bufsize = atoi(argv[1]);
- iop = iop_alloc(0);
- while ((cnt = get_a_record(&out, iop, 0)) > 0) {
- fwrite(out, 1, cnt, stdout);
- fwrite("\n", 1, 1, stdout);
- }
- }
- #endif
-