That is a lot of code for the job. It can be done significantly more easily in two areas:
- use an array instead of a queue
- use the POSIX function,
getline, which will handle lines of any size.
If you don't want to use getline (which admittedly might not have existed when K&R wrote their book), concentrate on writing its equivalent.
Here is a version that uses an allocated array or char* pointers. The array is zeroed (by calloc) so that we can tell whether the entry holds a line (which might not be so if the input is less than 10 (or the requested number of) lines.
int
tail(size_t n_lines, FILE *fp)
{
char **lines = calloc(sizeof(char*), n_lines);
if (!lines) {
perror("calloc");
return -1;
}
size_t size = 0;
size_t in = 0;
for (char *ln = 0; getline(&ln, &size, fp) > 0; in = (in + 1) % n_lines) {
if (lines[in]) {
free(lines[in]);
}
lines[in] = ln;
ln = NULL;
size = 0;
}
for (size_t i = 0; i < n_lines; ++i) {
if (lines[in]) {
printf("%s", lines[in]);
free(lines[in]);
}
in = (in + 1) % n_lines;
}
free(lines);
return 0;
}