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