home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / buff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-08  |  14.4 KB  |  649 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1996 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission.
  24.  *
  25.  * 5. Redistributions of any form whatsoever must retain the following
  26.  *    acknowledgment:
  27.  *    "This product includes software developed by the Apache Group
  28.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  31.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  34.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  41.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  * ====================================================================
  43.  *
  44.  * This software consists of voluntary contributions made by many
  45.  * individuals on behalf of the Apache Group and was originally based
  46.  * on public domain software written at the National Center for
  47.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  48.  * For more information on the Apache Group and the Apache HTTP server
  49.  * project, please see <http://www.apache.org/>.
  50.  *
  51.  */
  52.  
  53. #include <errno.h>
  54. #include <stdio.h>
  55. #include <stdarg.h>
  56. #include <string.h>
  57. #include <unistd.h>
  58.  
  59. #include "alloc.h"
  60. #include "buff.h"
  61.  
  62. #define DEFAULT_BUFSIZE (4096)
  63.  
  64. /*
  65.  * Buffered I/O routines.
  66.  * These are a replacement for the stdio routines.
  67.  * Advantages:
  68.  *  Known semantics for handling of file-descriptors (on close etc.)
  69.  *  No problems reading and writing simultanously to the same descriptor
  70.  *  No limits on the number of open file handles.
  71.  *  Only uses memory resources; no need to ensure the close routine
  72.  *  is called.
  73.  *  Extra code could be inserted between the buffered and un-buffered routines.
  74.  *  Timeouts could be handled by using select or poll before read or write.
  75.  *  Extra error handling could be introduced; e.g.
  76.  *   keep an address to which we should longjump(), or
  77.  *   keep a stack of routines to call on error.
  78.  */
  79.  
  80. /* Notes:
  81.  *  On reading EOF, EOF will set in the flags and no further Input will
  82.  * be done.
  83.  *
  84.  * On an error except for EAGAIN, ERROR will be set in the flags and no
  85.  * futher I/O will be done
  86.  */
  87.  
  88. static void
  89. doerror(BUFF *fb, int err)
  90. {
  91.     if (err == B_RD)
  92.     fb->flags |= B_RDERR;
  93.     else
  94.     fb->flags |= B_WRERR;
  95.     if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data);
  96. }
  97.  
  98. /* Buffering routines */
  99. /*
  100.  * Create a new buffered stream
  101.  */
  102. BUFF *
  103. bcreate(pool *p, int flags)
  104. {
  105.     BUFF *fb;
  106.  
  107.     fb = palloc(p, sizeof(BUFF));
  108.     fb->pool=p;
  109.     fb->bufsiz = DEFAULT_BUFSIZE;
  110.     fb->flags = flags & B_RDWR;
  111.  
  112.     if (flags & B_RD) fb->inbase = palloc(p, fb->bufsiz);
  113.     else fb->inbase = NULL;
  114.  
  115.     if (flags & B_WR) fb->outbase = palloc(p, fb->bufsiz);
  116.     else fb->inbase = NULL;
  117.  
  118.     fb->inptr = fb->inbase;
  119.  
  120.     fb->incnt = 0;
  121.     fb->outcnt = 0;
  122.     fb->error = NULL;
  123.     fb->bytes_sent = 0L;
  124.  
  125.     fb->fd = -1;
  126.     fb->fd_in = -1;
  127.  
  128.     return fb;
  129. }
  130.  
  131. /*
  132.  * Push some I/O file descriptors onto the stream
  133.  */
  134. void
  135. bpushfd(BUFF *fb, int fd_in, int fd_out)
  136. {
  137.     fb->fd = fd_out;
  138.     fb->fd_in = fd_in;
  139.     note_cleanups_for_fd(fb->pool,fb->fd);
  140.     if(fb->fd != fb->fd_in)
  141.     note_cleanups_for_fd(fb->pool,fb->fd_in);
  142. }
  143.  
  144. int
  145. bsetopt(BUFF *fb, int optname, const void *optval)
  146. {
  147.     if (optname == BO_BYTECT)
  148.     {
  149.     fb->bytes_sent = *(const long int *)optval - (long int)fb->outcnt;;
  150.     return 0;
  151.     } else
  152.     {
  153.     errno = EINVAL;
  154.     return -1;
  155.     }
  156. }
  157.  
  158. int
  159. bgetopt(BUFF *fb, int optname, void *optval)
  160. {
  161.     if (optname == BO_BYTECT)
  162.     {
  163.     long int bs=fb->bytes_sent + fb->outcnt;
  164.     if (bs < 0L) bs = 0L;
  165.     *(long int *)optval = bs;
  166.     return 0;
  167.     } else
  168.     {
  169.     errno = EINVAL;
  170.     return -1;
  171.     }
  172. }
  173.  
  174. /*
  175.  * Read up to nbyte bytes into buf.
  176.  * If fewer than byte bytes are currently available, then return those.
  177.  * Returns 0 for EOF, -1 for error.
  178.  */
  179. int
  180. bread(BUFF *fb, void *buf, int nbyte)
  181. {
  182.     int i, nrd;
  183.  
  184.     if (fb->flags & B_RDERR) return -1;
  185.     if (nbyte == 0) return 0;
  186.  
  187.     if (!(fb->flags & B_RD))
  188.     {
  189. /* Unbuffered reading */
  190.     do i = read(fb->fd_in, buf, nbyte);
  191.     while (i == -1 && errno == EINTR);
  192.     if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
  193.     return i;
  194.     }
  195.  
  196.     nrd = fb->incnt;
  197. /* can we fill the buffer */
  198.     if (nrd >= nbyte)
  199.     {
  200.     memcpy(buf, fb->inptr, nbyte);
  201.     fb->incnt = nrd - nbyte;
  202.     fb->inptr += nbyte;
  203.     return nbyte;
  204.     }
  205.     
  206.     if (nrd > 0)
  207.     {
  208.     memcpy(buf, fb->inptr, nrd);
  209.     nbyte -= nrd;
  210.     buf = nrd + (char *)buf;
  211.     fb->incnt = 0;
  212.     }
  213.     if (fb->flags & B_EOF) return nrd;
  214.  
  215. /* do a single read */
  216.     if (nbyte >= fb->bufsiz)
  217.     {
  218. /* read directly into buffer */
  219.     do i = read(fb->fd_in, buf, nbyte);
  220.     while (i == -1 && errno == EINTR);
  221.     if (i == -1)
  222.     {
  223.         if (nrd == 0)
  224.         {
  225.         if (errno != EAGAIN) doerror(fb, B_RD);
  226.         return -1;
  227.         }
  228.         else return nrd;
  229.     } else if (i == 0) fb->flags |= B_EOF;
  230.     } else
  231.     {
  232. /* read into hold buffer, then memcpy */
  233.     fb->inptr = fb->inbase;
  234.     do i = read(fb->fd_in, fb->inptr, fb->bufsiz);
  235.     while (i == -1 && errno == EINTR);
  236.     if (i == -1)
  237.     {
  238.         if (nrd == 0)
  239.         {
  240.         if (errno != EAGAIN) doerror(fb, B_RD);
  241.         return -1;
  242.         }
  243.         else return nrd;
  244.     } else if (i == 0) fb->flags |= B_EOF;
  245.     fb->incnt = i;
  246.     if (i > nbyte) i = nbyte;
  247.     memcpy(buf, fb->inptr, i);
  248.     fb->incnt -= i;
  249.     fb->inptr += i;
  250.     }
  251.     return nrd + i;
  252. }
  253.  
  254.  
  255. /*
  256.  * Reads from the stream into the array pointed to by buff, until
  257.  * a (CR)LF sequence is read, or end-of-file condition is encountered
  258.  * or until n-1 bytes have been stored in buff. If a CRLF sequence is
  259.  * read, it is replaced by a newline character.  The string is then
  260.  * terminated with a null character.
  261.  *
  262.  * Returns the number of bytes stored in buff, or zero on end of
  263.  * transmission, or -1 on an error.
  264.  *
  265.  * Notes:
  266.  *  If null characters are exepected in the data stream, then
  267.  * buff should not be treated as a null terminated C string; instead
  268.  * the returned count should be used to determine the length of the
  269.  * string.
  270.  *  CR characters in the byte stream not immediately followed by a LF
  271.  * will be preserved.
  272.  */
  273. int
  274. bgets(char *buff, int n, BUFF *fb)
  275. {
  276.     int i, ch, ct;
  277.  
  278. /* Can't do bgets on an unbuffered stream */
  279.     if (!(fb->flags & B_RD))
  280.     {
  281.     errno = EINVAL;
  282.     return -1;
  283.     }
  284.     if (fb->flags & B_RDERR) return -1;
  285.  
  286.     ct = 0;
  287.     i = 0;
  288.     for (;;)
  289.     {
  290.     if (i == fb->incnt)
  291.     {
  292. /* no characters left */
  293.         fb->inptr = fb->inbase;
  294.         fb->incnt = 0;
  295.         if (fb->flags & B_EOF) break;
  296.         do i = read(fb->fd_in, fb->inptr, fb->bufsiz);
  297.         while (i == -1 && errno == EINTR);
  298.         if (i == -1)
  299.         {
  300.         buff[ct] = '\0';
  301.         if (ct == 0)
  302.         {
  303.             if (errno != EAGAIN) doerror(fb, B_RD);
  304.             return -1;
  305.         }
  306.         else return ct;
  307.         }
  308.         fb->incnt = i;
  309.         if (i == 0)
  310.         {
  311.         fb->flags |= B_EOF;
  312.         break; /* EOF */
  313.         }
  314.         i = 0;
  315.         continue;  /* restart with the new data */
  316.     }
  317.  
  318.     ch = fb->inptr[i++];
  319.     if (ch == '\012')  /* got LF */
  320.     {
  321.         if (ct == 0) buff[ct++] = '\n';
  322. /* if just preceeded by CR, replace CR with LF */
  323.         else if (buff[ct-1] == '\015') buff[ct-1] = '\n';
  324.         else if (ct < n-1) buff[ct++] = '\n';
  325.         else i--; /* no room for LF */
  326.         break;
  327.     }
  328.     if (ct == n-1)
  329.     {
  330.         i--;  /* push back ch */
  331.         break;
  332.     }
  333.     
  334.     buff[ct++] = ch;
  335.     }
  336.     fb->incnt -= i;
  337.     fb->inptr += i;
  338.  
  339.     buff[ct] = '\0';
  340.     return ct;
  341. }
  342.  
  343. /*
  344.  * Skip data until a linefeed character is read
  345.  * Returns 1 on success, 0 if no LF found, or -1 on error
  346.  */
  347. int
  348. bskiplf(BUFF *fb)
  349. {
  350.     unsigned char *x;
  351.     int i;
  352.  
  353. /* Can't do bskiplf on an unbuffered stream */
  354.     if (!(fb->flags & B_RD))
  355.     {
  356.     errno = EINVAL;
  357.     return -1;
  358.     }
  359.     if (fb->flags & B_RDERR) return -1;
  360.  
  361.     for (;;)
  362.     {
  363.     x = memchr(fb->inptr, '\012', fb->incnt);
  364.     if (x != NULL)
  365.     {
  366.         x++;
  367.         fb->incnt -= x - fb->inptr;
  368.         fb->inptr = x;
  369.         return 1;
  370.     }
  371.  
  372.     fb->inptr = fb->inbase;
  373.     fb->incnt = 0;
  374.     if (fb->flags & B_EOF) return 0;
  375.     do i = read(fb->fd_in, fb->inptr, fb->bufsiz);
  376.     while (i == -1 && errno == EINTR);
  377.     if (i == 0) fb->flags |= B_EOF;
  378.     if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
  379.     if (i == 0 || i == -1) return i;
  380.     fb->incnt = i;
  381.     }
  382. }
  383.  
  384. /*
  385.  * Emtpy the buffer after putting a single character in it
  386.  */
  387. int
  388. bflsbuf(int c, BUFF *fb)
  389. {
  390.     char ss[1];
  391.  
  392.     ss[0] = c;
  393.     return bwrite(fb, ss, 1);
  394. }
  395.  
  396. /*
  397.  * Fill the buffer and read a character from it
  398.  */
  399. int
  400. bfilbuf(BUFF *fb)
  401. {
  402.     int i;
  403.     char buf[1];
  404.  
  405.     i = bread(fb, buf, 1);
  406.     if (i == 0) errno = 0;  /* no error; EOF */
  407.     if (i != 1) return EOF;
  408.     else return buf[0];
  409. }
  410.  
  411. /*
  412.  * Write nbyte bytes.
  413.  * Only returns fewer than nbyte if an error ocurred.
  414.  * Returns -1 if no bytes were written before the error ocurred.
  415.  */
  416. int
  417. bwrite(BUFF *fb, const void *buf, int nbyte)
  418. {
  419.     int i, nwr;
  420.  
  421.     if (fb->flags & (B_WRERR|B_EOUT)) return -1;
  422.     if (nbyte == 0) return 0;
  423.  
  424.     if (!(fb->flags & B_WR))
  425.     {
  426. /* unbuffered write */
  427.     do i = write(fb->fd, buf, nbyte);
  428.     while (i == -1 && errno == EINTR);
  429.     if (i > 0) fb->bytes_sent += i;
  430.     if (i == 0)
  431.     {
  432.         i = -1;  /* return of 0 means non-blocking */
  433.         errno = EAGAIN;
  434.     }
  435.     if (i == -1 && errno != EAGAIN) doerror(fb, B_WR);
  436.     return i;
  437.     }
  438.  
  439. /*
  440.  * Whilst there is data in the buffer, keep on adding to it and writing it
  441.  * out
  442.  */
  443.     nwr = 0;
  444.     while (fb->outcnt > 0)
  445.     {
  446. /* can we accept some data? */
  447.     i = fb->bufsiz - fb->outcnt;
  448.     if (i > 0)
  449.     {
  450.         if (i > nbyte) i = nbyte;
  451.         memcpy(fb->outbase + fb->outcnt, buf, i);
  452.         fb->outcnt += i;
  453.         nbyte -= i;
  454.         buf = i + (const char *)buf;
  455.         nwr += i;
  456.         if (nbyte == 0) return nwr; /* return if none left */
  457.     }
  458.  
  459. /* the buffer must be full */
  460.     do i = write(fb->fd, fb->outbase, fb->bufsiz);
  461.     while (i == -1 && errno == EINTR);
  462.     if (i > 0) fb->bytes_sent += i;
  463.     if (i == 0)
  464.     {
  465.         i = -1;  /* return of 0 means non-blocking */
  466.         errno = EAGAIN;
  467.     }
  468.     if (i == -1)
  469.     {
  470.         if (nwr == 0)
  471.         {
  472.         if (errno != EAGAIN) doerror(fb, B_WR);
  473.         return -1;
  474.         }
  475.         else return nwr;
  476.     }
  477.  
  478. /*
  479.  * we should have written all the data, however if the fd was in a
  480.  * strange (non-blocking) mode, then we might not have done so.
  481.  */
  482.     if (i < fb->bufsiz)
  483.     {
  484.         int j, n=fb->bufsiz;
  485.         unsigned char *x=fb->outbase;
  486.         for (j=i; j < n; j++) x[j-i] = x[j];
  487.         fb->outcnt = fb->bufsiz - i;
  488.     } else
  489.         fb->outcnt = 0;
  490.     }
  491. /* we have emptied the file buffer. Now try to write the data from the
  492.  * original buffer until there is less than bufsiz left
  493.  */
  494.     while (nbyte > fb->bufsiz)
  495.     {
  496.     do i = write(fb->fd, buf, nbyte);
  497.     while (i == -1 && errno == EINTR);
  498.     if (i > 0) fb->bytes_sent += i;
  499.     if (i == 0)
  500.     {
  501.         i = -1;  /* return of 0 means non-blocking */
  502.         errno = EAGAIN;
  503.     }
  504.     if (i == -1)
  505.     {
  506.         if (nwr == 0)
  507.         {
  508.         if (errno != EAGAIN) doerror(fb, B_WR);
  509.         return -1;
  510.         }
  511.         else return nwr;
  512.     }
  513.  
  514.     buf = i + (const char *)buf;
  515.     nwr += i;
  516.     nbyte -= i;
  517.     }
  518. /* copy what's left to the file buffer */
  519.     if (nbyte > 0) memcpy(fb->outbase, buf, nbyte);
  520.     fb->outcnt = nbyte;
  521.     nwr += nbyte;
  522.     return nwr;
  523. }
  524.  
  525. /*
  526.  * Flushes the buffered stream.
  527.  * Returns 0 on success or -1 on error
  528.  */
  529. int
  530. bflush(BUFF *fb)
  531. {
  532.     int i, j;
  533.  
  534.     if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0;
  535.  
  536.     if (fb->flags & B_WRERR) return -1;
  537.     
  538.     while (fb->outcnt > 0)
  539.     {
  540. /* the buffer must be full */
  541.     j = fb->outcnt;
  542.     do i = write(fb->fd, fb->outbase, fb->outcnt);
  543.     while (i == -1 && errno == EINTR);
  544.     if (i > 0) fb->bytes_sent += i;
  545.     if (i == 0)
  546.     {
  547.         errno = EAGAIN;
  548.         return -1;  /* return of 0 means non-blocking */
  549.     }
  550.     if (i == -1)
  551.     {
  552.         if (errno != EAGAIN) doerror(fb, B_WR);
  553.         return -1;
  554.     }
  555.  
  556. /*
  557.  * we should have written all the data, however if the fd was in a
  558.  * strange (non-blocking) mode, then we might not have done so.
  559.  */
  560.     if (i < fb->outcnt)
  561.     {
  562.         int j, n=fb->outcnt;
  563.         unsigned char *x=fb->outbase;
  564.         for (j=i; j < n; j++) x[j-i] = x[j];
  565.     }
  566.     fb->outcnt -= i;
  567.     }
  568.     return 0;
  569. }
  570.  
  571. /*
  572.  * Flushes and closes the file, even if an error occurred.
  573.  * Discards an data that was not read, or not written by bflush()
  574.  * Sets the EOF flag to indicate no futher data can be read,
  575.  * and the EOUT flag to indicate no further data can be written.
  576.  */
  577. int
  578. bclose(BUFF *fb)
  579. {
  580.     int rc1, rc2, rc3;
  581.  
  582.     if (fb->flags & B_WR) rc1 = bflush(fb);
  583.     else rc1 = 0;
  584.     rc2 = close(fb->fd);
  585.     if (fb->fd_in != fb->fd) rc3 = close(fb->fd_in);
  586.     else rc3 = 0;
  587.  
  588.     fb->inptr = fb->inbase;
  589.     fb->incnt = 0;
  590.     fb->outcnt = 0;
  591.  
  592.     fb->flags |= B_EOF | B_EOUT;
  593.     fb->fd = -1;
  594.     fb->fd_in = -1;
  595.  
  596.     if (rc1 != 0) return rc1;
  597.     else if (rc2 != 0) return rc2;
  598.     else return rc3;
  599. }
  600.  
  601. /*
  602.  * returns the number of bytes written or -1 on error
  603.  */
  604. int
  605. bputs(const char *x, BUFF *fb)
  606. {
  607.     int i, j=strlen(x);
  608.     i = bwrite(fb, x, j);
  609.     if (i != j) return -1;
  610.     else return j;
  611. }
  612.  
  613. /*
  614.  * returns the number of bytes written or -1 on error
  615.  */
  616. int
  617. bvputs(BUFF *fb, ...)
  618. {
  619.     int i, j, k;
  620.     va_list v;
  621.     const char *x;
  622.  
  623.     va_start(v, fb);
  624.     for (k=0;;)
  625.     {
  626.     x = va_arg(v, const char *);
  627.     if (x == NULL) break;
  628.     j = strlen(x);
  629.     i = bwrite(fb, x, j);
  630.     if (i != j)
  631.     {
  632.         va_end(v);
  633.         return -1;
  634.     }
  635.     k += i;
  636.     }
  637.  
  638.     va_end(v);
  639.  
  640.     return k;
  641. }
  642.  
  643. void
  644. bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), void *data)
  645. {
  646.     fb->error = error;
  647.     fb->error_data = data;
  648. }
  649.