home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff319.lzh / CNewsSrc / cnews.orig.lzh / libstdio / fgets.c next >
C/C++ Source or Header  |  1989-06-27  |  3KB  |  119 lines

  1. #include <stdio.h>
  2. #ifndef PTR_TYPE
  3. #define    PTR_TYPE    char *        /* type of _ptr in stdio.h */
  4. #endif
  5.  
  6. #define THRESHOLD 12            /* memcpy vs in-line threshold */
  7.  
  8. char *
  9. fgets(s, lim, fp)            /* optimised version */
  10. char *s;
  11. int lim;
  12. register FILE *fp;
  13. {
  14.     char *rets = s;            /* normal return by default */
  15.  
  16.     --lim;                /* leave room for terminating null */
  17.     while (lim > 0) {        /* room left in s */
  18.         int origbytesleft;
  19.         char *nlp = NULL;    /* points at newline */
  20.  
  21.         /*
  22.          * Find next newline (if any) by running through the
  23.          * stdio buffer until it runs out or a newline is seen.
  24.          * This dominates the running time for long lines.
  25.          */
  26.         {
  27.             register char *bp = (char *)fp->_ptr;
  28.             register int loops;
  29.             /* bytes to the end of s or the stdio buffer */
  30.             register int bytesleft = fp->_cnt;    /* to EOB */
  31.  
  32.             if (bytesleft > lim)    /* buffer longer than s */
  33.                 bytesleft = lim; /* only copy to s's end */
  34.             origbytesleft = bytesleft;
  35.  
  36.             /*
  37.              * This code uses Duff's Device (tm Tom Duff)
  38.              * to unroll the newline recogniser:
  39.              * for (++bytesleft; --bytesleft > 0; )
  40.              *    if (*bp++ == '\n') {
  41.              *        nlp = bp;    # NB points after \n
  42.              *        break;
  43.              *    }
  44.              * Sorry the code is so ugly.
  45.              */
  46.             if (bytesleft > 0) {
  47.                 /*
  48.                  * warning: this will need to be changed for
  49.                  * non-binary machines, if they exist.
  50.                  */
  51.                 loops = (bytesleft+8-1) >> 3;    /* /8 round up */
  52.  
  53.                 switch (bytesleft&(8-1)) {    /* %8 */
  54.                 case 0: do {
  55. #define SPOTNL if (*bp++ == '\n') { nlp = bp; break; }
  56.                         SPOTNL;
  57.                     case 7:    SPOTNL;
  58.                     case 6:    SPOTNL;
  59.                     case 5:    SPOTNL;
  60.                     case 4:    SPOTNL;
  61.                     case 3:    SPOTNL;
  62.                     case 2:    SPOTNL;
  63.                     case 1:    SPOTNL;
  64.                     } while (--loops > 0);
  65.                 }
  66.             }
  67.         }
  68.         /*
  69.          * If no newline was seen, copy remaining bytes from stdio
  70.          * buffer; else copy up to and including the newline.
  71.          * Adjust counts, then copy the bytes & adjust pointers.
  72.          * This dominates the running time for short lines.
  73.          */
  74.         {
  75.             register int copy;
  76.  
  77.             if (nlp == NULL)
  78.                 copy = origbytesleft;
  79.             else
  80.                 copy = nlp - (char *)fp->_ptr;
  81.             lim -= copy;
  82.             fp->_cnt -= copy;
  83.             if (copy < THRESHOLD) {
  84.                 register char *rs = s, *bp = (char *)fp->_ptr;
  85.  
  86.                 for (++copy; --copy > 0; )
  87.                     *rs++ = *bp++;
  88.                 s = rs;
  89.                 fp->_ptr = (PTR_TYPE)bp;
  90.             } else {
  91.                 memcpy(s, (char *)fp->_ptr, copy);
  92.                 s += copy;
  93.                 fp->_ptr += copy;
  94.             }
  95.         }
  96.         /*
  97.          * Quit if we saw a newline or "s" is full,
  98.          * else refill the stdio buffer and go again.
  99.          */
  100.         if (nlp != NULL || lim <= 0)
  101.             break;
  102.         else if (fp->_cnt <= 0) {        /* buffer empty */
  103.             register int c = getc(fp);    /* fill buffer */
  104.  
  105.             if (c == EOF) {
  106.                 if (s == rets)        /* s is empty */
  107.                     rets = NULL;
  108.                 break;            /* EOF return */
  109.             } else {
  110.                 if ((*s++ = c) == '\n')
  111.                     break;        /* newline return */
  112.                 --lim;
  113.             }
  114.         }
  115.     }
  116.     *s = '\0';    /* terminate s */
  117.     return rets;
  118. }
  119.