⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tail.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include	<u.h>#include	<libc.h>#include	<ctype.h>#include	<bio.h>/* * tail command, posix plus v10 option -r. * the simple command tail -c, legal in v10, is illegal */long	count;int	anycount;int	follow;int	file	= 0;char*	umsg	= "usage: tail [-n N] [-c N] [-f] [-r] [+-N[bc][fr]] [file]";Biobuf	bout;enum{	BEG,	END} origin = END;enum{	CHARS,	LINES} units = LINES;enum{	FWD,	REV} dir = FWD;extern	void	copy(void);extern	void	fatal(char*);extern	int	getnumber(char*);extern	void	keep(void);extern	void	reverse(void);extern	void	skip(void);extern	void	suffix(char*);extern	long	tread(char*, long);extern	void	trunc(Dir*, Dir**);extern	vlong	tseek(vlong, int);extern	void	twrite(char*, long);extern	void	usage(void);static	int	isseekable(int fd);#define JUMP(o,p) tseek(o,p), copy()voidmain(int argc, char **argv){	int seekable, c;	Binit(&bout, 1, OWRITE);	for(; argc > 1 && ((c=*argv[1])=='-'||c=='+'); argc--,argv++ ) {		if(getnumber(argv[1])) {			suffix(argv[1]);			continue;		} else		if(c == '-')			switch(argv[1][1]) {			case 'c':				units = CHARS;			case 'n':				if(getnumber(argv[1]+2))					continue;				else				if(argc > 2 && getnumber(argv[2])) {					argc--, argv++;					continue;				} else					usage();			case 'r':				dir = REV;				continue;			case 'f':				follow++;				continue;			case '-':				argc--, argv++;			}		break;	}	if(dir==REV && (units==CHARS || follow || origin==BEG))		fatal("incompatible options");	if(!anycount)		count = dir==REV? ~0UL>>1: 10;	if(origin==BEG && units==LINES && count>0)		count--;	if(argc > 2)		usage();	if(argc > 1 && (file=open(argv[1],0)) < 0)		fatal(argv[1]);	seekable = isseekable(file);	if(!seekable && origin==END)		keep();	else	if(!seekable && origin==BEG)		skip();	else	if(units==CHARS && origin==END)		JUMP(-count, 2);	else	if(units==CHARS && origin==BEG)		JUMP(count, 0);	else	if(units==LINES && origin==END)		reverse();	else	if(units==LINES && origin==BEG)		skip();	if(follow && seekable)		for(;;) {			static Dir *sb0, *sb1;			trunc(sb1, &sb0);			copy();			trunc(sb0, &sb1);			sleep(5000);		}	exits(0);}voidtrunc(Dir *old, Dir **new){	Dir *d;	vlong olength;	d = dirfstat(file);	if(d == nil)		return;	olength = 0;	if(old)		olength = old->length;	if(d->length < olength)		d->length = tseek(0LL, 0);	free(*new);	*new = d;}voidsuffix(char *s){	while(*s && strchr("0123456789+-", *s))		s++;	switch(*s) {	case 'b':		if((count *= 1024) < 0)			fatal("too big");	case 'c':		units = CHARS;	case 'l':		s++;	}	switch(*s) {	case 'r':		dir = REV;		return;	case 'f':		follow++;		return;	case 0:		return;	}	usage();}/* * read past head of the file to find tail */voidskip(void){	int i;	long n;	char buf[Bsize];	if(units == CHARS) {		for( ; count>0; count -=n) {			n = count<Bsize? count: Bsize;			if(!(n = tread(buf, n)))				return;		}	} else /*units == LINES*/ {		n = i = 0;		while(count > 0) {			if(!(n = tread(buf, Bsize)))				return;			for(i=0; i<n && count>0; i++)				if(buf[i]=='\n')					count--;		}		twrite(buf+i, n-i);	}	copy();}voidcopy(void){	long n;	char buf[Bsize];	while((n=tread(buf, Bsize)) > 0) {		twrite(buf, n);		Bflush(&bout);	/* for FWD on pipe; else harmless */	}}/* * read whole file, keeping the tail *	complexity is length(file)*length(tail). *	could be linear. */voidkeep(void){	int len = 0;	long bufsiz = 0;	char *buf = 0;	int j, k, n;	for(n=1; n;) {		if(len+Bsize > bufsiz) {			bufsiz += 2*Bsize;			if(!(buf = realloc(buf, bufsiz+1)))				fatal("out of space");		}		for(; n && len<bufsiz; len+=n)			n = tread(buf+len, bufsiz-len);		if(count >= len)			continue;		if(units == CHARS)			j = len - count;		else {			/* units == LINES */			j = buf[len-1]=='\n'? len-1: len;			for(k=0; j>0; j--)				if(buf[j-1] == '\n')					if(++k >= count)						break;		}		memmove(buf, buf+j, len-=j);	}	if(dir == REV) {		if(len>0 && buf[len-1]!='\n')			buf[len++] = '\n';		for(j=len-1 ; j>0; j--)			if(buf[j-1] == '\n') {				twrite(buf+j, len-j);				if(--count <= 0)					return;				len = j;			}	}	if(count > 0)		twrite(buf, len);}/* * count backward and print tail of file */voidreverse(void){	int first;	long len = 0;	long n = 0;	long bufsiz = 0;	char *buf = 0;	vlong pos = tseek(0LL, 2);	for(first=1; pos>0 && count>0; first=0) {		n = pos>Bsize? Bsize: (long)pos;		pos -= n;		if(len+n > bufsiz) {			bufsiz += 2*Bsize;			if(!(buf = realloc(buf, bufsiz+1)))				fatal("out of space");		}		memmove(buf+n, buf, len);		len += n;		tseek(pos, 0);		if(tread(buf, n) != n)			fatal("length error");		if(first && buf[len-1]!='\n')			buf[len++] = '\n';		for(n=len-1 ; n>0 && count>0; n--)			if(buf[n-1] == '\n') {				count--;				if(dir == REV)					twrite(buf+n, len-n);				len = n;			}	}	if(dir == FWD) {		if(n)			tseek(pos+n+1, 0);		else			tseek(0, 0);		copy();	} else	if(count > 0)		twrite(buf, len);}vlongtseek(vlong o, int p){	o = seek(file, o, p);	if(o == -1)		fatal("");	return o;}longtread(char *buf, long n){	int r = read(file, buf, n);	if(r == -1)		fatal("");	return r;}voidtwrite(char *s, long n){	if(Bwrite(&bout, s, n) != n)		fatal("");}intgetnumber(char *s){	if(*s=='-' || *s=='+')		s++;	if(!isdigit(*s))		return 0;	if(s[-1] == '+')		origin = BEG;	if(anycount++)		fatal("excess option");	count = atol(s);	/* check range of count */	if(count < 0 ||	(int)count != count)		fatal("too big");	return 1;}	void		fatal(char *s){	char buf[ERRMAX];	errstr(buf, sizeof buf);	fprint(2, "tail: %s: %s\n", s, buf);	exits(s);}voidusage(void){	fprint(2, "%s\n", umsg);	exits("usage");}/* return true if seeks work and if the file is > 0 length. * this will eventually bite me in the ass if seeking a file * is not conservative. - presotto */static intisseekable(int fd){		vlong m;	m = seek(fd, 0, 1);	if(m < 0)		return 0;	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -