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