Annotation of src/usr.bin/tail/forward.c, Revision 1.1.1.1
1.1 deraadt 1: /* $NetBSD: forward.c,v 1.6 1994/11/23 07:42:02 jtc Exp $ */
2:
3: /*-
4: * Copyright (c) 1991, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * Edward Sze-Tyan Wang.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93";
42: #endif
43: static char rcsid[] = "$NetBSD: forward.c,v 1.6 1994/11/23 07:42:02 jtc Exp $";
44: #endif /* not lint */
45:
46: #include <sys/types.h>
47: #include <sys/stat.h>
48: #include <sys/time.h>
49: #include <sys/mman.h>
50:
51: #include <limits.h>
52: #include <fcntl.h>
53: #include <errno.h>
54: #include <unistd.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
58: #include "extern.h"
59:
60: static void rlines __P((FILE *, long, struct stat *));
61:
62: /*
63: * forward -- display the file, from an offset, forward.
64: *
65: * There are eight separate cases for this -- regular and non-regular
66: * files, by bytes or lines and from the beginning or end of the file.
67: *
68: * FBYTES byte offset from the beginning of the file
69: * REG seek
70: * NOREG read, counting bytes
71: *
72: * FLINES line offset from the beginning of the file
73: * REG read, counting lines
74: * NOREG read, counting lines
75: *
76: * RBYTES byte offset from the end of the file
77: * REG seek
78: * NOREG cyclically read characters into a wrap-around buffer
79: *
80: * RLINES
81: * REG mmap the file and step back until reach the correct offset.
82: * NOREG cyclically read lines into a wrap-around array of buffers
83: */
84: void
85: forward(fp, style, off, sbp)
86: FILE *fp;
87: enum STYLE style;
88: long off;
89: struct stat *sbp;
90: {
91: register int ch;
92: struct timeval second;
93: fd_set zero;
94:
95: switch(style) {
96: case FBYTES:
97: if (off == 0)
98: break;
99: if (S_ISREG(sbp->st_mode)) {
100: if (sbp->st_size < off)
101: off = sbp->st_size;
102: if (fseek(fp, off, SEEK_SET) == -1) {
103: ierr();
104: return;
105: }
106: } else while (off--)
107: if ((ch = getc(fp)) == EOF) {
108: if (ferror(fp)) {
109: ierr();
110: return;
111: }
112: break;
113: }
114: break;
115: case FLINES:
116: if (off == 0)
117: break;
118: for (;;) {
119: if ((ch = getc(fp)) == EOF) {
120: if (ferror(fp)) {
121: ierr();
122: return;
123: }
124: break;
125: }
126: if (ch == '\n' && !--off)
127: break;
128: }
129: break;
130: case RBYTES:
131: if (S_ISREG(sbp->st_mode)) {
132: if (sbp->st_size >= off &&
133: fseek(fp, -off, SEEK_END) == -1) {
134: ierr();
135: return;
136: }
137: } else if (off == 0) {
138: while (getc(fp) != EOF);
139: if (ferror(fp)) {
140: ierr();
141: return;
142: }
143: } else
144: bytes(fp, off);
145: break;
146: case RLINES:
147: if (S_ISREG(sbp->st_mode))
148: if (!off) {
149: if (fseek(fp, 0L, SEEK_END) == -1) {
150: ierr();
151: return;
152: }
153: } else
154: rlines(fp, off, sbp);
155: else if (off == 0) {
156: while (getc(fp) != EOF);
157: if (ferror(fp)) {
158: ierr();
159: return;
160: }
161: } else
162: lines(fp, off);
163: break;
164: }
165:
166: /*
167: * We pause for one second after displaying any data that has
168: * accumulated since we read the file.
169: */
170: if (fflag) {
171: FD_ZERO(&zero);
172: second.tv_sec = 1;
173: second.tv_usec = 0;
174: }
175:
176: for (;;) {
177: while ((ch = getc(fp)) != EOF)
178: if (putchar(ch) == EOF)
179: oerr();
180: if (ferror(fp)) {
181: ierr();
182: return;
183: }
184: (void)fflush(stdout);
185: if (!fflag)
186: break;
187: /* Sleep(3) is eight system calls. Do it fast. */
188: if (select(0, &zero, &zero, &zero, &second) == -1)
189: err(1, "select: %s", strerror(errno));
190: clearerr(fp);
191: }
192: }
193:
194: /*
195: * rlines -- display the last offset lines of the file.
196: */
197: static void
198: rlines(fp, off, sbp)
199: FILE *fp;
200: long off;
201: struct stat *sbp;
202: {
203: register off_t size;
204: register char *p;
205: char *start;
206:
207: if (!(size = sbp->st_size))
208: return;
209:
210: if (size > SIZE_T_MAX) {
211: err(0, "%s: %s", fname, strerror(EFBIG));
212: return;
213: }
214:
215: if ((start = mmap(NULL, (size_t)size,
216: PROT_READ, 0, fileno(fp), (off_t)0)) == (caddr_t)-1) {
217: err(0, "%s: %s", fname, strerror(EFBIG));
218: return;
219: }
220:
221: /* Last char is special, ignore whether newline or not. */
222: for (p = start + size - 1; --size;)
223: if (*--p == '\n' && !--off) {
224: ++p;
225: break;
226: }
227:
228: /* Set the file pointer to reflect the length displayed. */
229: size = sbp->st_size - size;
230: WR(p, size);
231: if (fseek(fp, (long)sbp->st_size, SEEK_SET) == -1) {
232: ierr();
233: return;
234: }
235: if (munmap(start, (size_t)sbp->st_size)) {
236: err(0, "%s: %s", fname, strerror(errno));
237: return;
238: }
239: }