C tail -n Implementation
This a simple implementation for the command 'tail' with the option -n
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#define BUFF_SIZE 4096
#define DEFAULT_LAST_LINES 10
int isNumber(char *string)
{
char *endPointer;
long pid= strtol(string, &endPointer, 10);
if (*endPointer == '\0')
{
return 1;
}
return 0;
}
void printProgramUsage(FILE* stream, int exitCode)
{
fprintf(stream, "valid options\n");
fprintf(stream, "-h Display program usage valid options.\n"
"-n Prints the last n lines.\n");
exit(exitCode);
}
int openFile(const char *file)
{
int fd= open(file, O_RDONLY);
if(fd == -1)
{
fprintf(stderr,"Error opening file: %s\n", file);
exit(errno);
}
return (fd);
}
void printLines(int fd, off_t bytestart)
{
char buffer[BUFF_SIZE];
int readbytes;
lseek(fd,bytestart,SEEK_SET);
while((readbytes= read(fd,buffer,BUFF_SIZE)) > 0)
{
write(STDOUT_FILENO,buffer, readbytes);
}
}
long moveLines(int fd, off_t fileset, long linesdistance)
{
off_t current= lseek(fd, 0, SEEK_CUR);
lseek(fd,fileset,SEEK_SET);
long countlines= 0;
int nbytes;
char buffer[BUFF_SIZE];
long amountbytes= 0;
while((nbytes= read(fd,buffer,BUFF_SIZE)) > 0)
{
int index;
for(index= 0; index < nbytes; index++)
{
if(buffer[index] == '\n')
{
if(countlines == (linesdistance - 1))
{
amountbytes++;
return (fileset + amountbytes);
}
countlines++;
}
amountbytes++;
}
}
return (fileset);
}
void walkFile(int fd, long numlines)
{
long distance= 512;
off_t end_file;
off_t filebytes;
int nbytes;
int flag= 1;
char buffer[BUFF_SIZE];
long countbytes;
long countlines;
long linesdistance= 0;
filebytes= lseek(fd,0,SEEK_END);
end_file= filebytes - distance;
do
{
if(end_file < 0)
{
end_file= 0;
flag= 0;
}
else
{
end_file= moveLines(fd,end_file,1);
}
lseek(fd,end_file,SEEK_SET);
linesdistance= 0;
countbytes= 0;
countlines= 0;
while((nbytes= read(fd,buffer,BUFF_SIZE)) > 0)
{
int index;
off_t moveline;
for(index= 0; index < nbytes; index++)
{
if(buffer[index] == '\n' && (countbytes + end_file + 1) < filebytes)
{
if(countlines == numlines)
{
linesdistance++;
}
if(countlines < numlines)
{
countlines++;
}
}
countbytes++;
}
}
if(countlines == numlines)
{
linesdistance++;
long startline= moveLines(fd,end_file,linesdistance);
printLines(fd,startline);
exit(0);
}
distance= distance * 2;
end_file= filebytes - distance;
}while(flag == 1);
printLines(fd,0);
close(fd);
}
int main(int argc, char *argv[])
{
int fd;
int opt;
char *file= NULL;
long lines;
while((opt= getopt(argc,argv,"hn:")) != -1)
{
switch(opt)
{
case 'h': printProgramUsage(stdout,0);
break;
case 'n':
if(isNumber(optarg))
{
lines= atol(optarg);
break;
}
else
{
fprintf(stderr,"-n argument not is a number\n");
printProgramUsage(stderr,1);
}
case '?': printProgramUsage(stderr,1);
default: printProgramUsage(stderr,1);
}
}
if((optind + 1) != argc)
{
printProgramUsage(stderr,1);
}
file= argv[optind];
if(lines <= 0)
{
lines= DEFAULT_LAST_LINES;
}
fd= openFile(file);
walkFile(fd,lines);
return 0;
}