xref: /csrg-svn/usr.bin/tail/tail.c (revision 17708)
1*17708Sbloom #ifndef lint
2*17708Sbloom static char *sccsid = "@(#)tail.c	4.6 (Berkeley) 01/14/85";
3*17708Sbloom #endif
41214Sroot /* tail command
51214Sroot  *
61214Sroot  *	tail where [file]
713537Ssam  *	where is +/-n[type]
81214Sroot  *	- means n lines before end
91214Sroot  *	+ means nth line from beginning
101214Sroot  *	type 'b' means tail n blocks, not lines
111214Sroot  *	type 'c' means tail n characters
121214Sroot  *	Type 'r' means in lines in reverse order from end
131214Sroot  *	 (for -r, default is entire buffer )
141214Sroot  *	option 'f' means loop endlessly trying to read more
151214Sroot  *		characters after the end of file, on the  assumption
161214Sroot  *		that the file is growing
171214Sroot */
181214Sroot 
191214Sroot #include	<stdio.h>
201214Sroot #include	<ctype.h>
211214Sroot #include	<sys/types.h>
221214Sroot #include	<sys/stat.h>
23*17708Sbloom #include	<sys/file.h>
241214Sroot #include	<errno.h>
251214Sroot 
2616583Sralph #define LBIN 8193
2716583Sralph #undef	BUFSIZ
2816583Sralph #define	BUFSIZ	LBIN-1
291214Sroot struct	stat	statb;
301214Sroot int	follow;
311214Sroot int	piped;
321214Sroot char bin[LBIN];
331214Sroot int errno;
341214Sroot 
351214Sroot main(argc,argv)
361214Sroot char **argv;
371214Sroot {
381214Sroot 	long n,di;
391214Sroot 	register i,j,k;
401214Sroot 	char	*arg;
411214Sroot 	int partial,bylines,bkwds,fromend,lastnl;
421214Sroot 	char *p;
431214Sroot 
441214Sroot 	arg = argv[1];
451214Sroot 	if(argc<=1 || *arg!='-'&&*arg!='+') {
461214Sroot 		arg = "-10l";
471214Sroot 		argc++;
481214Sroot 		argv--;
491214Sroot 	}
501214Sroot 	fromend = *arg=='-';
511214Sroot 	arg++;
5214806Skarels 	if (isdigit(*arg)) {
5314806Skarels 		n = 0;
5414806Skarels 		while(isdigit(*arg))
5514806Skarels 			n = n*10 + *arg++ - '0';
5614806Skarels 	} else
5714806Skarels 		n = -1;
581214Sroot 	if(!fromend&&n>0)
591214Sroot 		n--;
601214Sroot 	if(argc>2) {
61*17708Sbloom 		(void)close(0);
621214Sroot 		if(open(argv[2],0)!=0) {
631214Sroot 			perror(argv[2]);
641214Sroot 			exit(1);
651214Sroot 		}
661214Sroot 	}
67*17708Sbloom 	(void)lseek(0,(off_t)0,L_INCR);
6812889Sralph 	piped = errno==ESPIPE;
691214Sroot 	bylines = -1; bkwds = 0;
701214Sroot 	while(*arg)
711214Sroot 	switch(*arg++) {
721214Sroot 
731214Sroot 	case 'b':
7416583Sralph 		if (n == -1) n = 1;
751214Sroot 		n <<= 9;
761214Sroot 		if(bylines!=-1) goto errcom;
771214Sroot 		bylines=0;
781214Sroot 		break;
791214Sroot 	case 'c':
801214Sroot 		if(bylines!=-1) goto errcom;
811214Sroot 		bylines=0;
821214Sroot 		break;
831214Sroot 	case 'f':
841214Sroot 		follow = 1;
851214Sroot 		break;
861214Sroot 	case 'r':
8714806Skarels 		if(n==-1) n = LBIN;
881214Sroot 		bkwds = 1; fromend = 1; bylines = 1;
891214Sroot 		break;
901214Sroot 	case 'l':
911214Sroot 		if(bylines!=-1) goto errcom;
921214Sroot 		bylines = 1;
931214Sroot 		break;
941214Sroot 	default:
951214Sroot 		goto errcom;
961214Sroot 	}
9714806Skarels 	if (n==-1) n = 10;
981214Sroot 	if(bylines==-1) bylines = 1;
991214Sroot 	if(bkwds) follow=0;
1001214Sroot 	if(fromend)
1011214Sroot 		goto keep;
1021214Sroot 
1031214Sroot 			/*seek from beginning */
1041214Sroot 
1051214Sroot 	if(bylines) {
1061214Sroot 		j = 0;
1071214Sroot 		while(n-->0) {
1081214Sroot 			do {
1091214Sroot 				if(j--<=0) {
1101214Sroot 					p = bin;
1111214Sroot 					j = read(0,p,BUFSIZ);
1121214Sroot 					if(j--<=0)
1131214Sroot 						fexit();
1141214Sroot 				}
1151214Sroot 			} while(*p++ != '\n');
1161214Sroot 		}
117*17708Sbloom 		(void)write(1,p,j);
1181214Sroot 	} else  if(n>0) {
1191214Sroot 		if(!piped)
120*17708Sbloom 			(void)fstat(0,&statb);
1211214Sroot 		if(piped||(statb.st_mode&S_IFMT)==S_IFCHR)
1221214Sroot 			while(n>0) {
1231214Sroot 				i = n>BUFSIZ?BUFSIZ:n;
1241214Sroot 				i = read(0,bin,i);
1251214Sroot 				if(i<=0)
1261214Sroot 					fexit();
1271214Sroot 				n -= i;
1281214Sroot 			}
1291214Sroot 		else
130*17708Sbloom 			(void)lseek(0,(off_t)n,L_SET);
1311214Sroot 	}
1321214Sroot copy:
1331214Sroot 	while((i=read(0,bin,BUFSIZ))>0)
134*17708Sbloom 		(void)write(1,bin,i);
1351214Sroot 	fexit();
1361214Sroot 
1371214Sroot 			/*seek from end*/
1381214Sroot 
1391214Sroot keep:
1401214Sroot 	if(n <= 0)
1411214Sroot 		fexit();
1421214Sroot 	if(!piped) {
143*17708Sbloom 		(void)fstat(0,&statb);
14416583Sralph 		/* If by lines, back up 1 buffer: else back up as needed */
14516583Sralph 		di = bylines?BUFSIZ:n;
1461214Sroot 		if(statb.st_size > di)
147*17708Sbloom 			(void)lseek(0,(off_t)-di,L_XTND);
1481214Sroot 		if(!bylines)
1491214Sroot 			goto copy;
1501214Sroot 	}
1511214Sroot 	partial = 1;
1521214Sroot 	for(;;) {
1531214Sroot 		i = 0;
1541214Sroot 		do {
1551214Sroot 			j = read(0,&bin[i],LBIN-i);
1561214Sroot 			if(j<=0)
1571214Sroot 				goto brka;
1581214Sroot 			i += j;
1591214Sroot 		} while(i<LBIN);
1601214Sroot 		partial = 0;
1611214Sroot 	}
1621214Sroot brka:
1631214Sroot 	if(!bylines) {
1641214Sroot 		k =
1651214Sroot 		    n<=i ? i-n:
1661214Sroot 		    partial ? 0:
1671214Sroot 		    n>=LBIN ? i+1:
1681214Sroot 		    i-n+LBIN;
1691214Sroot 		k--;
1701214Sroot 	} else {
1711214Sroot 		if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){	/* force trailing newline */
1721214Sroot 			bin[i]='\n';
1731214Sroot 			if(++i>=LBIN) {i = 0; partial = 0;}
1741214Sroot 		}
1751214Sroot 		k = i;
1761214Sroot 		j = 0;
1771214Sroot 		do {
1781214Sroot 			lastnl = k;
1791214Sroot 			do {
1801214Sroot 				if(--k<0) {
1811214Sroot 					if(partial) {
182*17708Sbloom 						if(bkwds)
183*17708Sbloom 						    (void)write(1,bin,lastnl+1);
1841214Sroot 						goto brkb;
1851214Sroot 					}
1861214Sroot 					k = LBIN -1;
1871214Sroot 				}
1881214Sroot 			} while(bin[k]!='\n'&&k!=i);
1891214Sroot 			if(bkwds && j>0){
190*17708Sbloom 				if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k);
1911214Sroot 				else {
192*17708Sbloom 					(void)write(1,&bin[k+1],LBIN-k-1);
193*17708Sbloom 					(void)write(1,bin,lastnl+1);
1941214Sroot 				}
1951214Sroot 			}
1961214Sroot 		} while(j++<n&&k!=i);
1971214Sroot brkb:
1981214Sroot 		if(bkwds) exit(0);
1991214Sroot 		if(k==i) do {
2001214Sroot 			if(++k>=LBIN)
2011214Sroot 				k = 0;
2021214Sroot 		} while(bin[k]!='\n'&&k!=i);
2031214Sroot 	}
2041214Sroot 	if(k<i)
205*17708Sbloom 		(void)write(1,&bin[k+1],i-k-1);
2061214Sroot 	else {
207*17708Sbloom 		(void)write(1,&bin[k+1],LBIN-k-1);
208*17708Sbloom 		(void)write(1,bin,i);
2091214Sroot 	}
2101214Sroot 	fexit();
2111214Sroot errcom:
2121214Sroot 	fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n");
2131214Sroot 	exit(2);
2141214Sroot }
2151214Sroot 
2161214Sroot fexit()
2171214Sroot {	register int n;
2181214Sroot 	if (!follow || piped) exit(0);
2191214Sroot 	for (;;)
2201214Sroot 	{	sleep(1);
2211214Sroot 		while ((n = read (0, bin, BUFSIZ)) > 0)
222*17708Sbloom 			(void)write (1, bin, n);
2231214Sroot 	}
2241214Sroot }
225