pr.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 604 行

C
604
字号
#ifndef lintstatic	char *sccsid = "@(#)pr.c	4.1	(ULTRIX)	7/17/90";#endif lint/********************************************************************* *			Copyright (c) 1988 by *		Digital Equipment Corporation, Maynard, MA *			All rights reserved. *								 *	This software is furnished under a license and may be used and *	copied  only  in accordance with the terms of such license and *	with the  inclusion  of  the  above  copyright  notice.   This *	software  or  any  other copies thereof may not be provided or *	otherwise made available to any other person.  No title to and *	ownership of the software is hereby transferred.		 *								 *	This software is  derived  from  software  received  from  the *	University    of   California,   Berkeley,   and   from   Bell *	Laboratories.  Use, duplication, or disclosure is  subject  to *	restrictions  under  license  agreements  with  University  of *	California and with AT&T.					 *								 *	The information in this software is subject to change  without *	notice  and should not be construed as a commitment by Digital *	Equipment Corporation.					 *								 *	Digital assumes no responsibility for the use  or  reliability *	of its software on equipment which is not supplied by Digital. ********************************************************************//******************************************************************** * * Modification History * * 11-Sep-88    David Gray (gray) *              Made sure "move" always had a value, problem occurred *              when tabs were encountered and neither the -i or -e *              option were specified, therefore set move = 8, DJG#3 *              Problem exposed due to previous fix. * * 16-Aug-88    Dave Gray (gray) *              1) Added "continue" statement after 'n' & 'x' options, *                 prevents the automatic inclusion of the 'b' option. *              2) Fixed -w option, previously had no effect on output. * *              Fixes labeled DJG#1 and DJG#2, respectively * * * 08-Jun-88	Mark Parenti (map) * *		Changed signal handlers to void. * * 11-Feb-88    David Gray (gray) * *              added -b option which prints blank headers * *******************************************************************/#include <stdio.h>/* *	PR command (print files in pages and columns, with headings) *	2+head+2+page[56]+5 */#define ESC	'\033'#define LENGTH	66#define LINEW	72#define NUMW	5#define MARGIN	10#define DEFTAB	8FILE *fopen(), *mustopen();char nulls[] = "";typedef struct { FILE *f_f; char *f_name; int f_nextc; } FILS;FILS *Files;int Multi = 0, Nfiles = 0, Error = 0;void  onintr();#include <signal.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>typedef char CHAR;typedef int ANY;typedef unsigned UNS;#define NFILES	10int Mode;char *ttyname(), *Ttyout, obuf[BUFSIZ];#define istty(F)	ttyname(fileno(F))/* ARGSUSED */fixtty(argc, argv) char **argv;{	struct stat sbuf;	setbuf(stdout, obuf);	if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr);	if (Ttyout= istty(stdout)) {		stat(Ttyout, &sbuf);		Mode = sbuf.st_mode&0777;		chmod(Ttyout, 0600);	}	return (argc);}#define done()	if (Ttyout) chmod(Ttyout, Mode)#define INTREXIT	_exitchar *GETDATE() /* return date file was last modified */{	char *ctime();	static char *now = NULL;	static struct stat sbuf, nbuf;	if (Nfiles > 1 || Files->f_name == nulls) {		if (now == NULL)			{ time(&nbuf.st_mtime); now = ctime(&nbuf.st_mtime); }		return (now);	} else {		stat(Files->f_name, &sbuf);		return (ctime(&sbuf.st_mtime));	}}#define CADDID()#define NOHEAD	"\n\n\n"#define HEAD	"%12.12s %4.4s  %s Page %d\n\n\n", date+4, date+20, head, Page#define TOLOWER(c)	(isupper(c) ? tolower(c) : c)	/* ouch! */#define cerror(S)	fprintf(stderr, "pr: %s", S)char *ffiler(s) char *s;{	static char buf[100];	sprintf(buf, "can't open %s", s);	return (buf);}#define STDINNAME()	nulls#define TTY	"/dev/tty", "r"#define PROMPT()	putc('\7', stderr) /* BEL */#define NOFILE	nulls#define TABS(N,C)	if ((N = intopt(argv, &C)) < 0) N = DEFTAB#define ETABS	(Inpos % Etabn)#define ITABS	(Itabn > 0 && Nspace >= (nc = Itabn - Outpos % Itabn))#define NSEPC	'\t'ANY *getspace();main(argc, argv) char *argv[];{	FILS fstr[NFILES];	int nfdone = 0;	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++]) == NULL)				++nfdone; /* suppress printing */		} else {			if (print(*argv))				fclose(Files->f_f);			++nfdone;		}	if (!nfdone) /* no files named, use stdin */		print(NOFILE); /* on GCOS, use current file, if any */	errprint(); /* print accumulated error reports */	exit(Error);}long Lnumb = 0;FILE *Ttyin = stdin;int Dblspace = 1, Fpage = 1, Formfeed = 0,	Length = LENGTH, Linew = 0, Offset = 0, Ncols = 1, Pause = 0, Sepc = 0,	Colw, Plength, Margin = MARGIN, Numw, Nsepc = NSEPC, Report = 1,	Etabn = 0, Etabc = '\t', Itabn = 0, Itabc = '\t', nhdr = 0;char *Head = NULL;CHAR *Buffer = NULL, *Bufend;typedef struct { CHAR *c_ptr, *c_ptr0; long c_lno; } *COLP;COLP Colpts;findopt(argc, argv) char *argv[];{	char **eargv = argv;	int eargc = 0, c;	argc = fixtty(argc, argv);	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': Length = atoix(argv); continue;				case 'a':				case 'm': Multi = c; continue;				case 'o': Offset = atoix(argv); continue;				case 'p': ++Pause; continue;				case 'r': Report = 0; 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':				case 'x': /* retained for historical reasons */					++Lnumb;					if ((Numw = intopt(argv, &Nsepc)) <= 0)						Numw = NUMW;					continue;   /*DJG#1*/				case 'b': nhdr++; continue;				case 'q': /* retained for historical reasons */				case 'j': /* ignore GCOS jprint option */					continue;				default : die("bad option");				}			} while ((c = *++*argv) != '\0');			if (Head == argv[1]) ++argv;			continue;		}		*eargv++ = *argv;		++eargc;	}	if (Length == 0) Length = LENGTH;	if (Length <= Margin) Margin = 0;	Plength = Length - 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 (Itabn == 0)			Itabn = DEFTAB;	}	if (Linew == 0) Linew = Ncols != 1 && Sepc == 0 ? LINEW : 512;	if (Lnumb) {		int numw;		if (Nsepc == '\t') {			if(Itabn == 0)					numw = Numw + DEFTAB - (Numw % DEFTAB);			else					numw = Numw + Itabn - (Numw % Itabn);		}else {				numw = Numw + ((isprint(Nsepc)) ? 1 : 0);		}		Linew -= (Multi == 'm') ? numw : numw * Ncols;	}	if ((Colw = (Linew - Ncols + 1)/Ncols) < 1)		die("width too small");	if (Ncols != 1 && Multi == 0) {		UNS buflen = ((UNS)(Plength/Dblspace + 1))*(Linew+1)*sizeof(CHAR);		Buffer = (CHAR *)getspace(buflen);		Bufend = &Buffer[buflen];		Colpts = (COLP)getspace((UNS)((Ncols+1)*sizeof(*Colpts)));	}	if (Ttyout && (Pause || Formfeed) && !istty(stdin))		Ttyin = fopen(TTY);	return (eargc);}intopt(argv, optp) char *argv[]; int *optp;{	int c;	if ((c = (*argv)[1]) != '\0' && !isdigit(c)) { *optp = c; ++*argv; }	return ((c = atoix(argv)) != 0 ? c : -1);}int Page, C = '\0', Nspace, Inpos;print(name) char *name;{	static int notfirst = 0;	char *date = NULL, *head = NULL;	int c;	if (Multi != 'm' && mustopen(name, &Files[0]) == NULL) return (0);	if (Buffer) ungetc(Files->f_nextc, Files->f_f);	if (Lnumb) Lnumb = 1;	for (Page = 0; ; putpage()) {		if (C == EOF) break;		if (Buffer) nexbuf();		Inpos = 0;		if (get(0) == EOF) break;		fflush(stdout);		if (++Page >= Fpage) {			if (Ttyout && (Pause || Formfeed && !notfirst++)) {				PROMPT(); /* prompt with bell and pause */				while ((c = getc(Ttyin)) != EOF && c != '\n') ;			}			if (Margin == 0) continue;			CADDID();			if (date == NULL) date = GETDATE();			if (head == NULL) head = Head != NULL ? Head :				Nfiles < 2 ? Files->f_name : nulls;			printf("\n\n");			Nspace = Offset;			putspace();			if (nhdr)				printf(NOHEAD);			else				printf(HEAD);		}	}	C = '\0';	return (1);}int Outpos, Lcolpos, Pcolpos, Line;putpage(){	register int colno;	for (Line = Margin/2; ; get(0)) {		for (Nspace = Offset, colno = 0, Outpos = 0; C != '\f'; ) {			if (Lnumb && C != EOF && ((colno == 0 && Multi == 'm') || Multi != 'm')) {				if (Page >= Fpage) {					putspace();					printf("%*ld%c", Numw, Buffer ?						Colpts[colno].c_lno++ : Lnumb, Nsepc);				}				++Lnumb;			}			for (Lcolpos = 0, Pcolpos = 0;				C != '\n' && C != '\f' && C != EOF; get(colno))					put(C);			if (C == EOF || ++colno == Ncols ||				C == '\n' && get(colno) == EOF) break;			if (Sepc) put(Sepc);			else if ((Nspace += Colw - Lcolpos + 1) < 1) Nspace = 1;		}		if (C == EOF) {			if (Margin != 0) break;			if (colno != 0) put('\n');			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 < Length) put('\n');}nexbuf(){	register CHAR *s = Buffer;	register 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 = (Length - Margin)/Dblspace; --j >= 0; ++bline)			for (Inpos = 0; ; ) {				if ((c = getc(Files->f_f)) == EOF) {					for (*s = EOF; p <= &Colpts[Ncols]; ++p)						p->c_ptr0 = p->c_ptr = s;					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;				}			}	}}balance(bline) /* line balancing for last page */{	register CHAR *s = Buffer;	register 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);}get(colno){	static int peekc = 0;	register COLP p;	register FILS *q;	register int c;	if (peekc)		{ peekc = 0; c = Etabc; }	else if (Buffer) {		p = &Colpts[colno];		if (p->c_ptr >= (p+1)->c_ptr0) c = EOF;		else if ((c = *p->c_ptr) != EOF) ++p->c_ptr;	} else if ((c = 		(q = &Files[Multi == 'a' ? 0 : colno])->f_nextc) == EOF) {		for (q = &Files[Nfiles]; --q >= Files && q->f_nextc == EOF; ) ;		if (q >= Files) c = '\n';	} else		q->f_nextc = getc(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);}put(c){	int move = 0;	switch (c) {	case ' ':		if(Ncols < 2 || Lcolpos < Colw) {			++Nspace;			++Lcolpos;		}		return;	case '\t':		if(Itabn == 0) {			move = DEFTAB; /*DJG#3*/			break;		}		if(Lcolpos < Colw) {			move = Itabn - ((Lcolpos + Itabn) % Itabn);			move = (move < Colw-Lcolpos) ? move : Colw-Lcolpos;			Nspace += move;			Lcolpos += move;		}		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;	putspace();	if (Ncols < 2 || Lcolpos <= Colw) {		if (Outpos < Linew) {      /*DJG#2*/			putchar(c);		}		Outpos += move;		Pcolpos = Lcolpos;	}}putspace(){	int nc;	for ( ; Nspace > 0; Outpos += nc, Nspace -= nc)		if (Outpos < Linew) {      /*DJG#2*/			if (ITABS)				putchar(Itabc);			else {				nc = 1;				putchar(' ');			}		}}atoix(p) register char **p;{	register 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.*/#define EMPTY	14	/* length of " -- empty file" */typedef struct err { struct err *e_nextp; char *e_mess; } ERR;ERR *Err = NULL, *Lasterr = (ERR *)&Err;FILE *mustopen(s, f) char *s; register FILS *f;{	if (*s == '\0') {		f->f_name = STDINNAME();		f->f_f = stdin;	} else if ((f->f_f = fopen(f->f_name = s, "r")) == NULL) {		char *strcpy();		s = ffiler(f->f_name);		s = strcpy((char *)getspace((UNS)(strlen(s) + 1)), s);	}	if (f->f_f != NULL) {		if ((f->f_nextc = getc(f->f_f)) != EOF || Multi == 'm')			return (f->f_f);		sprintf(s = (char *)getspace((UNS)(strlen(f->f_name) + 1 + EMPTY)),			"%s -- empty file", f->f_name);		fclose(f->f_f);	}	Error = 1;	if (Report)		if (Ttyout) { /* accumulate error reports */			Lasterr = Lasterr->e_nextp = (ERR *)getspace((UNS)sizeof(ERR));			Lasterr->e_nextp = NULL;			Lasterr->e_mess = s;		} else { /* ok to print error report now */			cerror(s);			putc('\n', stderr);		}	return ((FILE *)NULL);}ANY *getspace(n) UNS n;{	ANY *t;	if ((t = (ANY *)malloc(n)) == NULL) die("out of space");	return (t);}die(s) char *s;{	++Error;	errprint();	cerror(s);	putc('\n', stderr);	exit(1);}voidonintr(){	++Error;	errprint();	INTREXIT(1);}errprint() /* print accumulated error reports */{	fflush(stdout);	for ( ; Err != NULL; Err = Err->e_nextp) {		cerror(Err->e_mess);		putc('\n', stderr);	}	done();}

⌨️ 快捷键说明

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