xref: /original-bsd/old/pr/pr.c (revision 3a8172c6)
1 /*-
2  * Copyright (c) 1983 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)pr.c	4.9 (Berkeley) 04/18/91";
16 #endif /* not lint */
17 
18 /*
19  *   print file with headings
20  *  2+head+2+page[56]+5
21  */
22 
23 #include <stdio.h>
24 #include <signal.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 
28 /* Making putcp a macro sped things up by 14%. */
29 #define putcp(c)  if (page >= fpage) putchar(c)
30 
31 int	ncol	= 1;
32 char	*header;
33 int	col;
34 int	icol;
35 FILE	*file;
36 char	*bufp;
37 #define	BUFS	9000	/* at least 66 * 132 */
38 char	buffer[BUFS];	/* for multi-column output */
39 char	obuf[BUFSIZ];
40 #define	FF	014
41 int	line;
42 char	*colp[72];
43 int	nofile;
44 char	isclosed[10];
45 FILE	*ifile[10];
46 char	**lastarg;
47 int	peekc;
48 int	fpage;
49 int	page;
50 int	colw;
51 int	nspace;
52 int	width	= 72;
53 int	length	= 66;
54 int	plength = 61;
55 int	margin	= 10;
56 int	ntflg;
57 int	fflg;
58 int	mflg;
59 int	tabc;
60 char	*tty;
61 int	mode;
62 char	*ttyname();
63 char	*ctime();
64 
65 main(argc, argv)
66 char **argv;
67 {
68 	int nfdone;
69 	void onintr();
70 
71 	setbuf(stdout, obuf);
72 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
73 		signal(SIGINT, onintr);
74 	lastarg = &argv[argc-1];
75 	fixtty();
76 	for (nfdone=0; argc>1; argc--) {
77 		argv++;
78 		if (**argv == '-') {
79 			switch (*++*argv) {
80 			case 'h':		/* define page header */
81 				if (argc>=2) {
82 					header = *++argv;
83 					argc--;
84 				}
85 				continue;
86 
87 			case 't':		/* don't print page headers */
88 				ntflg++;
89 				continue;
90 
91 			case 'f':		/* use form feeds */
92 				fflg++;
93 				plength = 60;
94 				continue;
95 
96 			case 'l':		/* length of page */
97 				length = atoi(++*argv);
98 				continue;
99 
100 			case 'w':		/* width of page */
101 				width = atoi(++*argv);
102 				continue;
103 
104 			case 's':		/* col separator */
105 				if (*++*argv)
106 					tabc = **argv;
107 				else
108 					tabc = '\t';
109 				continue;
110 
111 			case 'm':		/* all files at once */
112 				mflg++;
113 				continue;
114 
115 			default:
116 				if (numeric(*argv)) {	/* # of cols */
117 					if ((ncol = atoi(*argv)) == 0) {
118 						fprintf(stderr, "can't print 0 cols, using 1 instead.\n");
119 						ncol = 1;
120 					}
121 				} else {
122 					fprintf(stderr, "pr: bad key %s\n", *argv);
123 					exit(1);
124 				}
125 				continue;
126 			}
127 		} else if (**argv == '+') {	/* start at page ++*argv */
128 			fpage = atoi(++*argv);
129 		} else {
130 			print(*argv, argv);
131 			nfdone++;
132 			if (mflg)
133 				break;
134 		}
135 	}
136 	if (nfdone==0)
137 		print((char *)0, (char **)0);
138 	done();
139 }
140 
141 done()
142 {
143 
144 	if (tty)
145 		chmod(tty, mode);
146 	exit(0);
147 }
148 
149 /* numeric -- returns 1 if str is numeric, elsewise 0 */
150 numeric(str)
151 	char	*str;
152 {
153 	for (; *str ; str++) {
154 		if (*str > '9' || *str < '0') {
155 			return(0);
156 		}
157 	}
158 	return(1);
159 }
160 
161 void
162 onintr()
163 {
164 
165 	if (tty)
166 		chmod(tty, mode);
167 	_exit(1);
168 }
169 
170 fixtty()
171 {
172 	struct stat sbuf;
173 
174 	tty = ttyname(1);
175 	if (tty == 0)
176 		return;
177 	stat(tty, &sbuf);
178 	mode = sbuf.st_mode&0777;
179 	chmod(tty, 0600);
180 }
181 
182 /* print -- print file */
183 print(fp, argp)
184 char *fp;
185 char **argp;
186 {
187 	struct stat sbuf;
188 	register sncol;
189 	register char *sheader;
190 	register char *cbuf;
191 	char linebuf[150], *cp;
192 
193 	if (ntflg)
194 		margin = 0;
195 	else
196 		margin = 10;
197 	if (length <= margin)
198 		length = 66;
199 	if (width <= 0)
200 		width = 72;
201 	if (ncol>72 || ncol>width) {
202 		fprintf(stderr, "pr: No room for columns.\n");
203 		done();
204 	}
205 	if (mflg) {
206 		mopen(argp);
207 		ncol = nofile;
208 	}
209 	colw = width/(ncol==0? 1 : ncol);
210 	sncol = ncol;
211 	sheader = header;
212 	plength = length-5;
213 	if (ntflg)
214 		plength = length;
215 	if (--ncol<0)
216 		ncol = 0;
217 	if (mflg)
218 		fp = 0;
219 	if (fp) {
220 		if((file=fopen(fp, "r"))==NULL) {
221 			if (tty==NULL)
222 				perror(fp);
223 			ncol = sncol;
224 			header = sheader;
225 			return;
226 		}
227 		stat(fp, &sbuf);
228 	} else {
229 		file = stdin;
230 		time(&sbuf.st_mtime);
231 	}
232 	if (header == 0)
233 		header = fp?fp:"";
234 	cbuf = ctime(&sbuf.st_mtime);
235 	cbuf[16] = '\0';
236 	cbuf[24] = '\0';
237 	page = 1;
238 	icol = 0;
239 	colp[ncol] = bufp = buffer;
240 	if (mflg==0)
241 		nexbuf();
242 	while (mflg&&nofile || (!mflg)&&tpgetc(ncol)>0) {
243 		if (mflg==0) {
244 			colp[ncol]--;
245 			if (colp[ncol] < buffer)
246 				colp[ncol] = &buffer[BUFS - 1];
247 		}
248 		line = 0;
249 		if (ntflg==0) {
250 			if (fflg) {
251 				/* Assume a ff takes two blank lines at the
252 				   top of the page. */
253 				line = 2;
254 				(void)sprintf(linebuf, "%s %s  %s Page %d\n\n\n",
255 					cbuf+4, cbuf+20, header, page);
256 			} else
257 				(void)sprintf(linebuf, "\n\n%s %s  %s Page %d\n\n\n",
258 					cbuf+4, cbuf+20, header, page);
259 			for(cp=linebuf;*cp;) put(*cp++);
260 		}
261 		putpage();
262 		if (ntflg==0) {
263 			if (fflg)
264 				put('\f');
265 			else
266 				while(line<length)
267 					put('\n');
268 		}
269 		page++;
270 	}
271 	fclose(file);
272 	ncol = sncol;
273 	header = sheader;
274 }
275 
276 mopen(ap)
277 char **ap;
278 {
279 	register char **p, *p1;
280 
281 	p = ap;
282 	while((p1 = *p) && p++ <= lastarg) {
283 		if((ifile[nofile]=fopen(p1, "r")) == NULL){
284 			isclosed[nofile] = 1;
285 			nofile--;
286 		}
287 		else
288 			isclosed[nofile] = 0;
289 		if(++nofile>=10) {
290 			fprintf(stderr, "pr: Too many args\n");
291 			done();
292 		}
293 	}
294 }
295 
296 putpage()
297 {
298 	register int lastcol, i, c;
299 	int j;
300 
301 	if (ncol==0) {
302 		while (line<plength) {
303 			while((c = tpgetc(0)) && c!='\n' && c!=FF)
304 				putcp(c);
305 			if (c==0) break;
306 			putcp('\n');
307 			line++;
308 			if (c==FF)
309 				break;
310 		}
311 		return;
312 	}
313 	colp[0] = colp[ncol];
314 	if (mflg==0) for (i=1; i<=ncol; i++) {
315 		colp[i] = colp[i-1];
316 		for (j = margin; j<length; j++)
317 			while((c=tpgetc(i))!='\n')
318 				if (c==0)
319 					break;
320 	}
321 	while (line<plength) {
322 		lastcol = colw;
323 		for (i=0; i<ncol; i++) {
324 			while ((c=pgetc(i)) && c!='\n')
325 				if (col<lastcol || tabc!=0)
326 					put(c);
327 			if (c==0)
328 				continue;
329 			if (tabc)
330 				put(tabc);
331 			else while (col<lastcol)
332 				put(' ');
333 			lastcol += colw;
334 		}
335 		while ((c = pgetc(ncol)) && c!='\n')
336 			put(c);
337 		put('\n');
338 	}
339 }
340 
341 nexbuf()
342 {
343 	register int n;
344 	register char *rbufp;
345 
346 	rbufp = bufp;
347 	n = &buffer[BUFS] - rbufp;
348 	if (n>512)
349 		n = 512;
350 	if((n=fread(rbufp,1,n,file)) <= 0){
351 		fclose(file);
352 		*rbufp = 0376;
353 	}
354 	else {
355 		rbufp += n;
356 		if (rbufp >= &buffer[BUFS])
357 			rbufp = buffer;
358 		*rbufp = 0375;
359 	}
360 	bufp = rbufp;
361 }
362 
363 tpgetc(ai)
364 {
365 	register char **p;
366 	register int c, i;
367 
368 	i = ai;
369 	if (mflg) {
370 		if((c=getc(ifile[i])) == EOF) {
371 			if (isclosed[i]==0) {
372 				isclosed[i] = 1;
373 				if (--nofile <= 0)
374 					return(0);
375 			}
376 			return('\n');
377 		}
378 		if (c==FF && ncol>0)
379 			c = '\n';
380 		return(c);
381 	}
382 loop:
383 	c = **(p = &colp[i]) & 0377;
384 	if (c == 0375) {
385 		nexbuf();
386 		c = **p & 0377;
387 	}
388 	if (c == 0376)
389 		return(0);
390 	(*p)++;
391 	if (*p >= &buffer[BUFS])
392 		*p = buffer;
393 	if (c==0)
394 		goto loop;
395 	return(c);
396 }
397 
398 pgetc(i)
399 {
400 	register int c;
401 
402 	if (peekc) {
403 		c = peekc;
404 		peekc = 0;
405 	} else
406 		c = tpgetc(i);
407 	if (tabc)
408 		return(c);
409 	switch (c) {
410 
411 	case '\t':
412 		icol++;
413 		if ((icol&07) != 0)
414 			peekc = '\t';
415 		return(' ');
416 
417 	case '\n':
418 		icol = 0;
419 		break;
420 
421 	case 010:
422 	case 033:
423 		icol--;
424 		break;
425 	}
426 	if (c >= ' ')
427 		icol++;
428 	return(c);
429 }
430 put(ac)
431 {
432 	register int ns, c;
433 
434 	c = ac;
435 	if (tabc) {
436 		putcp(c);
437 		if (c=='\n')
438 			line++;
439 		return;
440 	}
441 	switch (c) {
442 
443 	case ' ':
444 		nspace++;
445 		col++;
446 		return;
447 
448 	case '\n':
449 		col = 0;
450 		nspace = 0;
451 		line++;
452 		break;
453 
454 	case 010:
455 	case 033:
456 		if (--col<0)
457 			col = 0;
458 		if (--nspace<0)
459 			nspace = 0;
460 
461 	}
462 	while(nspace) {
463 		if (nspace>2 && col > (ns=((col-nspace)|07))) {
464 			nspace = col-ns-1;
465 			putcp('\t');
466 		} else {
467 			nspace--;
468 			putcp(' ');
469 		}
470 	}
471 	if (c >= ' ')
472 		col++;
473 	putcp(c);
474 }
475