/* Simple UNIX like tail on ATARI ST. Kees Lemmens; Juli 1993

   Usage: tail [+|-nr] <filename>
   
   Default is currently to list the last 10 lines from the file,
   which is equal to "tail -10 <filename>"

   Also works with pipes like in "tail file | more".

   Any questions or suggestions about this program can be send to:
   lemmens@dv.twi.tudelft.nl
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ux_misc.h"

#define MAXLEN	255
#define DEFTAIL -10

static char buffer[MAXLEN];

void TailFromEnd(int fp,long len)
{	size_t cumsize,readsize;
	size_t *position;
	size_t x,y;

	position = (size_t *)calloc(len+1,sizeof(size_t));
	/* check for out of memory */

	cumsize = 0L;
	do
	{	readsize = read(fp,buffer,MAXLEN);
		for(x=0;x<readsize;x++)
			if(buffer[x] == '\n')
			{	for(y=len;y>0;y--)	/* shift all previous values */
					position[y] = position[y-1];

				position[0] = cumsize + x;	/* store new value */
			}
		cumsize += readsize;
	}while(readsize == MAXLEN);

	if(position[len] == 0L)
		lseek(fp,0,SEEK_SET);	/* rewind to begin of file */
	else if(lseek(fp,position[len],SEEK_SET) == -1)
		exit(1);

	free(position);
}

void TailFromStart(int fp,long len)
{	size_t cumsize,readsize;
	size_t position;
	size_t x;

	/* just skip the first <len> lines */

	cumsize = 0L;
	do
	{	readsize = read(fp,buffer,MAXLEN);
		for(x=0;x<readsize && len >0;x++)
			if(buffer[x] == '\n')
			{	len--;
				position = cumsize + x;
			}
		cumsize += readsize;
	
	}while(readsize == MAXLEN && len>0);

	lseek(fp,position,SEEK_SET);
}

void ListTail(int fp)
{	size_t readsize;

	do
	{	readsize = read(fp,buffer,MAXLEN);
		write(fileno(stdout),buffer,readsize);
		
	} while(readsize == MAXLEN);
}

void main(int argc,char *argv[]) 
{	int fp;
	long len=DEFTAIL;
	char *filename = NULL;

	while(--argc>0)		/* parse options */
	{	if(*argv[1] == '-' || *argv[1] == '+')
		{	if((len=atol(argv[1])) == 0)
			{	fputs("Illegal value !\n",stderr);
				exit(1);
			}
			++argv;
		}
		else
			filename = argv[1];
	}

	if (filename != NULL)
	{	ux2dos(filename);	/* convert slashes */
		if ((fp = open(filename,O_RDONLY)) < 0)
		{	fputs("\nCan't open file\n",stderr);
			exit(1);
		}
	}
	else
		fp = fileno(stdin);

	if(len  > 0)
		TailFromStart(fp,len);
	else
		TailFromEnd(fp,(-len));
	
	ListTail(fp);

	if (fp != fileno(stdin))
		close(fp);
	exit(0);
}
