home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / tail / reverse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-13  |  6.2 KB  |  248 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Edward Sze-Tyan Wang.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)reverse.c    5.3 (Berkeley) 2/12/92";
  39. #endif /* not lint */
  40.  
  41. #include <sys/param.h>
  42. #include <sys/stat.h>
  43. #include <sys/mman.h>
  44. #include <errno.h>
  45. #include <unistd.h>
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include "extern.h"
  50.  
  51. static void r_buf __P((FILE *));
  52. static void r_reg __P((FILE *, enum STYLE, long, struct stat *));
  53.  
  54. /*
  55.  * reverse -- display input in reverse order by line.
  56.  *
  57.  * There are six separate cases for this -- regular and non-regular
  58.  * files by bytes, lines or the whole file.
  59.  *
  60.  * BYTES    display N bytes
  61.  *    REG    mmap the file and display the lines
  62.  *    NOREG    cyclically read characters into a wrap-around buffer
  63.  *
  64.  * LINES    display N lines
  65.  *    REG    mmap the file and display the lines
  66.  *    NOREG    cyclically read lines into a wrap-around array of buffers
  67.  *
  68.  * FILE        display the entire file
  69.  *    REG    mmap the file and display the lines
  70.  *    NOREG    cyclically read input into a linked list of buffers
  71.  */
  72. void
  73. reverse(fp, style, off, sbp)
  74.     FILE *fp;
  75.     enum STYLE style;
  76.     long off;
  77.     struct stat *sbp;
  78. {
  79.     if (style != REVERSE && off == 0)
  80.         return;
  81.  
  82.     if (S_ISREG(sbp->st_mode))
  83.         r_reg(fp, style, off, sbp);
  84.     else
  85.         switch(style) {
  86.         case FBYTES:
  87.             bytes(fp, off);
  88.             break;
  89.         case FLINES:
  90.             lines(fp, off);
  91.             break;
  92.         case REVERSE:
  93.             r_buf(fp);
  94.             break;
  95.         }
  96. }
  97.  
  98. /*
  99.  * r_reg -- display a regular file in reverse order by line.
  100.  */
  101. static void
  102. r_reg(fp, style, off, sbp)
  103.     FILE *fp;
  104.     register enum STYLE style;
  105.     long off;
  106.     struct stat *sbp;
  107. {
  108.     register off_t size;
  109.     register int llen;
  110.     register char *p;
  111.     int fd;
  112.  
  113.     if (!(size = sbp->st_size))
  114.         return;
  115.  
  116.     fd = fileno(fp);
  117.     if ((p =
  118.         mmap(NULL, size, PROT_READ, MAP_FILE, fd, (off_t)0)) == (caddr_t)-1)
  119.         err("%s", strerror(errno));
  120.     p += size - 1;
  121.  
  122.     if (style == RBYTES && off < size)
  123.         size = off;
  124.  
  125.     /* Last char is special, ignore whether newline or not. */
  126.     for (llen = 1; --size; ++llen)
  127.         if (*--p == '\n') {
  128.             WR(p + 1, llen);
  129.             llen = 0;
  130.             if (style == RLINES && !--off) {
  131.                 ++p;
  132.                 break;
  133.             }
  134.         }
  135.     if (llen)
  136.         WR(p, llen);
  137. }
  138.  
  139. typedef struct bf {
  140.     struct bf *next;
  141.     struct bf *prev;
  142.     int len;
  143.     char *l;
  144. } BF;
  145.  
  146. /*
  147.  * r_buf -- display a non-regular file in reverse order by line.
  148.  *
  149.  * This is the function that saves the entire input, storing the data in a
  150.  * doubly linked list of buffers and then displays them in reverse order.
  151.  * It has the usual nastiness of trying to find the newlines, as there's no
  152.  * guarantee that a newline occurs anywhere in the file, let alone in any
  153.  * particular buffer.  If we run out of memory, input is discarded (and the
  154.  * user warned).
  155.  */
  156. static void
  157. r_buf(fp)
  158.     FILE *fp;
  159. {
  160.     register BF *mark, *tl, *tr;
  161.     register int ch, len, llen;
  162.     register char *p;
  163.     off_t enomem;
  164.  
  165. #define    BSZ    (128 * 1024)
  166.     for (mark = NULL, enomem = 0;;) {
  167.         /*
  168.          * Allocate a new block and link it into place in a doubly
  169.          * linked list.  If out of memory, toss the LRU block and
  170.          * keep going.
  171.          */
  172.         if (enomem || (tl = malloc(sizeof(BF))) == NULL ||
  173.             (tl->l = malloc(BSZ)) == NULL) {
  174.             if (!mark)
  175.                 err("%s", strerror(errno));
  176.             tl = enomem ? tl->next : mark;
  177.             enomem += tl->len;
  178.         } else if (mark) {
  179.             tl->next = mark;
  180.             tl->prev = mark->prev;
  181.             mark->prev->next = tl;
  182.             mark->prev = tl;
  183.         } else
  184.             mark->next = mark->prev = (mark = tl);
  185.  
  186.         /* Fill the block with input data. */
  187.         for (p = tl->l, len = 0;
  188.             len < BSZ && (ch = getc(fp)) != EOF; ++len)
  189.             *p++ = ch;
  190.  
  191.         /*
  192.          * If no input data for this block and we tossed some data,
  193.          * recover it.
  194.          */
  195.         if (!len) {
  196.             if (enomem)
  197.                 enomem -= tl->len;
  198.             tl = tl->prev;
  199.             break;
  200.         }
  201.  
  202.         tl->len = len;
  203.         if (ch == EOF)
  204.             break;
  205.     }
  206.  
  207.     if (enomem) {
  208.         (void)fprintf(stderr,
  209.             "tail: warning: %ld bytes discarded\n", enomem);
  210.         rval = 1;
  211.     }
  212.  
  213.     /*
  214.      * Step through the blocks in the reverse order read.  The last char
  215.      * is special, ignore whether newline or not.
  216.      */
  217.     for (mark = tl;;) {
  218.         for (p = tl->l + (len = tl->len) - 1, llen = 0; len--;
  219.             --p, ++llen)
  220.             if (*p == '\n') {
  221.                 if (llen) {
  222.                     WR(p + 1, llen);
  223.                     llen = 0;
  224.                 }
  225.                 if (tl == mark)
  226.                     continue;
  227.                 for (tr = tl->next; tr->len; tr = tr->next) {
  228.                     WR(tr->l, tr->len);
  229.                     tr->len = 0;
  230.                     if (tr == mark)
  231.                         break;
  232.                 }
  233.             }
  234.         tl->len = llen;
  235.         if ((tl = tl->prev) == mark)
  236.             break;
  237.     }
  238.     tl = tl->next;
  239.     if (tl->len) {
  240.         WR(tl->l, tl->len);
  241.         tl->len = 0;
  242.     }
  243.     while ((tl = tl->next)->len) {
  244.         WR(tl->l, tl->len);
  245.         tl->len = 0;
  246.     }
  247. }
  248.