1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1980, 1993\n\
33 	The Regents of the University of California.  All rights reserved.\n";
34 #endif
35 
36 #if 0
37 #ifndef lint
38 static char sccsid[] = "@(#)colcrt.c	8.1 (Berkeley) 6/6/93";
39 #endif
40 #endif
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD: stable/9/usr.bin/colcrt/colcrt.c 216370 2010-12-11 08:32:16Z joel $");
44 
45 #include <err.h>
46 #include <locale.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <wchar.h>
52 
53 /*
54  * colcrt - replaces col for crts with new nroff esp. when using tbl.
55  * Bill Joy UCB July 14, 1977
56  *
57  * This filter uses a screen buffer, 267 half-lines by 132 columns.
58  * It interprets the up and down sequences generated by the new
59  * nroff when used with tbl and by \u \d and \r.
60  * General overstriking doesn't work correctly.
61  * Underlining is split onto multiple lines, etc.
62  *
63  * Option - suppresses all underlining.
64  * Option -2 forces printing of all half lines.
65  */
66 
67 wchar_t	page[267][132];
68 
69 int	outline = 1;
70 int	outcol;
71 
72 char	suppresul;
73 char	printall;
74 
75 static void	move(int, int);
76 static void	pflush(int);
77 static int	plus(wchar_t, wchar_t);
78 static void	usage(void);
79 
80 int
main(int argc,char * argv[])81 main(int argc, char *argv[])
82 {
83 	wint_t c;
84 	wchar_t *cp, *dp;
85 	int ch, i, w;
86 
87 	setlocale(LC_ALL, "");
88 
89 	while ((ch = getopt(argc, argv, "-2")) != -1)
90 		switch (ch) {
91 		case '-':
92 			suppresul = 1;
93 			break;
94 		case '2':
95 			printall = 1;
96 			break;
97 		default:
98 			usage();
99 		}
100 	argc -= optind;
101 	argv += optind;
102 
103 	do {
104 		if (argc > 0) {
105 			if (freopen(argv[0], "r", stdin) == NULL) {
106 				fflush(stdout);
107 				err(1, "%s", argv[0]);
108 			}
109 			argc--;
110 			argv++;
111 		}
112 		for (;;) {
113 			c = getwc(stdin);
114 			if (c == WEOF) {
115 				pflush(outline);
116 				fflush(stdout);
117 				break;
118 			}
119 			switch (c) {
120 			case '\n':
121 				if (outline >= 265)
122 					pflush(62);
123 				outline += 2;
124 				outcol = 0;
125 				continue;
126 			case '\016':
127 			case '\017':
128 				continue;
129 			case 033:
130 				c = getwc(stdin);
131 				switch (c) {
132 				case '9':
133 					if (outline >= 266)
134 						pflush(62);
135 					outline++;
136 					continue;
137 				case '8':
138 					if (outline >= 1)
139 						outline--;
140 					continue;
141 				case '7':
142 					outline -= 2;
143 					if (outline < 0)
144 						outline = 0;
145 					continue;
146 				default:
147 					continue;
148 				}
149 			case '\b':
150 				if (outcol)
151 					outcol--;
152 				continue;
153 			case '\t':
154 				outcol += 8;
155 				outcol &= ~7;
156 				outcol--;
157 				c = ' ';
158 			default:
159 				if ((w = wcwidth(c)) <= 0)
160 					w = 1;	/* XXX */
161 				if (outcol + w > 132) {
162 					outcol += w;
163 					continue;
164 				}
165 				cp = &page[outline][outcol];
166 				outcol += w;
167 				if (c == '_') {
168 					if (suppresul)
169 						continue;
170 					cp += 132;
171 					c = '-';
172 				}
173 				if (*cp == 0) {
174 					for (i = 0; i < w; i++)
175 						cp[i] = c;
176 					dp = cp - (outcol - w);
177 					for (cp--; cp >= dp && *cp == 0; cp--)
178 						*cp = ' ';
179 				} else {
180 					if (plus(c, *cp) || plus(*cp, c))
181 						*cp = '+';
182 					else if (*cp == ' ' || *cp == 0) {
183 						for (i = 1; i < w; i++)
184 							if (cp[i] != ' ' &&
185 							    cp[i] != 0)
186 								goto cont;
187 						for (i = 0; i < w; i++)
188 							cp[i] = c;
189 					}
190 				}
191 cont:
192 				continue;
193 			}
194 		}
195 		if (ferror(stdin))
196 			err(1, NULL);
197 	} while (argc > 0);
198 	fflush(stdout);
199 	exit(0);
200 }
201 
202 static void
usage(void)203 usage(void)
204 {
205 	fprintf(stderr, "usage: colcrt [-] [-2] [file ...]\n");
206 	exit(1);
207 }
208 
209 static int
plus(wchar_t c,wchar_t d)210 plus(wchar_t c, wchar_t d)
211 {
212 
213 	return ((c == '|' && d == '-') || d == '_');
214 }
215 
216 static void
pflush(int ol)217 pflush(int ol)
218 {
219 	static int first;
220 	int i;
221 	wchar_t *cp;
222 	char lastomit;
223 	int l, w;
224 
225 	l = ol;
226 	lastomit = 0;
227 	if (l > 266)
228 		l = 266;
229 	else
230 		l |= 1;
231 	for (i = first | 1; i < l; i++) {
232 		move(i, i - 1);
233 		move(i, i + 1);
234 	}
235 	for (i = first; i < l; i++) {
236 		cp = page[i];
237 		if (printall == 0 && lastomit == 0 && *cp == 0) {
238 			lastomit = 1;
239 			continue;
240 		}
241 		lastomit = 0;
242 		while (*cp != L'\0') {
243 			if ((w = wcwidth(*cp)) > 0) {
244 				putwchar(*cp);
245 				cp += w;
246 			} else
247 				cp++;
248 		}
249 		putwchar(L'\n');
250 	}
251 	wmemcpy(page[0], page[ol], (267 - ol) * 132);
252 	wmemset(page[267- ol], L'\0', ol * 132);
253 	outline -= ol;
254 	outcol = 0;
255 	first = 1;
256 }
257 
258 static void
move(int l,int m)259 move(int l, int m)
260 {
261 	wchar_t *cp, *dp;
262 
263 	for (cp = page[l], dp = page[m]; *cp; cp++, dp++) {
264 		switch (*cp) {
265 			case '|':
266 				if (*dp != ' ' && *dp != '|' && *dp != 0)
267 					return;
268 				break;
269 			case ' ':
270 				break;
271 			default:
272 				return;
273 		}
274 	}
275 	if (*cp == 0) {
276 		for (cp = page[l], dp = page[m]; *cp; cp++, dp++)
277 			if (*cp == '|')
278 				*dp = '|';
279 			else if (*dp == 0)
280 				*dp = ' ';
281 		page[l][0] = 0;
282 	}
283 }
284