xref: /csrg-svn/usr.bin/tail/tail.c (revision 48313)
1*48313Sbostic /*-
2*48313Sbostic  * Copyright (c) 1980 The Regents of the University of California.
3*48313Sbostic  * All rights reserved.
4*48313Sbostic  *
5*48313Sbostic  * %sccs.include.proprietary.c%
621579Sdist  */
721579Sdist 
817708Sbloom #ifndef lint
921579Sdist char copyright[] =
10*48313Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
1121579Sdist  All rights reserved.\n";
12*48313Sbostic #endif /* not lint */
1321579Sdist 
1421579Sdist #ifndef lint
15*48313Sbostic static char sccsid[] = "@(#)tail.c	5.4 (Berkeley) 04/18/91";
16*48313Sbostic #endif /* not lint */
1721579Sdist 
181214Sroot /* tail command
191214Sroot  *
201214Sroot  *	tail where [file]
2113537Ssam  *	where is +/-n[type]
221214Sroot  *	- means n lines before end
231214Sroot  *	+ means nth line from beginning
241214Sroot  *	type 'b' means tail n blocks, not lines
251214Sroot  *	type 'c' means tail n characters
261214Sroot  *	Type 'r' means in lines in reverse order from end
271214Sroot  *	 (for -r, default is entire buffer )
281214Sroot  *	option 'f' means loop endlessly trying to read more
291214Sroot  *		characters after the end of file, on the  assumption
301214Sroot  *		that the file is growing
311214Sroot */
321214Sroot 
331214Sroot #include	<stdio.h>
341214Sroot #include	<ctype.h>
351214Sroot #include	<sys/types.h>
361214Sroot #include	<sys/stat.h>
3717708Sbloom #include	<sys/file.h>
381214Sroot #include	<errno.h>
391214Sroot 
4025804Slepreau #define LBIN 32769
4116583Sralph #undef	BUFSIZ
4225804Slepreau #define	BUFSIZ	8192
431214Sroot struct	stat	statb;
441214Sroot int	follow;
451214Sroot int	piped;
461214Sroot char bin[LBIN];
471214Sroot int errno;
481214Sroot 
491214Sroot main(argc,argv)
501214Sroot char **argv;
511214Sroot {
521214Sroot 	long n,di;
531214Sroot 	register i,j,k;
541214Sroot 	char	*arg;
551214Sroot 	int partial,bylines,bkwds,fromend,lastnl;
561214Sroot 	char *p;
571214Sroot 
581214Sroot 	arg = argv[1];
591214Sroot 	if(argc<=1 || *arg!='-'&&*arg!='+') {
601214Sroot 		arg = "-10l";
611214Sroot 		argc++;
621214Sroot 		argv--;
631214Sroot 	}
641214Sroot 	fromend = *arg=='-';
651214Sroot 	arg++;
6614806Skarels 	if (isdigit(*arg)) {
6714806Skarels 		n = 0;
6814806Skarels 		while(isdigit(*arg))
6914806Skarels 			n = n*10 + *arg++ - '0';
7014806Skarels 	} else
7114806Skarels 		n = -1;
721214Sroot 	if(!fromend&&n>0)
731214Sroot 		n--;
741214Sroot 	if(argc>2) {
7517708Sbloom 		(void)close(0);
761214Sroot 		if(open(argv[2],0)!=0) {
771214Sroot 			perror(argv[2]);
781214Sroot 			exit(1);
791214Sroot 		}
801214Sroot 	}
8117708Sbloom 	(void)lseek(0,(off_t)0,L_INCR);
8212889Sralph 	piped = errno==ESPIPE;
831214Sroot 	bylines = -1; bkwds = 0;
841214Sroot 	while(*arg)
851214Sroot 	switch(*arg++) {
861214Sroot 
871214Sroot 	case 'b':
8816583Sralph 		if (n == -1) n = 1;
891214Sroot 		n <<= 9;
901214Sroot 		if(bylines!=-1) goto errcom;
911214Sroot 		bylines=0;
921214Sroot 		break;
931214Sroot 	case 'c':
941214Sroot 		if(bylines!=-1) goto errcom;
951214Sroot 		bylines=0;
961214Sroot 		break;
971214Sroot 	case 'f':
981214Sroot 		follow = 1;
991214Sroot 		break;
1001214Sroot 	case 'r':
10114806Skarels 		if(n==-1) n = LBIN;
1021214Sroot 		bkwds = 1; fromend = 1; bylines = 1;
1031214Sroot 		break;
1041214Sroot 	case 'l':
1051214Sroot 		if(bylines!=-1) goto errcom;
1061214Sroot 		bylines = 1;
1071214Sroot 		break;
1081214Sroot 	default:
1091214Sroot 		goto errcom;
1101214Sroot 	}
11114806Skarels 	if (n==-1) n = 10;
1121214Sroot 	if(bylines==-1) bylines = 1;
1131214Sroot 	if(bkwds) follow=0;
1141214Sroot 	if(fromend)
1151214Sroot 		goto keep;
1161214Sroot 
1171214Sroot 			/*seek from beginning */
1181214Sroot 
1191214Sroot 	if(bylines) {
1201214Sroot 		j = 0;
1211214Sroot 		while(n-->0) {
1221214Sroot 			do {
1231214Sroot 				if(j--<=0) {
1241214Sroot 					p = bin;
1251214Sroot 					j = read(0,p,BUFSIZ);
1261214Sroot 					if(j--<=0)
1271214Sroot 						fexit();
1281214Sroot 				}
1291214Sroot 			} while(*p++ != '\n');
1301214Sroot 		}
13117708Sbloom 		(void)write(1,p,j);
1321214Sroot 	} else  if(n>0) {
1331214Sroot 		if(!piped)
13417708Sbloom 			(void)fstat(0,&statb);
1351214Sroot 		if(piped||(statb.st_mode&S_IFMT)==S_IFCHR)
1361214Sroot 			while(n>0) {
1371214Sroot 				i = n>BUFSIZ?BUFSIZ:n;
1381214Sroot 				i = read(0,bin,i);
1391214Sroot 				if(i<=0)
1401214Sroot 					fexit();
1411214Sroot 				n -= i;
1421214Sroot 			}
1431214Sroot 		else
14417708Sbloom 			(void)lseek(0,(off_t)n,L_SET);
1451214Sroot 	}
1461214Sroot copy:
1471214Sroot 	while((i=read(0,bin,BUFSIZ))>0)
14817708Sbloom 		(void)write(1,bin,i);
1491214Sroot 	fexit();
1501214Sroot 
1511214Sroot 			/*seek from end*/
1521214Sroot 
1531214Sroot keep:
1541214Sroot 	if(n <= 0)
1551214Sroot 		fexit();
1561214Sroot 	if(!piped) {
15717708Sbloom 		(void)fstat(0,&statb);
15816583Sralph 		/* If by lines, back up 1 buffer: else back up as needed */
15925804Slepreau 		di = bylines?LBIN-1:n;
1601214Sroot 		if(statb.st_size > di)
16117708Sbloom 			(void)lseek(0,(off_t)-di,L_XTND);
1621214Sroot 		if(!bylines)
1631214Sroot 			goto copy;
1641214Sroot 	}
1651214Sroot 	partial = 1;
1661214Sroot 	for(;;) {
1671214Sroot 		i = 0;
1681214Sroot 		do {
1691214Sroot 			j = read(0,&bin[i],LBIN-i);
1701214Sroot 			if(j<=0)
1711214Sroot 				goto brka;
1721214Sroot 			i += j;
1731214Sroot 		} while(i<LBIN);
1741214Sroot 		partial = 0;
1751214Sroot 	}
1761214Sroot brka:
1771214Sroot 	if(!bylines) {
1781214Sroot 		k =
1791214Sroot 		    n<=i ? i-n:
1801214Sroot 		    partial ? 0:
1811214Sroot 		    n>=LBIN ? i+1:
1821214Sroot 		    i-n+LBIN;
1831214Sroot 		k--;
1841214Sroot 	} else {
1851214Sroot 		if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){	/* force trailing newline */
1861214Sroot 			bin[i]='\n';
1871214Sroot 			if(++i>=LBIN) {i = 0; partial = 0;}
1881214Sroot 		}
1891214Sroot 		k = i;
1901214Sroot 		j = 0;
1911214Sroot 		do {
1921214Sroot 			lastnl = k;
1931214Sroot 			do {
1941214Sroot 				if(--k<0) {
1951214Sroot 					if(partial) {
19617708Sbloom 						if(bkwds)
19717708Sbloom 						    (void)write(1,bin,lastnl+1);
1981214Sroot 						goto brkb;
1991214Sroot 					}
2001214Sroot 					k = LBIN -1;
2011214Sroot 				}
2021214Sroot 			} while(bin[k]!='\n'&&k!=i);
2031214Sroot 			if(bkwds && j>0){
20417708Sbloom 				if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k);
2051214Sroot 				else {
20617708Sbloom 					(void)write(1,&bin[k+1],LBIN-k-1);
20717708Sbloom 					(void)write(1,bin,lastnl+1);
2081214Sroot 				}
2091214Sroot 			}
2101214Sroot 		} while(j++<n&&k!=i);
2111214Sroot brkb:
2121214Sroot 		if(bkwds) exit(0);
2131214Sroot 		if(k==i) do {
2141214Sroot 			if(++k>=LBIN)
2151214Sroot 				k = 0;
2161214Sroot 		} while(bin[k]!='\n'&&k!=i);
2171214Sroot 	}
2181214Sroot 	if(k<i)
21917708Sbloom 		(void)write(1,&bin[k+1],i-k-1);
2201214Sroot 	else {
22117708Sbloom 		(void)write(1,&bin[k+1],LBIN-k-1);
22217708Sbloom 		(void)write(1,bin,i);
2231214Sroot 	}
2241214Sroot 	fexit();
2251214Sroot errcom:
2261214Sroot 	fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n");
2271214Sroot 	exit(2);
2281214Sroot }
2291214Sroot 
2301214Sroot fexit()
2311214Sroot {	register int n;
2321214Sroot 	if (!follow || piped) exit(0);
2331214Sroot 	for (;;)
2341214Sroot 	{	sleep(1);
2351214Sroot 		while ((n = read (0, bin, BUFSIZ)) > 0)
23630064Skarels 			if (write (1, bin, n) < 0)
23730064Skarels 				exit(1);
2381214Sroot 	}
2391214Sroot }
240