home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gawk213s.lzh / GAWK213S / IOP.C < prev    next >
C/C++ Source or Header  |  1993-07-29  |  5KB  |  238 lines

  1. /*
  2.  * iop.c - do i/o related things.
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. #ifndef atarist
  29. #define INVALID_HANDLE (-1)
  30. #else
  31. #include <stddef.h>
  32. #include <fcntl.h>
  33. #define INVALID_HANDLE  (__SMALLEST_VALID_HANDLE - 1)
  34. #endif  /* atarist */
  35.  
  36.  
  37. #ifdef TEST
  38. int bufsize = 8192;
  39. #endif
  40.  
  41. int
  42. optimal_bufsize(fd)
  43. int fd;
  44. {
  45. #ifdef VMS
  46. /* don't even bother trying [fstat() fails across DECnet] */
  47.     return BUFSIZ;
  48. #else
  49.     struct stat stb;
  50.  
  51.     /*
  52.      * System V doesn't have the file system block size in the
  53.      * stat structure. So we have to make some sort of reasonable
  54.      * guess. We use stdio's BUFSIZ, since that is what it was
  55.      * meant for in the first place.
  56.      */
  57. #ifdef BLKSIZE_MISSING
  58. #define    DEFBLKSIZE    BUFSIZ
  59. #else
  60. #define DEFBLKSIZE    (stb.st_blksize ? stb.st_blksize : BUFSIZ)
  61. #endif
  62.  
  63. #ifdef TEST
  64.     return bufsize;
  65. #endif
  66. #ifndef atarist
  67.     if (isatty(fd))
  68. #else
  69.     /*
  70.      * On ST redirected stdin does not have a name attached
  71.      * (this could be hard to do to) and fstat would fail
  72.      */
  73.     if (0 == fd || isatty(fd))
  74. #endif  /*atarist */
  75.         return BUFSIZ;
  76.     if (fstat(fd, &stb) == -1)
  77.         fatal("can't stat fd %d (%s)", fd, strerror(errno));
  78.     if (lseek(fd, 0L, 0) == -1)
  79.         return DEFBLKSIZE;
  80.     return (stb.st_size < DEFBLKSIZE ? stb.st_size : DEFBLKSIZE);
  81. #endif    /*! VMS */
  82. }
  83.  
  84. IOBUF *
  85. iop_alloc(fd)
  86. int fd;
  87. {
  88.     IOBUF *iop;
  89.  
  90.     if (fd == INVALID_HANDLE)
  91.         return NULL;
  92.     emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
  93.     iop->flag = 0;
  94.     if (isatty(fd))
  95.         iop->flag |= IOP_IS_TTY;
  96.     iop->size = optimal_bufsize(fd);
  97.     errno = 0;
  98.     iop->fd = fd;
  99.     emalloc(iop->buf, char *, iop->size + 2, "iop_alloc");
  100.     iop->end = iop->off = iop->buf;
  101.     iop->secsiz = iop->size < BUFSIZ ? iop->size : BUFSIZ;
  102.     emalloc(iop->secbuf, char *, iop->secsiz+2, "iop_alloc");
  103.     iop->cnt = -1;
  104.     return iop;
  105. }
  106.  
  107. int
  108. get_a_record(out, iop, rs)
  109. char **out;
  110. IOBUF *iop;
  111. register int rs;
  112. {
  113.     register char *bp = iop->off;
  114.     register char *end_data = iop->end;    /* end of current data read */
  115.     char *end_buf = iop->buf + iop->size;    /* end of input buffer */
  116.     char *start = iop->off;            /* beginning of record */
  117.     char *offset = iop->secbuf;        /* end of data in secbuf */
  118.     size_t size;
  119.  
  120.     if (iop->cnt == 0)
  121.         return EOF;
  122.  
  123.     /* set up sentinels */
  124.     if (rs == 0) {
  125.         *end_data = *(end_data+1) = '\n';
  126.         *end_buf = *(end_buf+1) = '\n';
  127.     } else
  128.         *end_data = *end_buf = rs;
  129.  
  130.     for (;;) {    /* break on end of record, read error or EOF */
  131.  
  132.         if (bp == end_data) {
  133.             if (bp == end_buf) {    /* record spans buffer end */
  134. #ifdef atarist
  135. #define P_DIFF ptrdiff_t
  136. #else
  137. #define P_DIFF int
  138. #endif
  139. #define    COPY_TO_SECBUF    { \
  140.                 P_DIFF oldlen = offset - iop->secbuf; \
  141.                 P_DIFF newlen = bp - start; \
  142.                                  \
  143.                 if (iop->secsiz < oldlen + newlen) { \
  144.                     erealloc(iop->secbuf, char *, \
  145.                         oldlen+newlen, "get_record"); \
  146.                     offset = iop->secbuf + oldlen; \
  147.                 } \
  148.                 memcpy(offset, start, newlen); \
  149.                 offset += newlen; \
  150.             }
  151.                 COPY_TO_SECBUF
  152.                 start = bp = iop->buf;
  153.                 size = iop->size;
  154.             } else
  155.                 size = end_buf - bp;
  156.             iop->cnt = read(iop->fd, bp, size);
  157.             if (iop->cnt == -1)
  158.                 fatal("error reading input");
  159.             else if (iop->cnt == 0) {
  160.                 break;
  161.             } else {
  162.                 end_data = bp + iop->cnt;
  163.                 if (rs == 0 && *bp == '\n'
  164.                     && offset > iop->secbuf
  165.                     && *(offset-1) == '\n') {
  166.                     bp++;
  167.                     break;
  168.                 }
  169.                 if (rs == 0) {
  170.                     *end_data = *(end_data+1) = '\n';
  171.                     *end_buf = *(end_buf+1) = '\n';
  172.                 } else
  173.                     *end_data = rs;
  174.             }
  175.         }
  176.         if (rs == 0) {
  177.             for (;;) {
  178.                 if (*bp++ == '\n' && *bp == '\n') {
  179.                     bp++;
  180.                     break;
  181.                 }
  182.             }
  183.         } else
  184.             while (*bp++ != rs)
  185.                 ;
  186.         if (bp <= end_data)    /* end of record */
  187.             break;
  188.         bp = end_data;
  189.     }
  190.     if (offset == iop->secbuf && start == bp && iop->cnt == 0) {
  191.         *out = start;
  192.         return EOF;
  193.     }
  194.     iop->off = bp;
  195.     iop->end = end_data;
  196.     if (offset != iop->secbuf) {
  197.         if (start != bp)
  198.             COPY_TO_SECBUF
  199.         start = iop->secbuf;
  200.         bp = offset;
  201.     }
  202.     if (rs == 0) {
  203.         if (*--bp == '\n') {
  204.             *bp = '\0';
  205.             if (*--bp == '\n')
  206.                 *bp = '\0';
  207.             else
  208.                 bp++;
  209.         } else
  210.             bp++;
  211.     } else if (*--bp == rs)
  212.         ;
  213.     else
  214.         bp++;
  215.     *bp = '\0';
  216.     *out = start;
  217.     return bp - start;
  218. }
  219.  
  220. #ifdef TEST
  221. main(argc, argv)
  222. int argc;
  223. char *argv[];
  224. {
  225.     IOBUF *iop;
  226.     char *out;
  227.     int cnt;
  228.  
  229.     if (argc > 1)
  230.         bufsize = atoi(argv[1]);
  231.     iop = iop_alloc(0);
  232.     while ((cnt = get_a_record(&out, iop, 0)) > 0) {
  233.         fwrite(out, 1, cnt, stdout);
  234.         fwrite("\n", 1, 1, stdout);
  235.     }
  236. }
  237. #endif
  238.