Serious quoteing problem in conditionals:
[unix-history] / usr / src / usr.bin / tail / forward.c
CommitLineData
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 12static 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
29static 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 */
53void
54forward(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 */
166static void
167rlines(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}