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

📄 pr.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h>/* *	PR command (print files in pages and columns, with headings) *	2+head+2+page[56]+5 */#define	ISPRINT(c)	((c) >= ' ')#define ESC		'\033'#define LENGTH		66#define LINEW		72#define NUMW		5#define MARGIN		10#define DEFTAB		8#define NFILES		10#define HEAD		"%12.12s %4.4s  %s Page %d\n\n\n", date+4, date+24, head, Page#define TOLOWER(c)	(isupper(c) ? tolower(c) : c)	/* ouch! */#define cerror(S)	fprint(2, "pr: %s", S)#define STDINNAME()	nulls#define TTY		"/dev/cons", 0#define PROMPT()	fprint(2, "\a") /* BEL */#define TABS(N,C)	if((N = intopt(argv, &C)) < 0) N = DEFTAB#define ETABS		(Inpos % Etabn)#define ITABS		(Itabn > 0 && Nspace > 1 && Nspace >= (nc = Itabn - Outpos % Itabn))#define NSEPC		'\t'#define EMPTY		14	/* length of " -- empty file" */typedef	struct	Fils	Fils;typedef	struct	Colp*	Colp;typedef	struct	Err	Err;struct	Fils{	Biobuf*	f_f;	char*	f_name;	long	f_nextc;};struct	Colp{	Rune*	c_ptr;	Rune*	c_ptr0;	long	c_lno;};struct	Err{	Err*	e_nextp;	char*	e_mess;};int	Balance = 0;Biobuf	bout;Rune*	Bufend;Rune*	Buffer = 0;int	C = '\0';Colp	Colpts;int	Colw;int	Dblspace = 1;Err*	err = 0;int	error = 0;int	Etabc = '\t';int	Etabn = 0;Fils*	Files;int	Formfeed = 0;int	Fpage = 1;char*	Head = 0;int	Inpos;int	Itabc = '\t';int	Itabn = 0;Err*	Lasterr = (Err*)&err;int	Lcolpos;int	Len = LENGTH;int	Line;int	Linew = 0;long	Lnumb = 0;int	Margin = MARGIN;int	Multi = 0;int	Ncols = 1;int	Nfiles = 0;int	Nsepc = NSEPC;int	Nspace;char	nulls[] = "";int	Numw;int	Offset = 0;int	Outpos;int	Padodd;int	Page;int	Pcolpos;int	Plength;int	Sepc = 0;extern	int	atoix(char**);extern	void	balance(int);extern	void	die(char*);extern	void	errprint(void);extern	char*	ffiler(char*);extern	int	findopt(int, char**);extern	int	get(int);extern	void*	getspace(ulong);extern	int	intopt(char**, int*);extern	void	main(int, char**);extern	Biobuf*	mustopen(char*, Fils*);extern	void	nexbuf(void);extern	int	pr(char*);extern	void	put(long);extern	void	putpage(void);extern	void	putspace(void);/* * return date file was last modified */char*getdate(void){	static char *now = 0;	static Dir *sbuf;	ulong mtime;	if(Nfiles > 1 || Files->f_name == nulls) {		if(now == 0) {			mtime = time(0);			now = ctime(mtime);		}		return now;	}	mtime = 0;	sbuf = dirstat(Files->f_name);	if(sbuf){		mtime = sbuf->mtime;		free(sbuf);	}	return ctime(mtime);}char*ffiler(char *s){	return smprint("can't open %s\n", s);}voidmain(int argc, char *argv[]){	Fils fstr[NFILES];	int nfdone = 0;	Binit(&bout, 1, OWRITE);	Files = fstr;	for(argc = findopt(argc, argv); argc > 0; --argc, ++argv)		if(Multi == 'm') {			if(Nfiles >= NFILES - 1)				die("too many files");			if(mustopen(*argv, &Files[Nfiles++]) == 0)				nfdone++; /* suppress printing */		} else {			if(pr(*argv))				Bterm(Files->f_f);			nfdone++;		}	if(!nfdone)			/* no files named, use stdin */		pr(nulls);		/* on GCOS, use current file, if any */	errprint();			/* print accumulated error reports */	exits(error? "error": 0);}intfindopt(int argc, char *argv[]){	char **eargv = argv;	int eargc = 0, c;	while(--argc > 0) {		switch(c = **++argv) {		case '-':			if((c = *++*argv) == '\0')				break;		case '+':			do {				if(isdigit(c)) {					--*argv;					Ncols = atoix(argv);				} else				switch(c = TOLOWER(c)) {				case '+':					if((Fpage = atoix(argv)) < 1)						Fpage = 1;					continue;				case 'd':					Dblspace = 2;					continue;				case 'e':					TABS(Etabn, Etabc);					continue;				case 'f':					Formfeed++;					continue;				case 'h':					if(--argc > 0)						Head = argv[1];					continue;				case 'i':					TABS(Itabn, Itabc);					continue;				case 'l':					Len = atoix(argv);					continue;				case 'a':				case 'm':					Multi = c;					continue;				case 'o':					Offset = atoix(argv);					continue;				case 's':					if((Sepc = (*argv)[1]) != '\0')						++*argv;					else						Sepc = '\t';					continue;				case 't':					Margin = 0;					continue;				case 'w':					Linew = atoix(argv);					continue;				case 'n':					Lnumb++;					if((Numw = intopt(argv, &Nsepc)) <= 0)						Numw = NUMW;				case 'b':					Balance = 1;					continue;				case 'p':					Padodd = 1;					continue;				default:					die("bad option");				}			} while((c = *++*argv) != '\0');			if(Head == argv[1])				argv++;			continue;		}		*eargv++ = *argv;		eargc++;	}	if(Len == 0)		Len = LENGTH;	if(Len <= Margin)		Margin = 0;	Plength = Len - Margin/2;	if(Multi == 'm')		Ncols = eargc;	switch(Ncols) {	case 0:		Ncols = 1;	case 1:		break;	default:		if(Etabn == 0)		/* respect explicit tab specification */			Etabn = DEFTAB;	}	if(Linew == 0)		Linew = Ncols != 1 && Sepc == 0? LINEW: 512;	if(Lnumb)		Linew -= Multi == 'm'? Numw: Numw*Ncols;	if((Colw = (Linew - Ncols + 1)/Ncols) < 1)		die("width too small");	if(Ncols != 1 && Multi == 0) {		ulong buflen = ((ulong)(Plength/Dblspace + 1))*(Linew+1)*sizeof(char);		Buffer = getspace(buflen*sizeof(*Buffer));		Bufend = &Buffer[buflen];		Colpts = getspace((Ncols+1)*sizeof(*Colpts));	}	return eargc;}intintopt(char *argv[], int *optp){	int c;	if((c = (*argv)[1]) != '\0' && !isdigit(c)) {		*optp = c;		(*argv)++;	}	c = atoix(argv);	return c != 0? c: -1;}intpr(char *name){	char *date = 0, *head = 0;	if(Multi != 'm' && mustopen(name, &Files[0]) == 0)		return 0;	if(Buffer)		Bungetc(Files->f_f);	if(Lnumb)		Lnumb = 1;	for(Page = 0;; putpage()) {		if(C == -1)			break;		if(Buffer)			nexbuf();		Inpos = 0;		if(get(0) == -1)			break;		Bflush(&bout);		Page++;		if(Page >= Fpage) {			if(Margin == 0)				continue;			if(date == 0)				date = getdate();			if(head == 0)				head = Head != 0 ? Head :					Nfiles < 2? Files->f_name: nulls;			Bprint(&bout, "\n\n");			Nspace = Offset;			putspace();			Bprint(&bout, HEAD);		}	}	if(Padodd && (Page&1) == 1) {		Line = 0;		if(Formfeed)			put('\f');		else			while(Line < Len)				put('\n');	}	C = '\0';	return 1;}voidputpage(void){	int colno;	for(Line = Margin/2;; get(0)) {		for(Nspace = Offset, colno = 0, Outpos = 0; C != '\f';) {			if(Lnumb && C != -1 && (colno == 0 || Multi == 'a')) {				if(Page >= Fpage) {					putspace();					Bprint(&bout, "%*ld", Numw, Buffer?						Colpts[colno].c_lno++: Lnumb);					Outpos += Numw;					put(Nsepc);				}				Lnumb++;			}			for(Lcolpos=0, Pcolpos=0; C!='\n' && C!='\f' && C!=-1; get(colno))					put(C);			if(C==-1 || ++colno==Ncols || C=='\n' && get(colno)==-1)				break;			if(Sepc)				put(Sepc);			else				if((Nspace += Colw - Lcolpos + 1) < 1)					Nspace = 1;		}	/*		if(C == -1) {			if(Margin != 0)				break;			if(colno != 0)				put('\n');			return;		}	*/		if(C == -1 && colno == 0) {			if(Margin != 0)				break;			return;		}		if(C == '\f')			break;		put('\n');		if(Dblspace == 2 && Line < Plength)			put('\n');		if(Line >= Plength)			break;	}	if(Formfeed)		put('\f');	else		while(Line < Len)			put('\n');}voidnexbuf(void){	Rune *s = Buffer;	Colp p = Colpts;	int j, c, bline = 0;	for(;;) {		p->c_ptr0 = p->c_ptr = s;		if(p == &Colpts[Ncols])			return;		(p++)->c_lno = Lnumb + bline;		for(j = (Len - Margin)/Dblspace; --j >= 0; bline++)			for(Inpos = 0;;) {				if((c = Bgetrune(Files->f_f)) == -1) {					for(*s = -1; p <= &Colpts[Ncols]; p++)						p->c_ptr0 = p->c_ptr = s;					if(Balance)						balance(bline);					return;				}				if(ISPRINT(c))					Inpos++;				if(Inpos <= Colw || c == '\n') {					*s = c;					if(++s >= Bufend)						die("page-buffer overflow");				}				if(c == '\n')					break;				switch(c) {				case '\b':					if(Inpos == 0)						s--;				case ESC:					if(Inpos > 0)						Inpos--;				}			}	}}/* * line balancing for last page */voidbalance(int bline){	Rune *s = Buffer;	Colp p = Colpts;	int colno = 0, j, c, l;	c = bline % Ncols;	l = (bline + Ncols - 1)/Ncols;	bline = 0;	do {		for(j = 0; j < l; ++j)			while(*s++ != '\n')				;		(++p)->c_lno = Lnumb + (bline += l);		p->c_ptr0 = p->c_ptr = s;		if(++colno == c)			l--;	} while(colno < Ncols - 1);}intget(int colno){	static int peekc = 0;	Colp p;	Fils *q;	long c;	if(peekc) {		peekc = 0;		c = Etabc;	} else	if(Buffer) {		p = &Colpts[colno];		if(p->c_ptr >= (p+1)->c_ptr0)			c = -1;		else			if((c = *p->c_ptr) != -1)				p->c_ptr++;	} else	if((c = (q = &Files[Multi == 'a'? 0: colno])->f_nextc) == -1) {		for(q = &Files[Nfiles]; --q >= Files && q->f_nextc == -1;)			;		if(q >= Files)			c = '\n';	} else		q->f_nextc = Bgetrune(q->f_f);	if(Etabn != 0 && c == Etabc) {		Inpos++;		peekc = ETABS;		c = ' ';	} else	if(ISPRINT(c))		Inpos++;	else		switch(c) {		case '\b':		case ESC:			if(Inpos > 0)				Inpos--;			break;		case '\f':			if(Ncols == 1)				break;			c = '\n';		case '\n':		case '\r':			Inpos = 0;		}	return C = c;}voidput(long c){	int move;	switch(c) {	case ' ':		Nspace++;		Lcolpos++;		return;	case '\b':		if(Lcolpos == 0)			return;		if(Nspace > 0) {			Nspace--;			Lcolpos--;			return;		}		if(Lcolpos > Pcolpos) {			Lcolpos--;			return;		}	case ESC:		move = -1;		break;	case '\n':		Line++;	case '\r':	case '\f':		Pcolpos = 0;		Lcolpos = 0;		Nspace = 0;		Outpos = 0;	default:		move = (ISPRINT(c) != 0);	}	if(Page < Fpage)		return;	if(Lcolpos > 0 || move > 0)		Lcolpos += move;	if(Lcolpos <= Colw) {		putspace();		Bputrune(&bout, c);		Pcolpos = Lcolpos;		Outpos += move;	}}voidputspace(void){	int nc;	for(; Nspace > 0; Outpos += nc, Nspace -= nc)		if(ITABS)			Bputc(&bout, Itabc);		else {			nc = 1;			Bputc(&bout, ' ');		}}intatoix(char **p){	int n = 0, c;	while(isdigit(c = *++*p))		n = 10*n + c - '0';	(*p)--;	return n;}/* * Defer message about failure to open file to prevent messing up * alignment of page with tear perforations or form markers. * Treat empty file as special case and report as diagnostic. */Biobuf*mustopen(char *s, Fils *f){	char *tmp;	if(*s == '\0') {		f->f_name = STDINNAME();		f->f_f = malloc(sizeof(Biobuf));		if(f->f_f == 0)			cerror("no memory");		Binit(f->f_f, 0, OREAD);	} else	if((f->f_f = Bopen(f->f_name = s, OREAD)) == 0) {		tmp = ffiler(f->f_name);		s = strcpy((char*)getspace(strlen(tmp) + 1), tmp);		free(tmp);	}	if(f->f_f != 0) {		if((f->f_nextc = Bgetrune(f->f_f)) >= 0 || Multi == 'm')			return f->f_f;		sprint(s = (char*)getspace(strlen(f->f_name) + 1 + EMPTY),			"%s -- empty file\n", f->f_name);		Bterm(f->f_f);	}	error = 1;	cerror(s);	fprint(2, "\n");	return 0;}void*getspace(ulong n){	void *t;	if((t = malloc(n)) == 0)		die("out of space");	return t;}voiddie(char *s){	error++;	errprint();	cerror(s);	Bputc(&bout, '\n');	exits("error");}/*voidonintr(void){	error++;	errprint();	exits("error");}/**//* * print accumulated error reports */voiderrprint(void){	Bflush(&bout);	for(; err != 0; err = err->e_nextp) {		cerror(err->e_mess);		fprint(2, "\n");	}}

⌨️ 快捷键说明

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