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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The C Programming Language: 2nd Edition
*
* Exercise 5-13: Write the program `tail`, which prints the last n lines of
* its input. By default, n is 10, let us say, but it can be changed by an
* optional argument, so that `tail -n` prints the last n lines. The program
* should behave rationally no matter how unreasonable the input or the value
* of n. Write the program so it make the best use of available storage; lines
* should be stored as in the sorting program of Section 5.6, not in a
* two-dimensional array of fixed size.
*/
#define MAXLINES 50000
#define MAXLEN 1000
#define DEFAULT_LINES 10
#define ALLOCSIZE 10000000
static char allocbuf[ALLOCSIZE];
static char *allocp = allocbuf;
char *lineptr[MAXLINES];
int numlines;
int mygetline(char *line, int lim) {
int c, i;
for (i = 0; i < lim && (c = getchar()) != EOF && c != '\n'; i++) {
*(line++) = c;
}
if (c == '\n') {
i++; /* I count newlines; some don't */
*(line++) = c;
}
*line = '\0';
return i;
}
char *alloc(int n) {
if (allocbuf + ALLOCSIZE - allocp >= n) {
allocp += n;
return allocp - n;
} else {
return 0;
}
}
int readlines(char *lineptr[], int maxlines) {
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = mygetline(line, MAXLEN)) > 0) {
if (nlines >= maxlines || (p = alloc(len)) == NULL) {
return -1;
} else {
line[len-1] = '\0';
strcpy(p, line);
lineptr[nlines++] = p;
}
}
return nlines;
}
void writelines(char *lineptr[], int sline, int nlines) {
int i;
if (sline > 0) {
i = sline;
} else {
i = 0;
}
for (; i < nlines && lineptr[i] != NULL; i++) {
printf("%s\n", lineptr[i]);
}
}
void parse_args(int argc, char *argv[]) {
if (argc == 2 && *(++argv)[0] == '-') {
int i = 1;
char arg[10];
for (i = 1; i < 10 && (*argv)[i] != '\0'; i++) {
arg[i - 1] = (*argv)[i];
}
numlines = atoi(arg);
} else {
numlines = DEFAULT_LINES;
}
}
int main(int argc, char *argv[]) {
int nlines;
parse_args(argc, argv);
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
writelines(lineptr, nlines - numlines, nlines);
return 0;
} else {
/* we should repeat ourselves here so tail fails, but gracefully. We
* _did_ gather some input, and should print it! */
nlines = MAXLINES;
writelines(lineptr, nlines - numlines, nlines);
printf("-----------------------\n");
printf("ERROR: Input too large.\n");
return 1;
}
}
|