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