1152616Sle/*
2152616Sle * Copyright (c) 1980, 1993
3152631Sle *	The Regents of the University of California.  All rights reserved.
4152616Sle *
5152616Sle * Redistribution and use in source and binary forms, with or without
6152616Sle * modification, are permitted provided that the following conditions
7152631Sle * are met:
8152631Sle * 1. Redistributions of source code must retain the above copyright
9152631Sle *    notice, this list of conditions and the following disclaimer.
10152631Sle * 2. Redistributions in binary form must reproduce the above copyright
11152616Sle *    notice, this list of conditions and the following disclaimer in the
12152616Sle *    documentation and/or other materials provided with the distribution.
13152616Sle * 4. Neither the name of the University nor the names of its contributors
14152616Sle *    may be used to endorse or promote products derived from this software
15152616Sle *    without specific prior written permission.
16152616Sle *
17152616Sle * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18152616Sle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19152616Sle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20152616Sle * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21152616Sle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22152616Sle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23152616Sle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24152616Sle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25152616Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26152616Sle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27152616Sle * SUCH DAMAGE.
28152631Sle */
29152616Sle
30152616Sle#ifndef lint
31266014Smariusstatic const char copyright[] =
32152616Sle"@(#) Copyright (c) 1980, 1993\n\
33152616Sle	The Regents of the University of California.  All rights reserved.\n";
34152616Sle#endif
35152616Sle
36152616Sle#if 0
37152616Sle#ifndef lint
38152616Slestatic char sccsid[] = "@(#)colcrt.c	8.1 (Berkeley) 6/6/93";
39152616Sle#endif
40152616Sle#endif
41152616Sle
42152616Sle#include <sys/cdefs.h>
43190507Slulf__FBSDID("$FreeBSD$");
44190507Slulf
45233648Seadler#include <err.h>
46190507Slulf#include <locale.h>
47190507Slulf#include <stdio.h>
48190507Slulf#include <stdlib.h>
49190507Slulf#include <string.h>
50162842Sru#include <unistd.h>
51162842Sru#include <wchar.h>
52162842Sru
53152631Sle/*
54152616Sle * colcrt - replaces col for crts with new nroff esp. when using tbl.
55152616Sle * Bill Joy UCB July 14, 1977
56162842Sru *
57162842Sru * This filter uses a screen buffer, 267 half-lines by 132 columns.
58152616Sle * It interprets the up and down sequences generated by the new
59190507Slulf * nroff when used with tbl and by \u \d and \r.
60190507Slulf * General overstriking doesn't work correctly.
61235873Swblock * Underlining is split onto multiple lines, etc.
62235873Swblock *
63190507Slulf * Option - suppresses all underlining.
64152616Sle * Option -2 forces printing of all half lines.
65152616Sle */
66152616Sle
67152631Slestatic wchar_t	page[267][132];
68152631Sle
69152616Slestatic int	outline = 1;
70152616Slestatic int	outcol;
71190507Slulf
72190507Slulfstatic char	suppresul;
73190507Slulfstatic char	printall;
74190507Slulf
75190507Slulfstatic void	move(int, int);
76190507Slulfstatic void	pflush(int);
77190507Slulfstatic int	plus(wchar_t, wchar_t);
78190507Slulfstatic void	usage(void);
79190507Slulf
80190507Slulfint
81190507Slulfmain(int argc, char *argv[])
82190507Slulf{
83190884Slulf	wint_t c;
84190884Slulf	wchar_t *cp, *dp;
85190884Slulf	int ch, i, w;
86190884Slulf
87162842Sru	setlocale(LC_ALL, "");
88152631Sle
89152631Sle	while ((ch = getopt(argc, argv, "-2")) != -1)
90152616Sle		switch (ch) {
91162842Sru		case '-':
92162842Sru			suppresul = 1;
93162842Sru			break;
94162842Sru		case '2':
95162842Sru			printall = 1;
96162842Sru			break;
97162842Sru		default:
98152616Sle			usage();
99152616Sle		}
100162842Sru	argc -= optind;
101162842Sru	argv += optind;
102152616Sle
103152631Sle	do {
104152616Sle		if (argc > 0) {
105152616Sle			if (freopen(argv[0], "r", stdin) == NULL) {
106190507Slulf				fflush(stdout);
107233648Seadler				err(1, "%s", argv[0]);
108190507Slulf			}
109190507Slulf			argc--;
110233648Seadler			argv++;
111190507Slulf		}
112190507Slulf		for (;;) {
113190507Slulf			c = getwc(stdin);
114162842Sru			if (c == WEOF) {
115162842Sru				pflush(outline);
116162842Sru				fflush(stdout);
117152616Sle				break;
118152616Sle			}
119162842Sru			switch (c) {
120162842Sru			case '\n':
121152616Sle				if (outline >= 265)
122152616Sle					pflush(62);
123190507Slulf				outline += 2;
124190507Slulf				outcol = 0;
125190507Slulf				continue;
126190507Slulf			case '\016':
127190507Slulf			case '\017':
128190507Slulf				continue;
129190507Slulf			case 033:
130190507Slulf				c = getwc(stdin);
131162842Sru				switch (c) {
132162842Sru				case '9':
133152616Sle					if (outline >= 266)
134190507Slulf						pflush(62);
135190507Slulf					outline++;
136162842Sru					continue;
137162842Sru				case '8':
138152616Sle					if (outline >= 1)
139162842Sru						outline--;
140162842Sru					continue;
141152616Sle				case '7':
142162842Sru					outline -= 2;
143152616Sle					if (outline < 0)
144162842Sru						outline = 0;
145152631Sle					continue;
146152616Sle				default:
147162842Sru					continue;
148162842Sru				}
149152616Sle			case '\b':
150190507Slulf				if (outcol)
151190507Slulf					outcol--;
152235873Swblock				continue;
153235873Swblock			case '\t':
154190507Slulf				outcol += 8;
155162842Sru				outcol &= ~7;
156162842Sru				outcol--;
157162842Sru				c = ' ';
158152616Sle			default:
159152616Sle				if ((w = wcwidth(c)) <= 0)
160152616Sle					w = 1;	/* XXX */
161152631Sle				if (outcol + w > 132) {
162152616Sle					outcol += w;
163152616Sle					continue;
164162842Sru				}
165162842Sru				cp = &page[outline][outcol];
166162842Sru				outcol += w;
167152631Sle				if (c == '_') {
168152616Sle					if (suppresul)
169152616Sle						continue;
170152616Sle					cp += 132;
171266014Smarius					c = '-';
172157052Sle				}
173157052Sle				if (*cp == 0) {
174157052Sle					for (i = 0; i < w; i++)
175162842Sru						cp[i] = c;
176152631Sle					dp = cp - (outcol - w);
177152616Sle					for (cp--; cp >= dp && *cp == 0; cp--)
178152616Sle						*cp = ' ';
179162842Sru				} else {
180152631Sle					if (plus(c, *cp) || plus(*cp, c))
181152616Sle						*cp = '+';
182152616Sle					else if (*cp == ' ' || *cp == 0) {
183162842Sru						for (i = 1; i < w; i++)
184152631Sle							if (cp[i] != ' ' &&
185162842Sru							    cp[i] != 0)
186162842Sru								goto cont;
187152616Sle						for (i = 0; i < w; i++)
188152616Sle							cp[i] = c;
189162842Sru					}
190152616Sle				}
191162842Srucont:
192162842Sru				continue;
193190507Slulf			}
194190507Slulf		}
195190507Slulf		if (ferror(stdin))
196190507Slulf			err(1, NULL);
197162842Sru	} while (argc > 0);
198152616Sle	fflush(stdout);
199152616Sle	exit(0);
200190507Slulf}
201190507Slulf
202190507Slulfstatic void
203190507Slulfusage(void)
204190507Slulf{
205190507Slulf	fprintf(stderr, "usage: colcrt [-] [-2] [file ...]\n");
206235873Swblock	exit(1);
207235873Swblock}
208235873Swblock
209152616Slestatic int
210152616Sleplus(wchar_t c, wchar_t d)
211152616Sle{
212152616Sle
213152616Sle	return ((c == '|' && d == '-') || d == '_');
214162842Sru}
215162842Sru
216152616Slestatic void
217162842Srupflush(int ol)
218162842Sru{
219152616Sle	static int first;
220152616Sle	int i;
221152616Sle	wchar_t *cp;
222162842Sru	char lastomit;
223152616Sle	int l, w;
224152616Sle
225152616Sle	l = ol;
226152616Sle	lastomit = 0;
227152616Sle	if (l > 266)
228152616Sle		l = 266;
229152616Sle	else
230162842Sru		l |= 1;
231162842Sru	for (i = first | 1; i < l; i++) {
232162842Sru		move(i, i - 1);
233152631Sle		move(i, i + 1);
234152616Sle	}
235152616Sle	for (i = first; i < l; i++) {
236152616Sle		cp = page[i];
237152631Sle		if (printall == 0 && lastomit == 0 && *cp == 0) {
238152616Sle			lastomit = 1;
239152616Sle			continue;
240162842Sru		}
241162842Sru		lastomit = 0;
242152616Sle		while (*cp != L'\0') {
243152616Sle			if ((w = wcwidth(*cp)) > 0) {
244152631Sle				putwchar(*cp);
245152616Sle				cp += w;
246152616Sle			} else
247162842Sru				cp++;
248162842Sru		}
249152616Sle		putwchar(L'\n');
250152616Sle	}
251152631Sle	wmemcpy(page[0], page[ol], (267 - ol) * 132);
252152616Sle	wmemset(page[267- ol], L'\0', ol * 132);
253152616Sle	outline -= ol;
254152616Sle	outcol = 0;
255152616Sle	first = 1;
256152616Sle}
257152616Sle
258152616Slestatic void
259152616Slemove(int l, int m)
260152616Sle{
261152616Sle	wchar_t *cp, *dp;
262162842Sru
263152616Sle	for (cp = page[l], dp = page[m]; *cp; cp++, dp++) {
264152616Sle		switch (*cp) {
265152616Sle			case '|':
266162842Sru				if (*dp != ' ' && *dp != '|' && *dp != 0)
267162842Sru					return;
268162842Sru				break;
269162842Sru			case ' ':
270162842Sru				break;
271162842Sru			default:
272162842Sru				return;
273162842Sru		}
274152616Sle	}
275162842Sru	if (*cp == 0) {
276152616Sle		for (cp = page[l], dp = page[m]; *cp; cp++, dp++)
277152616Sle			if (*cp == '|')
278152616Sle				*dp = '|';
279152616Sle			else if (*dp == 0)
280152616Sle				*dp = ' ';
281190507Slulf		page[l][0] = 0;
282255977Spluknet	}
283255977Spluknet}
284235873Swblock