xref: /netbsd-src/usr.sbin/lpr/filters/lpf.c (revision fbffadb9f864c0324fb295860ab0faeb187269cc)
1*fbffadb9Smrg /*	$NetBSD: lpf.c,v 1.15 2019/02/03 03:19:30 mrg Exp $	*/
261f28255Scgd /*
3f881d1d4Scgd  * Copyright (c) 1983, 1993
4f881d1d4Scgd  *	The Regents of the University of California.  All rights reserved.
561f28255Scgd  *
661f28255Scgd  * Redistribution and use in source and binary forms, with or without
761f28255Scgd  * modification, are permitted provided that the following conditions
861f28255Scgd  * are met:
961f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1061f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1161f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1261f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1361f28255Scgd  *    documentation and/or other materials provided with the distribution.
14326b2259Sagc  * 3. Neither the name of the University nor the names of its contributors
1561f28255Scgd  *    may be used to endorse or promote products derived from this software
1661f28255Scgd  *    without specific prior written permission.
1761f28255Scgd  *
1861f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1961f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2061f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2161f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2261f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2361f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2461f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2561f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2661f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2761f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2861f28255Scgd  * SUCH DAMAGE.
2961f28255Scgd  */
3061f28255Scgd 
31fe7ed7ceSmrg #include <sys/cdefs.h>
3261f28255Scgd #ifndef lint
339c194566Slukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
349c194566Slukem  The Regents of the University of California.  All rights reserved.");
354a711f6dSmikel #if 0
36f881d1d4Scgd static char sccsid[] = "@(#)lpf.c	8.1 (Berkeley) 6/6/93";
374a711f6dSmikel #else
38*fbffadb9Smrg __RCSID("$NetBSD: lpf.c,v 1.15 2019/02/03 03:19:30 mrg Exp $");
394a711f6dSmikel #endif
4061f28255Scgd #endif /* not lint */
4161f28255Scgd 
4261f28255Scgd /*
4361f28255Scgd  * 	filter which reads the output of nroff and converts lines
4461f28255Scgd  *	with ^H's to overwritten lines.  Thus this works like 'ul'
4561f28255Scgd  *	but is much better: it can handle more than 2 overwrites
4661f28255Scgd  *	and it is written with some style.
4761f28255Scgd  *	modified by kls to use register references instead of arrays
4861f28255Scgd  *	to try to gain a little speed.
4961f28255Scgd  */
5061f28255Scgd 
5161f28255Scgd #include <signal.h>
529581f118Sthorpej #include <string.h>
53f881d1d4Scgd #include <unistd.h>
54f881d1d4Scgd #include <stdlib.h>
55f881d1d4Scgd #include <stdio.h>
5661f28255Scgd 
5761f28255Scgd #define MAXWIDTH  132
5861f28255Scgd #define MAXREP    10
5961f28255Scgd 
60257a846aSjoerg static char	buf[MAXREP][MAXWIDTH];
61257a846aSjoerg static int	maxcol[MAXREP] = {-1};
62257a846aSjoerg static int	lineno;
63257a846aSjoerg static int	width = 132;	/* default line length */
64257a846aSjoerg static int	length = 66;	/* page length */
65257a846aSjoerg static int	indent;		/* indentation length */
66257a846aSjoerg static int	npages = 1;
67257a846aSjoerg static int	literal;	/* print control characters */
68257a846aSjoerg static char	*name;		/* user's login name */
69257a846aSjoerg static char	*host;		/* user's machine name */
70257a846aSjoerg static char	*acctfile;	/* accounting information file */
71257a846aSjoerg static int	crnl;		/* \n -> \r\n */
72257a846aSjoerg static int	need_cr;
7361f28255Scgd 
74257a846aSjoerg __dead static void usage(void);
75fe7ed7ceSmrg 
76f881d1d4Scgd int
main(int argc,char * argv[])77895dc72aSwiz main(int argc, char *argv[])
7861f28255Scgd {
79fe7ed7ceSmrg 	FILE *p = stdin, *o = stdout;
80fe7ed7ceSmrg 	int i, col;
81fe7ed7ceSmrg 	char *cp;
825b6d0e7eSmrg 	int done, linedone, maxrep, ch, prch;
83fe7ed7ceSmrg 	char *limit;
8461f28255Scgd 
858eef858aSchristos         while ((ch = getopt(argc, argv, "cfh:i:j:l:n:w:")) != -1)
866a7a9484Sabs 		switch (ch) {
8761f28255Scgd 		case 'n':
886a7a9484Sabs 			name = optarg;
8961f28255Scgd 			break;
9061f28255Scgd 		case 'h':
916a7a9484Sabs 			host = optarg;
9261f28255Scgd 			break;
9361f28255Scgd 		case 'w':
946a7a9484Sabs 			if ((i = atoi(optarg)) > 0 && i <= MAXWIDTH)
9561f28255Scgd 				width = i;
9661f28255Scgd 			break;
9761f28255Scgd 		case 'l':
986a7a9484Sabs 			length = atoi(optarg);
9961f28255Scgd 			break;
10061f28255Scgd 		case 'i':
1016a7a9484Sabs 			indent = atoi(optarg);
10261f28255Scgd 			break;
10361f28255Scgd 		case 'c':	/* Print control chars */
10461f28255Scgd 			literal++;
10561f28255Scgd 			break;
1065b6d0e7eSmrg 		case 'f':	/* Fix missing carriage returns */
1075b6d0e7eSmrg 			crnl++;
1085b6d0e7eSmrg 			break;
1098eef858aSchristos 		case 'j':	/* ignore job name */
1108eef858aSchristos 			break;
1116a7a9484Sabs 		default:
1126a7a9484Sabs 			usage();
11361f28255Scgd 		}
1146a7a9484Sabs 	argc -= optind;
1156a7a9484Sabs 	argv += optind;
1166a7a9484Sabs 	if (argc)
1176a7a9484Sabs 		acctfile = *argv;
11861f28255Scgd 
1196a7a9484Sabs 	memset(buf, ' ',  sizeof(buf));
12061f28255Scgd 	done = 0;
12161f28255Scgd 
12261f28255Scgd 	while (!done) {
12361f28255Scgd 		col = indent;
12461f28255Scgd 		maxrep = -1;
12561f28255Scgd 		linedone = 0;
1265b6d0e7eSmrg 		prch = ch = 0;
1275b6d0e7eSmrg 		need_cr = 0;
12861f28255Scgd 		while (!linedone) {
1295b6d0e7eSmrg 			prch = ch;
13061f28255Scgd 			switch (ch = getc(p)) {
13161f28255Scgd 			case EOF:
13261f28255Scgd 				linedone = done = 1;
13361f28255Scgd 				ch = '\n';
13461f28255Scgd 				break;
13561f28255Scgd 
13661f28255Scgd 			case '\f':
13761f28255Scgd 				lineno = length;
138*fbffadb9Smrg 				/* FALLTHROUGH */
13961f28255Scgd 			case '\n':
1405b6d0e7eSmrg 				if (crnl && prch != '\r')
1415b6d0e7eSmrg 					need_cr = 1;
14261f28255Scgd 				if (maxrep < 0)
14361f28255Scgd 					maxrep = 0;
14461f28255Scgd 				linedone = 1;
14561f28255Scgd 				break;
14661f28255Scgd 
14761f28255Scgd 			case '\b':
14861f28255Scgd 				if (--col < indent)
14961f28255Scgd 					col = indent;
15061f28255Scgd 				break;
15161f28255Scgd 
15261f28255Scgd 			case '\r':
15361f28255Scgd 				col = indent;
15461f28255Scgd 				break;
15561f28255Scgd 
15661f28255Scgd 			case '\t':
15761f28255Scgd 				col = ((col - indent) | 07) + indent + 1;
15861f28255Scgd 				break;
15961f28255Scgd 
16061f28255Scgd 			case '\031':
16161f28255Scgd 				/*
16261f28255Scgd 				 * lpd needs to use a different filter to
16361f28255Scgd 				 * print data so stop what we are doing and
16461f28255Scgd 				 * wait for lpd to restart us.
16561f28255Scgd 				 */
16661f28255Scgd 				if ((ch = getchar()) == '\1') {
16761f28255Scgd 					fflush(stdout);
16861f28255Scgd 					kill(getpid(), SIGSTOP);
16961f28255Scgd 					break;
17061f28255Scgd 				} else {
17161f28255Scgd 					ungetc(ch, stdin);
17261f28255Scgd 					ch = '\031';
17361f28255Scgd 				}
17461f28255Scgd 
175*fbffadb9Smrg 				/* FALLTHROUGH */
17661f28255Scgd 			default:
1774a711f6dSmikel 				if (col >= width || (!literal && ch < ' ')) {
17861f28255Scgd 					col++;
17961f28255Scgd 					break;
18061f28255Scgd 				}
18161f28255Scgd 				cp = &buf[0][col];
18261f28255Scgd 				for (i = 0; i < MAXREP; i++) {
18361f28255Scgd 					if (i > maxrep)
18461f28255Scgd 						maxrep = i;
18561f28255Scgd 					if (*cp == ' ') {
18661f28255Scgd 						*cp = ch;
18761f28255Scgd 						if (col > maxcol[i])
18861f28255Scgd 							maxcol[i] = col;
18961f28255Scgd 						break;
19061f28255Scgd 					}
19161f28255Scgd 					cp += MAXWIDTH;
19261f28255Scgd 				}
19361f28255Scgd 				col++;
19461f28255Scgd 				break;
19561f28255Scgd 			}
19661f28255Scgd 		}
19761f28255Scgd 
19861f28255Scgd 		/* print out lines */
19961f28255Scgd 		for (i = 0; i <= maxrep; i++) {
20061f28255Scgd 			for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) {
20161f28255Scgd 				putc(*cp, o);
20261f28255Scgd 				*cp++ = ' ';
20361f28255Scgd 			}
20461f28255Scgd 			if (i < maxrep)
20561f28255Scgd 				putc('\r', o);
2065b6d0e7eSmrg 			else {
2075b6d0e7eSmrg 				if (need_cr)
2085b6d0e7eSmrg 					putc('\r', o);
20961f28255Scgd 				putc(ch, o);
2105b6d0e7eSmrg 			}
21161f28255Scgd 			if (++lineno >= length) {
21261f28255Scgd 				fflush(o);
21361f28255Scgd 				npages++;
21461f28255Scgd 				lineno = 0;
21561f28255Scgd 			}
21661f28255Scgd 			maxcol[i] = -1;
21761f28255Scgd 		}
21861f28255Scgd 	}
21961f28255Scgd 	if (lineno) {		/* be sure to end on a page boundary */
22061f28255Scgd 		putchar('\f');
22161f28255Scgd 		npages++;
22261f28255Scgd 	}
22361f28255Scgd 	if (name && acctfile && access(acctfile, 02) >= 0 &&
22461f28255Scgd 	    freopen(acctfile, "a", stdout) != NULL) {
22561f28255Scgd 		printf("%7.2f\t%s:%s\n", (float)npages, host, name);
22661f28255Scgd 	}
22761f28255Scgd 	exit(0);
22861f28255Scgd }
2296a7a9484Sabs 
230257a846aSjoerg static void
usage(void)231895dc72aSwiz usage(void)
2326a7a9484Sabs {
2336a7a9484Sabs         fprintf(stderr,
2346a7a9484Sabs 	  "usage: lpf [-c] [-f] [-h host] [-i indent] [-l length] [-n name] [-w width] [acctfile]\n");
2356a7a9484Sabs 	exit(1);
2366a7a9484Sabs 
2376a7a9484Sabs }
2386a7a9484Sabs 
239