#include <stdio.h>
#include <local.h>

#define	LINSIZ	128	/* max bytes in 1 line */
#define	DEFAULT	10	/* default lines used  */

#define max(x, y)  ((x) > (y) ? (x) : (y))

/*
 * TAIL.C - the tail of a file, works like a filter if there are no
 * files specified on the command line, the unix utility does not
 * allow wildcards in the tail and tail commands, so they are not
 * supported, usage like: tail {/n} {file file ... }
 */

static	char *Program [] = { "S. Leoce, *nix(tm) tail.c"
			     "v1.0 r1.0 svclvl 1 va@psj" };

static	char *Usage = "usage: tail [/hn#] [file file ...]";

#include "b:cmdline.c"

typedef	struct	qnode {			/* queue entry node		  */
	char *ln;			/* next line data area		  */
	struct  qnode *next;		/* next node in queue		  */
} node;
static	long qsize = 0L;

int main (argc, argv)
char	*argv[];
int	 argc;
{
	short	unsigned LineOption = FALSE;
	short	unsigned header     = FALSE;
	long	register number = DEFAULT;	/* default lines to write */
	FILE	*fp;				/* file stream pointer	  */
	char	line [LINSIZ];			/* input line		  */
	node	*enqueue();			/* insert routine	  */
	node	*release();			/* the free routine	  */

	node *front = NULL;
	node *rear  = NULL;

	opterr = FALSE;
	while ((LineOption = getopt(argc, argv, "hn:")) != EOF)
		switch(LineOption) {
		case '?':
			fprintf(stderr,"tail: illegal option %c\n",badopt);
			_exit (0x04);
		case 'n':
			number = max(atol(optarg),0);
			break;
		case 'h':
			header = TRUE;
		}	/* switch closed here */

	if (number == 0)
		_exit(fprintf(stderr,"%s\n", Usage) + 0x04);

	if (argv[optind] == NULL) {	/* use like a filter now	  */
		while(fgets(line,LINSIZ,stdin) != NULL)
			if (number > 0) {
				front = enqueue(front,number--,line);
				if (++qsize == 1)
					rear = front;
				else
					rear = rear -> next;
			}
			if (number == 0)
				rear -> next = front;
			else {			  /* move the queue down */
				rear = front;
				front = front -> next;
				strcpy(rear -> ln, line);
			}
		dequeue(front,qsize);
	}
	else {				/* do each file			  */
		long save = number;
		while (argv[optind] != NULL) {
			if (header)
				printf("--------------- %s\n",argv[optind]);
			number = save;
			qsize  = 0L;
			if ((fp = fopen(argv[optind++], "r")) == NULL)
				_exit(perror(strcat("tail: can't open ",
					strupr(argv[optind-1]))) + 0x10);
			while(fgets(line, LINSIZ, fp) != NULL)
				if (number > 0) {	/* enqueue next  */
					front = enqueue(front,number--,line);
					if (++qsize == 1)	/* rear is same */
						rear = front;
					else
						rear = rear -> next;
					if (number == 0)
						rear -> next = front;
				}					
				else {		  /* move the queue down */
					strcpy (front -> ln, line);
					rear = front;
					front = front -> next;
				}
			dequeue(front,qsize);
			fclose (fp);
			front = rear = release(front,qsize);
			printf("\n");	/* ensure the newline for next file */
		}
	}	/* else is closed */

	return (0);
}

node *enqueue(p,n,data)
node *p;
char *data;
long n;
{
	char *strwrt();

	if (p == NULL) {	/* here's the place to link ... */
		if ((p = (node *) malloc(sizeof(node))) == NULL)
			_exit(fprintf(stderr,
				"tail: insufficient core\n") + 0x10);
		p -> ln = strwrt(data, LINSIZ);
		p -> next = NULL;
	}
	else
		p -> next = enqueue(p -> next, n, data);

	return (p);		/* return the pointer here */

}

char *strwrt(s,n)		/* save a string s somewhere in memory */
char *s;
unsigned n;
{
	char *p;

	if ((p = (char *) malloc(n+1)) != NULL)
		strcpy (p, s);
	else
		_exit(fprintf(stderr,"tail: insufficient core\n") + 0x10);

	return (p);
}

dequeue(q,n)
node *q;
long n;
{
	while (n-- > 0 && q != NULL) {
		printf ("%s", q -> ln);
		q = q -> next;
	}
}

node *release(p,s)
node *p;
long s;
{
	/* release the pointers and the node item for next time */
	
	auto node *q = p;

	while (s-- > 0) {
		q = p -> next;
		free (p -> ln);
		free (p);
		p = q;
	}
	return (NULL);
}
		