home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-src.tgz / tar.out / fsf / gawk / iop.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  325 lines

  1. /*
  2.  * iop.c - do i/o related things.
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 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 2 of the License, or
  14.  * (at your option) 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, Inc., 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.  
  40. void
  41. fatal(s)
  42. char *s;
  43. {
  44.     printf("%s\n", s);
  45.     exit(1);
  46. }
  47. #endif
  48.  
  49. int
  50. optimal_bufsize(fd)
  51. int fd;
  52. {
  53.     struct stat stb;
  54.  
  55. #ifdef VMS
  56.     /*
  57.      * These values correspond with the RMS multi-block count used by
  58.      * vms_open() in vms/vms_misc.c.
  59.      */
  60.     if (isatty(fd) > 0)
  61.         return BUFSIZ;
  62.     else if (fstat(fd, &stb) < 0)
  63.         return 8*512;    /* conservative in case of DECnet access */
  64.     else
  65.         return 32*512;
  66.  
  67. #else
  68.     /*
  69.      * System V doesn't have the file system block size in the
  70.      * stat structure. So we have to make some sort of reasonable
  71.      * guess. We use stdio's BUFSIZ, since that is what it was
  72.      * meant for in the first place.
  73.      */
  74. #ifdef BLKSIZE_MISSING
  75. #define    DEFBLKSIZE    BUFSIZ
  76. #else
  77. #define DEFBLKSIZE    (stb.st_blksize ? stb.st_blksize : BUFSIZ)
  78. #endif
  79.  
  80. #ifdef TEST
  81.     return bufsize;
  82. #else
  83. #ifndef atarist
  84.     if (isatty(fd))
  85. #else
  86.     /*
  87.      * On ST redirected stdin does not have a name attached
  88.      * (this could be hard to do to) and fstat would fail
  89.      */
  90.     if (0 == fd || isatty(fd))
  91. #endif  /*atarist */
  92.         return BUFSIZ;
  93. #ifndef BLKSIZE_MISSING
  94.     /* VMS POSIX 1.0: st_blksize is never assigned a value, so zero it */
  95.     stb.st_blksize = 0;
  96. #endif
  97.     if (fstat(fd, &stb) == -1)
  98.         fatal("can't stat fd %d (%s)", fd, strerror(errno));
  99.     if (lseek(fd, (off_t)0, 0) == -1)    /* not a regular file */
  100.         return DEFBLKSIZE;
  101.     if (stb.st_size > 0 && stb.st_size < DEFBLKSIZE) /* small file */
  102.         return (stb.st_size);
  103.     return (DEFBLKSIZE);
  104. #endif    /*! TEST */
  105. #endif    /*! VMS */
  106. }
  107.  
  108. IOBUF *
  109. iop_alloc(fd)
  110. int fd;
  111. {
  112.     IOBUF *iop;
  113.  
  114.     if (fd == INVALID_HANDLE)
  115.         return NULL;
  116.     emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
  117.     iop->flag = 0;
  118.     if (isatty(fd))
  119.         iop->flag |= IOP_IS_TTY;
  120.     iop->size = optimal_bufsize(fd);
  121.     iop->secsiz = -2;
  122.     errno = 0;
  123.     iop->fd = fd;
  124.     iop->off = iop->buf = NULL;
  125.     iop->cnt = 0;
  126.     return iop;
  127. }
  128.  
  129. /*
  130.  * Get the next record.  Uses a "split buffer" where the latter part is
  131.  * the normal read buffer and the head part is an "overflow" area that is used
  132.  * when a record spans the end of the normal buffer, in which case the first
  133.  * part of the record is copied into the overflow area just before the
  134.  * normal buffer.  Thus, the eventual full record can be returned as a
  135.  * contiguous area of memory with a minimum of copying.  The overflow area
  136.  * is expanded as needed, so that records are unlimited in length.
  137.  * We also mark both the end of the buffer and the end of the read() with
  138.  * a sentinel character (the current record separator) so that the inside
  139.  * loop can run as a single test.
  140.  */
  141. int
  142. get_a_record(out, iop, grRS, errcode)
  143. char **out;
  144. IOBUF *iop;
  145. register int grRS;
  146. int *errcode;
  147. {
  148.     register char *bp = iop->off;
  149.     char *bufend;
  150.     char *start = iop->off;            /* beginning of record */
  151.     char rs;
  152.     int saw_newline = 0, eat_whitespace = 0;    /* used iff grRS==0 */
  153.  
  154.     if (iop->cnt == EOF) {    /* previous read hit EOF */
  155.         *out = NULL;
  156.         return EOF;
  157.     }
  158.  
  159.     if (grRS == 0) {    /* special case:  grRS == "" */
  160.         rs = '\n';
  161.     } else
  162.         rs = (char) grRS;
  163.  
  164.     /* set up sentinel */
  165.     if (iop->buf) {
  166.         bufend = iop->buf + iop->size + iop->secsiz;
  167.         *bufend = rs;
  168.     } else
  169.         bufend = NULL;
  170.  
  171.     for (;;) {    /* break on end of record, read error or EOF */
  172.  
  173.         /* Following code is entered on the first call of this routine
  174.          * for a new iop, or when we scan to the end of the buffer.
  175.          * In the latter case, we copy the current partial record to
  176.          * the space preceding the normal read buffer.  If necessary,
  177.          * we expand this space.  This is done so that we can return
  178.          * the record as a contiguous area of memory.
  179.          */
  180.         if ((iop->flag & IOP_IS_INTERNAL) == 0 && bp >= bufend) {
  181.             char *oldbuf = NULL;
  182.             char *oldsplit = iop->buf + iop->secsiz;
  183.             long len;    /* record length so far */
  184.  
  185.             len = bp - start;
  186.             if (len > iop->secsiz) {
  187.                 /* expand secondary buffer */
  188.                 if (iop->secsiz == -2)
  189.                     iop->secsiz = 256;
  190.                 while (len > iop->secsiz)
  191.                     iop->secsiz *= 2;
  192.                 oldbuf = iop->buf;
  193.                 emalloc(iop->buf, char *,
  194.                     iop->size+iop->secsiz+2, "get_a_record");
  195.                 bufend = iop->buf + iop->size + iop->secsiz;
  196.                 *bufend = rs;
  197.             }
  198.             if (len > 0) {
  199.                 char *newsplit = iop->buf + iop->secsiz;
  200.  
  201.                 if (start < oldsplit) {
  202.                     memcpy(newsplit - len, start,
  203.                             oldsplit - start);
  204.                     memcpy(newsplit - (bp - oldsplit),
  205.                             oldsplit, bp - oldsplit);
  206.                 } else
  207.                     memcpy(newsplit - len, start, len);
  208.             }
  209.             bp = iop->end = iop->off = iop->buf + iop->secsiz;
  210.             start = bp - len;
  211.             if (oldbuf) {
  212.                 free(oldbuf);
  213.                 oldbuf = NULL;
  214.             }
  215.         }
  216.         /* Following code is entered whenever we have no more data to
  217.          * scan.  In most cases this will read into the beginning of
  218.          * the main buffer, but in some cases (terminal, pipe etc.)
  219.          * we may be doing smallish reads into more advanced positions.
  220.          */
  221.         if (bp >= iop->end) {
  222.             if ((iop->flag & IOP_IS_INTERNAL) != 0) {
  223.                 iop->cnt = EOF;
  224.                 break;
  225.             }
  226.             iop->cnt = read(iop->fd, iop->end, bufend - iop->end);
  227.             if (iop->cnt == -1) {
  228.                 if (! do_unix && errcode != NULL) {
  229.                     *errcode = errno;
  230.                     iop->cnt = EOF;
  231.                     break;
  232.                 } else
  233.                     fatal("error reading input: %s",
  234.                         strerror(errno));
  235.             } else if (iop->cnt == 0) {
  236.                 iop->cnt = EOF;
  237.                 break;
  238.             }
  239.             iop->end += iop->cnt;
  240.             *iop->end = rs;
  241.         }
  242.         if (grRS == 0) {
  243.             extern int default_FS;
  244.  
  245.             if (default_FS && (bp == start || eat_whitespace)) {
  246.                 while (bp < iop->end
  247.                       && (*bp == ' ' || *bp == '\t' || *bp == '\n'))
  248.                     bp++;
  249.                 if (bp == iop->end) {
  250.                     eat_whitespace = 1;
  251.                     continue;
  252.                 } else
  253.                     eat_whitespace = 0;
  254.                 start = bp;    /* skip leading white space */
  255.             }
  256.             if (saw_newline && *bp == rs) {
  257.                 bp++;
  258.                 break;
  259.             }
  260.             saw_newline = 0;
  261.         }
  262.  
  263.         while (*bp++ != rs)
  264.             ;
  265.  
  266.         if (bp <= iop->end) {
  267.             if (grRS == 0)
  268.                 saw_newline = 1;
  269.             else
  270.                 break;
  271.         } else
  272.             bp--;
  273.  
  274.         if ((iop->flag & IOP_IS_INTERNAL) != 0)
  275.             iop->cnt = bp - start;
  276.     }
  277.     if (iop->cnt == EOF
  278.         && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp)) {
  279.         *out = NULL;
  280.         return EOF;
  281.     }
  282.  
  283.     iop->off = bp;
  284.     bp--;
  285.     if (*bp != rs)
  286.         bp++;
  287.     *bp = '\0';
  288.     if (grRS == 0) {
  289.         /* there could be more newlines left, clean 'em out now */
  290.         while (iop->off <= iop->end && *(iop->off) == rs)
  291.             (iop->off)++;
  292.  
  293.         if (*--bp == rs)
  294.             *bp = '\0';
  295.         else
  296.             bp++;
  297.     }
  298.  
  299.     *out = start;
  300.     return bp - start;
  301. }
  302.  
  303. #ifdef TEST
  304. main(argc, argv)
  305. int argc;
  306. char *argv[];
  307. {
  308.     IOBUF *iop;
  309.     char *out;
  310.     int cnt;
  311.     char rs[2];
  312.  
  313.     rs[0] = 0;
  314.     if (argc > 1)
  315.         bufsize = atoi(argv[1]);
  316.     if (argc > 2)
  317.         rs[0] = *argv[2];
  318.     iop = iop_alloc(0);
  319.     while ((cnt = get_a_record(&out, iop, rs[0], NULL)) > 0) {
  320.         fwrite(out, 1, cnt, stdout);
  321.         fwrite(rs, 1, 1, stdout);
  322.     }
  323. }
  324. #endif
  325.