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