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[] = "@(#)forward.c 5.4 (Berkeley) 2/12/92"; 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/time.h> 44 #include <sys/mman.h> 45 #include <fcntl.h> 46 #include <errno.h> 47 #include <unistd.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include "extern.h" 52 53 static void rlines __P((FILE *, long, struct stat *)); 54 55 /* 56 * forward -- display the file, from an offset, forward. 57 * 58 * There are eight separate cases for this -- regular and non-regular 59 * files, by bytes or lines and from the beginning or end of the file. 60 * 61 * FBYTES byte offset from the beginning of the file 62 * REG seek 63 * NOREG read, counting bytes 64 * 65 * FLINES line offset from the beginning of the file 66 * REG read, counting lines 67 * NOREG read, counting lines 68 * 69 * RBYTES byte offset from the end of the file 70 * REG seek 71 * NOREG cyclically read characters into a wrap-around buffer 72 * 73 * RLINES 74 * REG mmap the file and step back until reach the correct offset. 75 * NOREG cyclically read lines into a wrap-around array of buffers 76 */ 77 void 78 forward(fp, style, off, sbp) 79 FILE *fp; 80 enum STYLE style; 81 long off; 82 struct stat *sbp; 83 { 84 register int ch; 85 struct timeval second; 86 fd_set zero; 87 88 switch(style) { 89 case FBYTES: 90 if (off == 0) 91 break; 92 if (S_ISREG(sbp->st_mode)) { 93 if (sbp->st_size < off) 94 off = sbp->st_size; 95 if (fseek(fp, off, SEEK_SET) == -1) 96 ierr(); 97 } else while (off--) 98 if ((ch = getc(fp)) == EOF) { 99 if (ferror(fp)) 100 ierr(); 101 break; 102 } 103 break; 104 case FLINES: 105 if (off == 0) 106 break; 107 for (;;) { 108 if ((ch = getc(fp)) == EOF) { 109 if (ferror(fp)) 110 ierr(); 111 break; 112 } 113 if (ch == '\n' && !--off) 114 break; 115 } 116 break; 117 case RBYTES: 118 if (S_ISREG(sbp->st_mode)) { 119 if (sbp->st_size >= off && 120 fseek(fp, -off, SEEK_END) == -1) 121 ierr(); 122 } else if (off == 0) { 123 while (getc(fp) != EOF); 124 if (ferror(fp)) 125 ierr(); 126 } else 127 bytes(fp, off); 128 break; 129 case RLINES: 130 if (S_ISREG(sbp->st_mode)) 131 if (!off) { 132 if (fseek(fp, 0L, SEEK_END) == -1) 133 ierr(); 134 } else 135 rlines(fp, off, sbp); 136 else if (off == 0) { 137 while (getc(fp) != EOF); 138 if (ferror(fp)) 139 ierr(); 140 } else 141 lines(fp, off); 142 break; 143 } 144 145 /* 146 * We pause for one second after displaying any data that has 147 * accumulated since we read the file. 148 */ 149 if (fflag) { 150 FD_ZERO(&zero); 151 second.tv_sec = 1; 152 second.tv_usec = 0; 153 } 154 155 for (;;) { 156 while ((ch = getc(fp)) != EOF) 157 if (putchar(ch) == EOF) 158 oerr(); 159 if (ferror(fp)) 160 ierr(); 161 (void)fflush(stdout); 162 if (!fflag) 163 break; 164 /* Sleep is eight system calls. Do it fast. */ 165 if (select(0, &zero, &zero, &zero, &second) == -1) 166 err("select: %s", strerror(errno)); 167 clearerr(fp); 168 } 169 } 170 171 /* 172 * rlines -- display the last offset lines of the file. 173 */ 174 static void 175 rlines(fp, off, sbp) 176 FILE *fp; 177 long off; 178 struct stat *sbp; 179 { 180 register off_t size; 181 register char *p; 182 183 if (!(size = sbp->st_size)) 184 return; 185 186 if ((p = mmap(NULL, 187 size, PROT_READ, MAP_FILE, fileno(fp), (off_t)0)) == (caddr_t)-1) 188 err("%s", strerror(errno)); 189 190 /* Last char is special, ignore whether newline or not. */ 191 for (p += size - 1; --size;) 192 if (*--p == '\n' && !--off) { 193 ++p; 194 break; 195 } 196 197 /* Set the file pointer to reflect the length displayed. */ 198 size = sbp->st_size - size; 199 WR(p, size); 200 if (fseek(fp, sbp->st_size, SEEK_SET) == -1) 201 ierr(); 202 } 203