xref: /csrg-svn/usr.bin/tail/tail.c (revision 21579)
1*21579Sdist /*
2*21579Sdist  * Copyright (c) 1980 Regents of the University of California.
3*21579Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21579Sdist  * specifies the terms and conditions for redistribution.
5*21579Sdist  */
6*21579Sdist 
717708Sbloom #ifndef lint
8*21579Sdist char copyright[] =
9*21579Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10*21579Sdist  All rights reserved.\n";
11*21579Sdist #endif not lint
12*21579Sdist 
13*21579Sdist #ifndef lint
14*21579Sdist static char sccsid[] = "@(#)tail.c	5.1 (Berkeley) 05/31/85";
15*21579Sdist #endif not lint
16*21579Sdist 
171214Sroot /* tail command
181214Sroot  *
191214Sroot  *	tail where [file]
2013537Ssam  *	where is +/-n[type]
211214Sroot  *	- means n lines before end
221214Sroot  *	+ means nth line from beginning
231214Sroot  *	type 'b' means tail n blocks, not lines
241214Sroot  *	type 'c' means tail n characters
251214Sroot  *	Type 'r' means in lines in reverse order from end
261214Sroot  *	 (for -r, default is entire buffer )
271214Sroot  *	option 'f' means loop endlessly trying to read more
281214Sroot  *		characters after the end of file, on the  assumption
291214Sroot  *		that the file is growing
301214Sroot */
311214Sroot 
321214Sroot #include	<stdio.h>
331214Sroot #include	<ctype.h>
341214Sroot #include	<sys/types.h>
351214Sroot #include	<sys/stat.h>
3617708Sbloom #include	<sys/file.h>
371214Sroot #include	<errno.h>
381214Sroot 
3916583Sralph #define LBIN 8193
4016583Sralph #undef	BUFSIZ
4116583Sralph #define	BUFSIZ	LBIN-1
421214Sroot struct	stat	statb;
431214Sroot int	follow;
441214Sroot int	piped;
451214Sroot char bin[LBIN];
461214Sroot int errno;
471214Sroot 
481214Sroot main(argc,argv)
491214Sroot char **argv;
501214Sroot {
511214Sroot 	long n,di;
521214Sroot 	register i,j,k;
531214Sroot 	char	*arg;
541214Sroot 	int partial,bylines,bkwds,fromend,lastnl;
551214Sroot 	char *p;
561214Sroot 
571214Sroot 	arg = argv[1];
581214Sroot 	if(argc<=1 || *arg!='-'&&*arg!='+') {
591214Sroot 		arg = "-10l";
601214Sroot 		argc++;
611214Sroot 		argv--;
621214Sroot 	}
631214Sroot 	fromend = *arg=='-';
641214Sroot 	arg++;
6514806Skarels 	if (isdigit(*arg)) {
6614806Skarels 		n = 0;
6714806Skarels 		while(isdigit(*arg))
6814806Skarels 			n = n*10 + *arg++ - '0';
6914806Skarels 	} else
7014806Skarels 		n = -1;
711214Sroot 	if(!fromend&&n>0)
721214Sroot 		n--;
731214Sroot 	if(argc>2) {
7417708Sbloom 		(void)close(0);
751214Sroot 		if(open(argv[2],0)!=0) {
761214Sroot 			perror(argv[2]);
771214Sroot 			exit(1);
781214Sroot 		}
791214Sroot 	}
8017708Sbloom 	(void)lseek(0,(off_t)0,L_INCR);
8112889Sralph 	piped = errno==ESPIPE;
821214Sroot 	bylines = -1; bkwds = 0;
831214Sroot 	while(*arg)
841214Sroot 	switch(*arg++) {
851214Sroot 
861214Sroot 	case 'b':
8716583Sralph 		if (n == -1) n = 1;
881214Sroot 		n <<= 9;
891214Sroot 		if(bylines!=-1) goto errcom;
901214Sroot 		bylines=0;
911214Sroot 		break;
921214Sroot 	case 'c':
931214Sroot 		if(bylines!=-1) goto errcom;
941214Sroot 		bylines=0;
951214Sroot 		break;
961214Sroot 	case 'f':
971214Sroot 		follow = 1;
981214Sroot 		break;
991214Sroot 	case 'r':
10014806Skarels 		if(n==-1) n = LBIN;
1011214Sroot 		bkwds = 1; fromend = 1; bylines = 1;
1021214Sroot 		break;
1031214Sroot 	case 'l':
1041214Sroot 		if(bylines!=-1) goto errcom;
1051214Sroot 		bylines = 1;
1061214Sroot 		break;
1071214Sroot 	default:
1081214Sroot 		goto errcom;
1091214Sroot 	}
11014806Skarels 	if (n==-1) n = 10;
1111214Sroot 	if(bylines==-1) bylines = 1;
1121214Sroot 	if(bkwds) follow=0;
1131214Sroot 	if(fromend)
1141214Sroot 		goto keep;
1151214Sroot 
1161214Sroot 			/*seek from beginning */
1171214Sroot 
1181214Sroot 	if(bylines) {
1191214Sroot 		j = 0;
1201214Sroot 		while(n-->0) {
1211214Sroot 			do {
1221214Sroot 				if(j--<=0) {
1231214Sroot 					p = bin;
1241214Sroot 					j = read(0,p,BUFSIZ);
1251214Sroot 					if(j--<=0)
1261214Sroot 						fexit();
1271214Sroot 				}
1281214Sroot 			} while(*p++ != '\n');
1291214Sroot 		}
13017708Sbloom 		(void)write(1,p,j);
1311214Sroot 	} else  if(n>0) {
1321214Sroot 		if(!piped)
13317708Sbloom 			(void)fstat(0,&statb);
1341214Sroot 		if(piped||(statb.st_mode&S_IFMT)==S_IFCHR)
1351214Sroot 			while(n>0) {
1361214Sroot 				i = n>BUFSIZ?BUFSIZ:n;
1371214Sroot 				i = read(0,bin,i);
1381214Sroot 				if(i<=0)
1391214Sroot 					fexit();
1401214Sroot 				n -= i;
1411214Sroot 			}
1421214Sroot 		else
14317708Sbloom 			(void)lseek(0,(off_t)n,L_SET);
1441214Sroot 	}
1451214Sroot copy:
1461214Sroot 	while((i=read(0,bin,BUFSIZ))>0)
14717708Sbloom 		(void)write(1,bin,i);
1481214Sroot 	fexit();
1491214Sroot 
1501214Sroot 			/*seek from end*/
1511214Sroot 
1521214Sroot keep:
1531214Sroot 	if(n <= 0)
1541214Sroot 		fexit();
1551214Sroot 	if(!piped) {
15617708Sbloom 		(void)fstat(0,&statb);
15716583Sralph 		/* If by lines, back up 1 buffer: else back up as needed */
15816583Sralph 		di = bylines?BUFSIZ:n;
1591214Sroot 		if(statb.st_size > di)
16017708Sbloom 			(void)lseek(0,(off_t)-di,L_XTND);
1611214Sroot 		if(!bylines)
1621214Sroot 			goto copy;
1631214Sroot 	}
1641214Sroot 	partial = 1;
1651214Sroot 	for(;;) {
1661214Sroot 		i = 0;
1671214Sroot 		do {
1681214Sroot 			j = read(0,&bin[i],LBIN-i);
1691214Sroot 			if(j<=0)
1701214Sroot 				goto brka;
1711214Sroot 			i += j;
1721214Sroot 		} while(i<LBIN);
1731214Sroot 		partial = 0;
1741214Sroot 	}
1751214Sroot brka:
1761214Sroot 	if(!bylines) {
1771214Sroot 		k =
1781214Sroot 		    n<=i ? i-n:
1791214Sroot 		    partial ? 0:
1801214Sroot 		    n>=LBIN ? i+1:
1811214Sroot 		    i-n+LBIN;
1821214Sroot 		k--;
1831214Sroot 	} else {
1841214Sroot 		if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){	/* force trailing newline */
1851214Sroot 			bin[i]='\n';
1861214Sroot 			if(++i>=LBIN) {i = 0; partial = 0;}
1871214Sroot 		}
1881214Sroot 		k = i;
1891214Sroot 		j = 0;
1901214Sroot 		do {
1911214Sroot 			lastnl = k;
1921214Sroot 			do {
1931214Sroot 				if(--k<0) {
1941214Sroot 					if(partial) {
19517708Sbloom 						if(bkwds)
19617708Sbloom 						    (void)write(1,bin,lastnl+1);
1971214Sroot 						goto brkb;
1981214Sroot 					}
1991214Sroot 					k = LBIN -1;
2001214Sroot 				}
2011214Sroot 			} while(bin[k]!='\n'&&k!=i);
2021214Sroot 			if(bkwds && j>0){
20317708Sbloom 				if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k);
2041214Sroot 				else {
20517708Sbloom 					(void)write(1,&bin[k+1],LBIN-k-1);
20617708Sbloom 					(void)write(1,bin,lastnl+1);
2071214Sroot 				}
2081214Sroot 			}
2091214Sroot 		} while(j++<n&&k!=i);
2101214Sroot brkb:
2111214Sroot 		if(bkwds) exit(0);
2121214Sroot 		if(k==i) do {
2131214Sroot 			if(++k>=LBIN)
2141214Sroot 				k = 0;
2151214Sroot 		} while(bin[k]!='\n'&&k!=i);
2161214Sroot 	}
2171214Sroot 	if(k<i)
21817708Sbloom 		(void)write(1,&bin[k+1],i-k-1);
2191214Sroot 	else {
22017708Sbloom 		(void)write(1,&bin[k+1],LBIN-k-1);
22117708Sbloom 		(void)write(1,bin,i);
2221214Sroot 	}
2231214Sroot 	fexit();
2241214Sroot errcom:
2251214Sroot 	fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n");
2261214Sroot 	exit(2);
2271214Sroot }
2281214Sroot 
2291214Sroot fexit()
2301214Sroot {	register int n;
2311214Sroot 	if (!follow || piped) exit(0);
2321214Sroot 	for (;;)
2331214Sroot 	{	sleep(1);
2341214Sroot 		while ((n = read (0, bin, BUFSIZ)) > 0)
23517708Sbloom 			(void)write (1, bin, n);
2361214Sroot 	}
2371214Sroot }
238