xref: /freebsd/usr.sbin/lpr/filters/lpf.c (revision 4b9d6057)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include "lp.cdefs.h"		/* A cross-platform version of <sys/cdefs.h> */
33 /*
34  * 	filter which reads the output of nroff and converts lines
35  *	with ^H's to overwritten lines.  Thus this works like 'ul'
36  *	but is much better: it can handle more than 2 overwrites
37  *	and it is written with some style.
38  *	modified by kls to use register references instead of arrays
39  *	to try to gain a little speed.
40  */
41 
42 #include <signal.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 
48 #define MAXWIDTH  132
49 #define MAXREP    10
50 
51 static char	buf[MAXREP][MAXWIDTH];
52 static int	maxcol[MAXREP] = {-1};
53 static int	lineno;
54 static int	width = 132;	/* default line length */
55 static int	length = 66;	/* page length */
56 static int	indent;		/* indentation length */
57 static int	npages = 1;
58 static int	literal;	/* print control characters */
59 static char	*name;		/* user's login name */
60 static char	*host;		/* user's machine name */
61 static char	*acctfile;	/* accounting information file */
62 
63 int
64 main(int argc, char *argv[])
65 {
66 	register FILE *p = stdin, *o = stdout;
67 	register int i, col;
68 	register char *cp;
69 	int done, linedone, maxrep;
70 	char *limit;
71 	int ch;
72 
73 	while (--argc) {
74 		if (*(cp = *++argv) == '-') {
75 			switch (cp[1]) {
76 			case 'n':
77 				argc--;
78 				name = *++argv;
79 				break;
80 
81 			case 'h':
82 				argc--;
83 				host = *++argv;
84 				break;
85 
86 			case 'w':
87 				if ((i = atoi(&cp[2])) > 0 && i <= MAXWIDTH)
88 					width = i;
89 				break;
90 
91 			case 'l':
92 				length = atoi(&cp[2]);
93 				break;
94 
95 			case 'i':
96 				indent = atoi(&cp[2]);
97 				break;
98 
99 			case 'c':	/* Print control chars */
100 				literal++;
101 				break;
102 			}
103 		} else
104 			acctfile = cp;
105 	}
106 
107 	memset(buf, ' ', sizeof(buf));
108 	done = 0;
109 
110 	while (!done) {
111 		col = indent;
112 		maxrep = -1;
113 		linedone = 0;
114 		while (!linedone) {
115 			switch (ch = getc(p)) {
116 			case EOF:
117 				linedone = done = 1;
118 				ch = '\n';
119 				break;
120 
121 			case '\f':
122 				lineno = length;
123 			case '\n':
124 				if (maxrep < 0)
125 					maxrep = 0;
126 				linedone = 1;
127 				break;
128 
129 			case '\b':
130 				if (--col < indent)
131 					col = indent;
132 				break;
133 
134 			case '\r':
135 				col = indent;
136 				break;
137 
138 			case '\t':
139 				col = ((col - indent) | 07) + indent + 1;
140 				break;
141 
142 			case '\031':
143 				/*
144 				 * lpd needs to use a different filter to
145 				 * print data so stop what we are doing and
146 				 * wait for lpd to restart us.
147 				 */
148 				if ((ch = getchar()) == '\1') {
149 					fflush(stdout);
150 					kill(getpid(), SIGSTOP);
151 					break;
152 				} else {
153 					ungetc(ch, stdin);
154 					ch = '\031';
155 				}
156 
157 			default:
158 				if (col >= width || (!literal && ch < ' ')) {
159 					col++;
160 					break;
161 				}
162 				cp = &buf[0][col];
163 				for (i = 0; i < MAXREP; i++) {
164 					if (i > maxrep)
165 						maxrep = i;
166 					if (*cp == ' ') {
167 						*cp = ch;
168 						if (col > maxcol[i])
169 							maxcol[i] = col;
170 						break;
171 					}
172 					cp += MAXWIDTH;
173 				}
174 				col++;
175 				break;
176 			}
177 		}
178 
179 		/* print out lines */
180 		for (i = 0; i <= maxrep; i++) {
181 			for (cp = buf[i], limit = cp+maxcol[i]; cp <= limit;) {
182 				putc(*cp, o);
183 				*cp++ = ' ';
184 			}
185 			if (i < maxrep)
186 				putc('\r', o);
187 			else
188 				putc(ch, o);
189 			if (++lineno >= length) {
190 				fflush(o);
191 				npages++;
192 				lineno = 0;
193 			}
194 			maxcol[i] = -1;
195 		}
196 	}
197 	if (lineno) {		/* be sure to end on a page boundary */
198 		putchar('\f');
199 		npages++;
200 	}
201 	if (name && acctfile && access(acctfile, 02) >= 0 &&
202 	    freopen(acctfile, "a", stdout) != NULL) {
203 		printf("%7.2f\t%s:%s\n", (float)npages, host, name);
204 	}
205 	exit(0);
206 }
207