1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
#include "gbos.h"
/* tail [-n N] [N] [file]: last N lines (default 10) of a file or stdin.
*
* There is no seek syscall, so this cannot jump to the end: it streams the
* whole input through a ring of N lines and prints the ring at EOF. The ring
* is the memory budget - N lines of up to LINEW chars each - so N is capped. */
#define MAXN 12 /* 12 * 42 = 504 bytes of ring, fits a task */
#define LINEW 42
void main(void) {
char *argv[8];
char ring[MAXN][LINEW];
unsigned char len[MAXN];
unsigned char argc = argv_parse(argv, 8);
char *nv = optval(argv, argc, 'n');
unsigned char n = 10, i, cur = 0, filled = 0, fd = NOFD, l = 0;
char *fname = 0;
int ch;
if (nv) n = atou(nv);
for (i = 0; i < argc; i++) {
if (argv[i][0] == '-') continue;
if (nv == argv[i]) continue;
if (!nv && argv[i][0] >= '0' && argv[i][0] <= '9') {
n = atou(argv[i]);
continue;
}
fname = argv[i];
break;
}
if (n == 0) return;
if (n > MAXN) n = MAXN;
if (fname) {
fd = open(fname, O_READ);
if (fd == EISDIR) {
puts("tail: is a directory");
nl();
sexit(2);
}
if (fd == NOFD) {
puts("tail: no such file");
nl();
sexit(2);
}
}
for (i = 0; i < MAXN; i++) len[i] = 0;
for (;;) {
if (fd == NOFD) {
char c = readc();
ch = (c == EOF) ? -1 : c;
} else ch = fgetc(fd);
if (ch == '\r') continue;
if (ch >= 0 && ch != '\n') {
if (len[cur] < LINEW) ring[cur][len[cur]++] = (char)ch;
continue;
}
if (ch < 0 && len[cur] == 0) break; /* EOF, nothing pending */
cur = (unsigned char)((cur + 1) % n); /* keep only the last n */
if (filled < n) filled++;
len[cur] = 0;
if (ch < 0) break;
}
if (fd != NOFD) close(fd);
/* oldest kept line first: cur points at the (empty) next slot */
i = (unsigned char)((cur + n - filled) % n);
while (filled--) {
writes(ring[i], len[i]);
nl();
i = (unsigned char)((i + 1) % n);
}
}
|