]> git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/colcrt.c
e6c18b79b7b53dfb9783da163a58620be751023c
[thirdparty/util-linux.git] / text-utils / colcrt.c
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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
36 * added Native Language Support
37 * 1999-09-19 Bruno Haible <haible@clisp.cons.org>
38 * modified to work correctly in multi-byte locales
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h> /* for close() */
44 #include <string.h>
45 #include <getopt.h>
46 #include "nls.h"
47
48 #include "widechar.h"
49 #include "c.h"
50 #include "closestream.h"
51
52 int plus(wchar_t c, wchar_t d);
53 void move(int l, int m);
54 void pflush(int ol);
55 static void __attribute__ ((__noreturn__)) usage(FILE * out);
56
57 /*
58 * colcrt - replaces col for crts with new nroff esp. when using tbl.
59 * Bill Joy UCB July 14, 1977
60 *
61 * This filter uses a screen buffer, 267 half-lines by 132 columns.
62 * It interprets the up and down sequences generated by the new
63 * nroff when used with tbl and by \u \d and \r.
64 * General overstriking doesn't work correctly.
65 * Underlining is split onto multiple lines, etc.
66 *
67 * Option - suppresses all underlining.
68 * Option -2 forces printing of all half lines.
69 */
70
71 wchar_t page[267][132];
72
73 int outline = 1;
74 int outcol;
75
76 char suppresul;
77 char printall;
78
79 void colcrt(FILE *f);
80
81 int main(int argc, char **argv) {
82 FILE *f;
83 int i, opt;
84 enum { NO_UL_OPTION = CHAR_MAX + 1 };
85
86 static const struct option longopts[] = {
87 { "no-underlining", no_argument, 0, NO_UL_OPTION },
88 { "half-lines", no_argument, 0, '2' },
89 { "version", no_argument, 0, 'V' },
90 { "help", no_argument, 0, 'h' },
91 { NULL, 0, 0, 0}
92 };
93
94 setlocale(LC_ALL, "");
95 bindtextdomain(PACKAGE, LOCALEDIR);
96 textdomain(PACKAGE);
97 atexit(close_stdout);
98
99 /* Take care of lonely hyphen option. */
100 for (i = 0; i < argc; i++)
101 if (argv[i][0] == '-' && argv[i][1] == '\0') {
102 suppresul = 1;
103 argc--;
104 memmove(argv + i, argv + i + 1,
105 sizeof(char *) * (argc - i));
106 i--;
107 }
108
109 while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1)
110 switch (opt) {
111 case NO_UL_OPTION:
112 suppresul = 1;
113 break;
114 case '2':
115 printall = 1;
116 break;
117 case 'V':
118 printf(_("%s from %s\n"),
119 program_invocation_short_name,
120 PACKAGE_STRING);
121 return EXIT_SUCCESS;
122 case 'h':
123 usage(stdout);
124 default:
125 usage(stderr);
126 }
127 argc -= optind;
128 argv += optind;
129
130 do {
131 if (argc > 0) {
132 if (!(f = fopen(argv[0], "r"))) {
133 fflush(stdout);
134 err(EXIT_FAILURE, "%s", argv[0]);
135 }
136 argc--;
137 argv++;
138 } else {
139 f = stdin;
140 }
141 colcrt(f);
142 if (f != stdin)
143 fclose(f);
144 } while (argc > 0);
145 fflush(stdout);
146 return EXIT_SUCCESS;
147 }
148
149 void colcrt(FILE *f) {
150 wint_t c;
151 wchar_t *cp, *dp;
152 int i, w;
153
154 for (;;) {
155 c = getwc(f);
156 if (c == WEOF) {
157 pflush(outline);
158 fflush(stdout);
159 break;
160 }
161 switch (c) {
162 case '\n':
163 if (outline >= 265)
164 pflush(62);
165 outline += 2;
166 outcol = 0;
167 continue;
168 case '\016':
169 case '\017':
170 continue;
171 case 033:
172 c = getwc(f);
173 switch (c) {
174 case '9':
175 if (outline >= 266)
176 pflush(62);
177 outline++;
178 continue;
179 case '8':
180 if (outline >= 1)
181 outline--;
182 continue;
183 case '7':
184 outline -= 2;
185 if (outline < 0)
186 outline = 0;
187 continue;
188 default:
189 continue;
190 }
191 case '\b':
192 if (outcol)
193 outcol--;
194 continue;
195 case '\t':
196 outcol += 8;
197 outcol &= ~7;
198 outcol--;
199 c = ' ';
200 /* fallthrough */
201 default:
202 w = wcwidth(c);
203 if (outcol + w > 132) {
204 outcol++;
205 continue;
206 }
207 cp = &page[outline][outcol];
208 outcol += w;
209 if (c == '_') {
210 if (suppresul)
211 continue;
212 cp += 132;
213 c = '-';
214 }
215 if (*cp == 0) {
216 /* trick! */
217 for (i = 0; i < w; i++)
218 cp[i] = c;
219 dp = cp - (outcol - w);
220 for (cp--; cp >= dp && *cp == 0; cp--)
221 *cp = ' ';
222 } else {
223 if (plus(c, *cp) || plus(*cp, c))
224 *cp = '+';
225 else if (*cp == ' ' || *cp == 0) {
226 for (i = 1; i < w; i++)
227 if (cp[i] != ' ' && cp[i] != 0)
228 continue;
229 for (i = 0; i < w; i++)
230 cp[i] = c;
231 }
232 }
233 continue;
234 }
235 }
236 }
237
238 int plus(wchar_t c, wchar_t d)
239 {
240
241 return (c == '|' && (d == '-' || d == '_'));
242 }
243
244 int first;
245
246 void pflush(int ol)
247 {
248 register int i;
249 register wchar_t *cp;
250 char lastomit;
251 int l, w;
252
253 l = ol;
254 lastomit = 0;
255 if (l > 266)
256 l = 266;
257 else
258 l |= 1;
259 for (i = first | 1; i < l; i++) {
260 move(i, i - 1);
261 move(i, i + 1);
262 }
263 for (i = first; i < l; i++) {
264 cp = page[i];
265 if (printall == 0 && lastomit == 0 && *cp == 0) {
266 lastomit = 1;
267 continue;
268 }
269 lastomit = 0;
270 while (*cp) {
271 if ((w = wcwidth(*cp)) > 0) {
272 putwchar(*cp);
273 cp += w;
274 } else
275 cp++;
276 }
277 putwchar('\n');
278 }
279 memmove(page, page[ol], (267 - ol) * 132 * sizeof(wchar_t));
280 memset(page[267 - ol], '\0', ol * 132 * sizeof(wchar_t));
281 outline -= ol;
282 outcol = 0;
283 first = 1;
284 }
285
286 void move(int l, int m)
287 {
288 register wchar_t *cp, *dp;
289
290 for (cp = page[l], dp = page[m]; *cp; cp++, dp++) {
291 switch (*cp) {
292 case '|':
293 if (*dp != ' ' && *dp != '|' && *dp != 0)
294 return;
295 break;
296 case ' ':
297 break;
298 default:
299 return;
300 }
301 }
302 if (*cp == 0) {
303 for (cp = page[l], dp = page[m]; *cp; cp++, dp++)
304 if (*cp == '|')
305 *dp = '|';
306 else if (*dp == 0)
307 *dp = ' ';
308 page[l][0] = 0;
309 }
310 }
311
312 static void __attribute__ ((__noreturn__)) usage(FILE * out)
313 {
314 fprintf(out,
315 _("\nUsage:\n"
316 " %s [options] [file ...]\n"), program_invocation_short_name);
317
318 fprintf(out,
319 _(" -, --no-underlining suppress all underlining\n"
320 " -2, --half-lines print all half-lines\n"
321 " -V, --version output version information and exit\n"
322 " -h, --help display this help and exit\n\n"));
323
324 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
325 }