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

Popular posts from this blog

Contents

Blogger Page Margins in Contempo