V9/cmd/tail.c

Compare this file to the similar file:
Show the results in this format:

/* tail command 
 *
 *	tail where [file]
 *	where is +_n[type]
 *	- means n lines before end
 *	+ means nth line from beginning
 *	type 'b' means tail n blocks, not lines
 *	type 'c' means tail n characters
 *	Type 'r' means in lines in reverse order from end
 *	 (for -r, default is entire buffer )
 *	option 'f' means loop endlessly trying to read more
 *		characters after the end of file, on the  assumption
 *		that the file is growing
*/

#include	<stdio.h>
#include	<ctype.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<errno.h>

#define LBIN 16383
struct	stat	statb;
int	follow;
int	piped;
char	bin[LBIN];
int	errno;
int	infd = 0;

main(argc,argv)
char **argv;
{
	long n,di;
	register i,j,k;
	char *arg;
	int partial,bylines,bkwds,fromend,lastnl;
	char *p;
	int anydigit = 0;

	arg = argv[1];
	if(argc<=1 || *arg!='-'&&*arg!='+') {
		arg = "-10l";
		argc++;
		argv--;
	}
	n = 0;
	fromend = *arg=='-';
	arg++;
	while(isdigit(*arg)) {
		anydigit++;
		n = n*10 + *arg++ - '0';
	}
	if(!fromend&&n>0)
		n--;
	if(argc>2) {
		if((infd = open(argv[2],0))<0) {
			perror(argv[2]);
			exit(1);
		}
	}
	lseek(infd,(long)0,1);
	piped = errno==ESPIPE;
	bylines = -1; bkwds = 0;
	while(*arg)
	switch(*arg++) {

	case 'b':
		n *= BUFSIZ;
		if(bylines!=-1) goto errcom;
		bylines=0;
		break;
	case 'c':
		if(bylines!=-1) goto errcom;
		bylines=0;
		break;
	case 'f':
		follow = 1;
		break;
	case 'r':
		if(!anydigit) n = LBIN;
		bkwds = 1; fromend = 1; bylines = 1;
		break;
	case 'l':
		if(bylines!=-1) goto errcom;
		bylines = 1;
		break;
	default:
		goto errcom;
	}
        if(fromend && !bkwds && !anydigit) n = 10;
	if(bylines==-1) bylines = 1;
	if(bkwds) follow=0;
	if(fromend)
		goto keep;

			/*seek from beginning */

	if(bylines) {
		j = 0;
		while(n-->0) {
			do {
				if(j--<=0) {
					p = bin;
					j = read(infd,p,BUFSIZ);
					if(j--<=0)
						fexit();
				}
			} while(*p++ != '\n');
		}
		if(j>0)
			zwrite(1,p,j);
	} else  if(n>0) {
		if(!piped)
			fstat(infd,&statb);
		if(piped||(statb.st_mode&S_IFMT)==S_IFCHR)
			while(n>0) {
				i = n>BUFSIZ?BUFSIZ:n;
				i = read(infd,bin,i);
				if(i<=0)
					fexit();
				n -= i;
			}
		else
			lseek(infd,n,0);
	}
copy:
	while((i=read(infd,bin,BUFSIZ))>0)
		zwrite(1,bin,i);
	fexit();

			/*seek from end*/

keep:
	if(n <= 0) {
		lseek(infd,0L,2);
		fexit();
	}
	if(!piped) {
		fstat(infd,&statb);
		di = !bylines&&n<LBIN?n:LBIN-1;
		if(statb.st_size > di)
			lseek(infd,-di,2);
		if(!bylines)
			goto copy;
	}
	partial = 1;
	for(;;) {
		i = 0;
		do {
			j = read(infd,&bin[i],LBIN-i);
			if(j<=0)
				goto brka;
			i += j;
		} while(i<LBIN);
		partial = 0;
	}
brka:
	if(!bylines) {
		k = n<=i ? i-n: partial ? 0: n>=LBIN ? i+1: i-n+LBIN;
		k--;
	} else {
		if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){	/* force trailing newline */
			bin[i]='\n';
			if(++i>=LBIN) {i = 0; partial = 0;}
		}
		k = i;
		j = 0;
		do {
			lastnl = k;
			do {
				if(--k<0) {
					if(partial) {
						if(bkwds) zwrite(1,bin,lastnl+1);
						goto brkb;
					}
					k = LBIN -1;
				}
			} while(bin[k]!='\n'&&k!=i);
			if(bkwds && j>0){
				if(k<lastnl) zwrite(1,&bin[k+1],lastnl-k);
				else {
					if(k<LBIN-1)
						zwrite(1,&bin[k+1],LBIN-k-1);
					zwrite(1,bin,lastnl+1);
				}
			}
		} while(j++<n&&k!=i);
brkb:
		if(bkwds) exit(0);
		if(k==i) do {
			if(++k>=LBIN)
				k = 0;
		} while(bin[k]!='\n'&&k!=i);
	}
	if(k<i)
		zwrite(1,&bin[k+1],i-k-1);
	else {
		if(k<LBIN-1)
			zwrite(1,&bin[k+1],LBIN-k-1);
		if(i>0)
			zwrite(1,bin,i);
	}
	fexit();
errcom:
	fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n");
	exit(2);
}

fexit()
{	register int n;
	long amtread;
	if (!follow || piped) exit(0);
	amtread = lseek(infd, 0L, 1);
	for (;;) {
		sleep(5);
		if(fstat(infd, &statb) == -1)
			exit(1);
		if(statb.st_size < amtread) {
			fprintf(stderr, "tail: file truncated; restarting\n");
			lseek(infd, 0L, 0);
			amtread = 0;
		}
		while ((n = read (infd, bin, BUFSIZ)) > 0) {
			zwrite (1, bin, n);
			amtread += n;
		}
		if(n < 0)
			exit(1);
	}
}

zwrite(f, b, n)
char *b;
{
	if (n!=0)
		write(f, b, n);
}