xref: /original-bsd/old/pr/pr.c (revision a910c8b7)
1 static char *sccsid = "@(#)pr.c	4.5 (Berkeley) 12/12/84";
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 	extern char *sprintf();
172 	struct stat sbuf;
173 	register sncol;
174 	register char *sheader;
175 	register char *cbuf;
176 	char linebuf[150], *cp;
177 
178 	if (ntflg)
179 		margin = 0;
180 	else
181 		margin = 10;
182 	if (length <= margin)
183 		length = 66;
184 	if (width <= 0)
185 		width = 72;
186 	if (ncol>72 || ncol>width) {
187 		fprintf(stderr, "pr: No room for columns.\n");
188 		done();
189 	}
190 	if (mflg) {
191 		mopen(argp);
192 		ncol = nofile;
193 	}
194 	colw = width/(ncol==0? 1 : ncol);
195 	sncol = ncol;
196 	sheader = header;
197 	plength = length-5;
198 	if (ntflg)
199 		plength = length;
200 	if (--ncol<0)
201 		ncol = 0;
202 	if (mflg)
203 		fp = 0;
204 	if (fp) {
205 		if((file=fopen(fp, "r"))==NULL) {
206 			if (tty==NULL)
207 				perror(fp);
208 			ncol = sncol;
209 			header = sheader;
210 			return;
211 		}
212 		stat(fp, &sbuf);
213 	} else {
214 		file = stdin;
215 		time(&sbuf.st_mtime);
216 	}
217 	if (header == 0)
218 		header = fp?fp:"";
219 	cbuf = ctime(&sbuf.st_mtime);
220 	cbuf[16] = '\0';
221 	cbuf[24] = '\0';
222 	page = 1;
223 	icol = 0;
224 	colp[ncol] = bufp = buffer;
225 	if (mflg==0)
226 		nexbuf();
227 	while (mflg&&nofile || (!mflg)&&tpgetc(ncol)>0) {
228 		if (mflg==0) {
229 			colp[ncol]--;
230 			if (colp[ncol] < buffer)
231 				colp[ncol] = &buffer[BUFS];
232 		}
233 		line = 0;
234 		if (ntflg==0) {
235 			if (fflg) {
236 				/* Assume a ff takes two blank lines at the
237 				   top of the page. */
238 				line = 2;
239 				sprintf(linebuf, "%s %s  %s Page %d\n\n\n",
240 					cbuf+4, cbuf+20, header, page);
241 			} else
242 				sprintf(linebuf, "\n\n%s %s  %s Page %d\n\n\n",
243 					cbuf+4, cbuf+20, header, page);
244 			for(cp=linebuf;*cp;) put(*cp++);
245 		}
246 		putpage();
247 		if (ntflg==0) {
248 			if (fflg)
249 				put('\f');
250 			else
251 				while(line<length)
252 					put('\n');
253 		}
254 		page++;
255 	}
256 	fclose(file);
257 	ncol = sncol;
258 	header = sheader;
259 }
260 
261 mopen(ap)
262 char **ap;
263 {
264 	register char **p, *p1;
265 
266 	p = ap;
267 	while((p1 = *p) && p++ <= lastarg) {
268 		if((ifile[nofile]=fopen(p1, "r")) == NULL){
269 			isclosed[nofile] = 1;
270 			nofile--;
271 		}
272 		else
273 			isclosed[nofile] = 0;
274 		if(++nofile>=10) {
275 			fprintf(stderr, "pr: Too many args\n");
276 			done();
277 		}
278 	}
279 }
280 
281 putpage()
282 {
283 	register int lastcol, i, c;
284 	int j;
285 
286 	if (ncol==0) {
287 		while (line<plength) {
288 			while((c = tpgetc(0)) && c!='\n' && c!=FF)
289 				putcp(c);
290 			if (c==0) break;
291 			putcp('\n');
292 			line++;
293 			if (c==FF)
294 				break;
295 		}
296 		return;
297 	}
298 	colp[0] = colp[ncol];
299 	if (mflg==0) for (i=1; i<=ncol; i++) {
300 		colp[i] = colp[i-1];
301 		for (j = margin; j<length; j++)
302 			while((c=tpgetc(i))!='\n')
303 				if (c==0)
304 					break;
305 	}
306 	while (line<plength) {
307 		lastcol = colw;
308 		for (i=0; i<ncol; i++) {
309 			while ((c=pgetc(i)) && c!='\n')
310 				if (col<lastcol || tabc!=0)
311 					put(c);
312 			if (c==0)
313 				continue;
314 			if (tabc)
315 				put(tabc);
316 			else while (col<lastcol)
317 				put(' ');
318 			lastcol += colw;
319 		}
320 		while ((c = pgetc(ncol)) && c!='\n')
321 			put(c);
322 		put('\n');
323 	}
324 }
325 
326 nexbuf()
327 {
328 	register int n;
329 	register char *rbufp;
330 
331 	rbufp = bufp;
332 	n = &buffer[BUFS] - rbufp;
333 	if (n>512)
334 		n = 512;
335 	if((n=fread(rbufp,1,n,file)) <= 0){
336 		fclose(file);
337 		*rbufp = 0376;
338 	}
339 	else {
340 		rbufp += n;
341 		if (rbufp >= &buffer[BUFS])
342 			rbufp = buffer;
343 		*rbufp = 0375;
344 	}
345 	bufp = rbufp;
346 }
347 
348 tpgetc(ai)
349 {
350 	register char **p;
351 	register int c, i;
352 
353 	i = ai;
354 	if (mflg) {
355 		if((c=getc(ifile[i])) == EOF) {
356 			if (isclosed[i]==0) {
357 				isclosed[i] = 1;
358 				if (--nofile <= 0)
359 					return(0);
360 			}
361 			return('\n');
362 		}
363 		if (c==FF && ncol>0)
364 			c = '\n';
365 		return(c);
366 	}
367 loop:
368 	c = **(p = &colp[i]) & 0377;
369 	if (c == 0375) {
370 		nexbuf();
371 		c = **p & 0377;
372 	}
373 	if (c == 0376)
374 		return(0);
375 	(*p)++;
376 	if (*p >= &buffer[BUFS])
377 		*p = buffer;
378 	if (c==0)
379 		goto loop;
380 	return(c);
381 }
382 
383 pgetc(i)
384 {
385 	register int c;
386 
387 	if (peekc) {
388 		c = peekc;
389 		peekc = 0;
390 	} else
391 		c = tpgetc(i);
392 	if (tabc)
393 		return(c);
394 	switch (c) {
395 
396 	case '\t':
397 		icol++;
398 		if ((icol&07) != 0)
399 			peekc = '\t';
400 		return(' ');
401 
402 	case '\n':
403 		icol = 0;
404 		break;
405 
406 	case 010:
407 	case 033:
408 		icol--;
409 		break;
410 	}
411 	if (c >= ' ')
412 		icol++;
413 	return(c);
414 }
415 put(ac)
416 {
417 	register int ns, c;
418 
419 	c = ac;
420 	if (tabc) {
421 		putcp(c);
422 		if (c=='\n')
423 			line++;
424 		return;
425 	}
426 	switch (c) {
427 
428 	case ' ':
429 		nspace++;
430 		col++;
431 		return;
432 
433 	case '\n':
434 		col = 0;
435 		nspace = 0;
436 		line++;
437 		break;
438 
439 	case 010:
440 	case 033:
441 		if (--col<0)
442 			col = 0;
443 		if (--nspace<0)
444 			nspace = 0;
445 
446 	}
447 	while(nspace) {
448 		if (nspace>2 && col > (ns=((col-nspace)|07))) {
449 			nspace = col-ns-1;
450 			putcp('\t');
451 		} else {
452 			nspace--;
453 			putcp(' ');
454 		}
455 	}
456 	if (c >= ' ')
457 		col++;
458 	putcp(c);
459 }
460