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
31static 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
38static char sccsid[] = "@(#)colcrt.c	8.1 (Berkeley) 6/6/93";
39#endif
40#endif
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: releng/10.3/usr.bin/colcrt/colcrt.c 227158 2011-11-06 08:14:28Z ed $");
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
67static wchar_t	page[267][132];
68
69static int	outline = 1;
70static int	outcol;
71
72static char	suppresul;
73static char	printall;
74
75static void	move(int, int);
76static void	pflush(int);
77static int	plus(wchar_t, wchar_t);
78static void	usage(void);
79
80int
81main(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				}
191cont:
192				continue;
193			}
194		}
195		if (ferror(stdin))
196			err(1, NULL);
197	} while (argc > 0);
198	fflush(stdout);
199	exit(0);
200}
201
202static void
203usage(void)
204{
205	fprintf(stderr, "usage: colcrt [-] [-2] [file ...]\n");
206	exit(1);
207}
208
209static int
210plus(wchar_t c, wchar_t d)
211{
212
213	return ((c == '|' && d == '-') || d == '_');
214}
215
216static void
217pflush(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
258static void
259move(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