Page 118

Write the program tail, which prints the last n lines of its input. By default, n is 10, 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 makes 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.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define DEFAULT_PRINT_COUNT 10
#define STORE_SIZE 1000000
#define MAX_LINES 1000
#define MAX_LINE 1000

int get_line(char s[], int lim);

int main(int argc, char *argv[])
{
	unsigned print_count = DEFAULT_PRINT_COUNT;
	unsigned line_count;
	char storage[STORE_SIZE];
	char *lines[MAX_LINES];

	int i;
	while (--argc > 0) {
		if (argv[argc][0] == '-') {
			for (i = 1; isdigit(argv[argc][i]); i++)
				;
			if (argv[argc][i] == '\0') {
				print_count = atoi(&argv[argc][1]);
			} else {
				printf("Invalid argument '%s'! Must be an integer.\n",
				       argv[argc]);
			}
		}
	}

	unsigned len;
	unsigned used = 0;
	for (; (len = get_line(storage + used, MAX_LINE)) > 0; line_count++) {
		lines[line_count] = storage + used;
		used += len + 1;
	}

	for (i = print_count > line_count ? 0 : line_count - print_count;
	     i < line_count; i++) {
		printf("%s", lines[i]);
	}
}

int get_line(char s[], int lim)
{
	int c, i;

	i = 0;
	while (--lim > 0 && (c = getchar()) != EOF && c != '\n') {
		s[i++] = c;
	}
	if (c == '\n') {
		s[i++] = c;
	}
	s[i] = '\0';
	return i;
}