#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); } }