Exercise 5-13 (tail - Print last lines)
Chapter_5 Exercise_5-12-2 | numcmp Exercise_5-14 |
Exercise 5-13 K&R, p. 118
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 that 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.
tail.c download
#include <stdio.h> // for getchar(), putchar(), printf(), EOF
#include <stdlib.h> // for atoi()
#include <string.h> // for strcpy()
#define MAXLINES 20000 // max no of lines to be sorted
#define MAXLEN 100 // max line length
int readlines (char *lineptr[], int nlines);
void writelines (char *lineptr[], int lines); // write last lines
int main(int argc, char *argv[])
{
if (argc > 2)
{
printf("Usage ./tail [-n]\n");
printf("n > 0 no of lines to display\n");
return 1; // exit program, signalling error
}
int lines = 10; // no of lines to display
if (argc == 2)
{
if (*argv[1] != '-')
{
printf("Usage ./tail [-n]\n");
printf("n > 0 no of lines to display\n");
return 1; // exit program, signalling error
}
argv[1]++; // move past '-'
lines = atoi(argv[1]);
if (lines <= 0)
{
printf("Usage ./tail [-n]\n");
printf("n > 0 no of lines to display\n");
return 1; // exit program, signalling error
}
}
char *lineptr[MAXLINES];
int nlines; // no of input lines read
if ((nlines = readlines(lineptr, MAXLINES)) >= 0)
{
if (lines > nlines)
{
lines = nlines;
}
writelines(lineptr+nlines, lines); // lineptr+nlines points after the last element
}
else
{
printf("Error: input too big to sort\n");
return 1; // exit program, signalling error
}
return 0;
}
int getLine(char *, int); // getline() is declared in stdio.h
char* alloc(int); // allocate storage
int readlines (char *lineptr[], int maxlines) // read input lines
{
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getLine(line, MAXLEN)) > 0)
{
if(nlines >= maxlines || (p = alloc(len+1)) == NULL)
{return -1;} // len+1 for ending '\0'
else
{
strcpy(p, line);
lineptr[nlines++] = p;
}
}
return nlines;
}
int getLine(char *s, int lim)
{
int c = EOF; // initialize
char *p;
// getchar() is only executed if ((p-s) < (lim-1)):
for (p = s; (p-s) < (lim-1) && (c = getchar()) != EOF && c != '\n'; p++)
{ // from 0 to lim-2; s[lim-2]='\n', s[lim-1]='\0'
*p = c;
}
if (c == '\n')
{*p++ = c;}
*p = '\0'; // the null character ends a string
return p-s; // max(p-s) == (lim-1)
}
#define ALLOCSIZE (MAXLINES * MAXLEN)
static char allocbuf[ALLOCSIZE]; // storage for alloc()
static char *allocp = allocbuf; // next free position
char* alloc(int n) // return pointer to n chars
{
if (allocbuf + ALLOCSIZE - allocp >= n) // it fits
{
allocp += n;
return allocp-n; // old pointer
}
else {return 0;} // null pointer
}
void afree(char *p) // free storage pointed to by p
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
{allocp = p;}
}
void writelines (char *lineptr[], int lines) // write output lines
{
lineptr -= lines;
while (lines-- > 0)
{printf("%s", *lineptr++);}
}
/*
gcc tail.c -o tail
./tail 10
Usage ./tail [-n]
n > 0 no of lines to display
./tail -0
Usage ./tail [-n]
n > 0 no of lines to display
./tail --1
Usage ./tail [-n]
n > 0 no of lines to display
./tail < me.txt // prints last 10 lines
./tail -10 < me.txt // prints last 10 lines
./tail -100 < me.txt // prints last 100 lines
*/
Notes:
For the contents of text file me.txt see
Martin_Eden on
Project_Gutenberg.
Redefine MAXLINES and MAXLEN if you use other input file.
getLine() should return after reading
'\n' or EOF (upon reaching the end of file),
otherwise it may need ungetch(), see
Chapter_4, Sec. 4.3.
Chapter_5 Exercise_5-12-2 | BACK_TO_TOP | numcmp Exercise_5-14 |
Comments
Post a Comment