]> git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/colcrt.c
su: use lib/pty-session.c code for --pty
[thirdparty/util-linux.git] / text-utils / colcrt.c
1 /*
2 * Copyright (C) 2016 Sami Kerola <kerolasa@iki.fi>
3 * Copyright (C) 2016 Karel Zak <kzak@redhat.com>
4 *
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 /*
38 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
39 * added Native Language Support
40 * 1999-09-19 Bruno Haible <haible@clisp.cons.org>
41 * modified to work correctly in multi-byte locales
42 */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <getopt.h>
47
48 #include "nls.h"
49 #include "c.h"
50 #include "widechar.h"
51 #include "closestream.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 the up and down sequences generated by the new
58 * nroff when used with tbl and by \u \d and \r.
59 * General overstriking doesn't work correctly.
60 * Underlining is split onto multiple lines, etc.
61 *
62 * Option - suppresses all underlining.
63 * Option -2 forces printing of all half lines.
64 */
65
66 enum { OUTPUT_COLS = 132 };
67
68 struct colcrt_control {
69 FILE *f;
70 wchar_t line[OUTPUT_COLS + 1];
71 wchar_t line_under[OUTPUT_COLS + 1];
72 unsigned int print_nl:1,
73 need_line_under:1,
74 no_underlining:1,
75 half_lines:1;
76 };
77
78 static void __attribute__((__noreturn__)) usage(void)
79 {
80 FILE *out = stdout;
81 fputs(USAGE_HEADER, out);
82 fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name);
83
84 fputs(USAGE_SEPARATOR, out);
85 fputs(_("Filter nroff output for CRT previewing.\n"), out);
86
87 fputs(USAGE_OPTIONS, out);
88 fputs(_(" -, --no-underlining suppress all underlining\n"), out);
89 fputs(_(" -2, --half-lines print all half-lines\n"), out);
90
91 fputs(USAGE_SEPARATOR, out);
92 printf(USAGE_HELP_OPTIONS(25));
93
94 printf(USAGE_MAN_TAIL("colcrt(1)"));
95
96 exit(EXIT_SUCCESS);
97 }
98
99 static void trim_trailing_spaces(wchar_t *s)
100 {
101 size_t size;
102 wchar_t *end;
103
104 size = wcslen(s);
105 if (!size)
106 return;
107 end = s + size - 1;
108 while (s <= end && iswspace(*end))
109 end--;
110 *(end + 1) = L'\0';
111 }
112
113
114 static void output_lines(struct colcrt_control *ctl, int col)
115 {
116 /* first line */
117 trim_trailing_spaces(ctl->line);
118 fputws(ctl->line, stdout);
119
120 if (ctl->print_nl)
121 fputwc(L'\n', stdout);
122 if (!ctl->half_lines && !ctl->no_underlining)
123 ctl->print_nl = 0;
124
125 wmemset(ctl->line, L'\0', OUTPUT_COLS);
126
127 /* second line */
128 if (ctl->need_line_under) {
129 ctl->need_line_under = 0;
130 ctl->line_under[col] = L'\0';
131 trim_trailing_spaces(ctl->line_under);
132 fputws(ctl->line_under, stdout);
133 fputwc(L'\n', stdout);
134 wmemset(ctl->line_under, L' ', OUTPUT_COLS);
135
136 } else if (ctl->half_lines && 0 < col)
137 fputwc(L'\n', stdout);
138 }
139
140 static int rubchars(struct colcrt_control *ctl, int col, int n)
141 {
142 while (0 < n && 0 < col) {
143 ctl->line[col] = L'\0';
144 ctl->line_under[col] = L' ';
145 n--;
146 col--;
147 }
148 return col;
149 }
150
151 static void colcrt(struct colcrt_control *ctl)
152 {
153 int col;
154 wint_t c = 0;
155 long old_pos;
156
157 ctl->print_nl = 1;
158 if (ctl->half_lines)
159 fputwc(L'\n', stdout);
160
161 for (col = 0; /* nothing */; col++) {
162 if (OUTPUT_COLS - 1 < col) {
163 output_lines(ctl, col);
164 errno = 0;
165 old_pos = ftell(ctl->f);
166
167 while (getwc(ctl->f) != L'\n') {
168 long new_pos;
169
170 if (ferror(ctl->f) || feof(ctl->f))
171 return;
172 new_pos = ftell(ctl->f);
173 if (old_pos == new_pos) {
174 if (fseek(ctl->f, 1, SEEK_CUR) < 1)
175 return;
176 } else
177 old_pos = new_pos;
178 }
179 col = -1;
180 continue;
181 }
182 c = getwc(ctl->f);
183 switch (c) {
184 case 033: /* ESC */
185 c = getwc(ctl->f);
186 if (c == L'8') {
187 col = rubchars(ctl, col, 1);
188 continue;
189 }
190 if (c == L'7') {
191 col = rubchars(ctl, col, 2);
192 continue;
193 }
194 continue;
195 case WEOF:
196 ctl->print_nl = 0;
197 output_lines(ctl, col);
198 return;
199 case L'\n':
200 output_lines(ctl, col);
201 col = -1;
202 continue;
203 case L'\t':
204 for (/* nothing */; col % 8 && col < OUTPUT_COLS; col++) {
205 ctl->line[col] = L' ';
206 }
207 col--;
208 continue;
209 case L'_':
210 ctl->line[col] = L' ';
211 if (!ctl->no_underlining) {
212 ctl->need_line_under = 1;
213 ctl->line_under[col] = L'-';
214 }
215 continue;
216 default:
217 if (!iswprint(c)) {
218 col--;
219 continue;
220 }
221 ctl->print_nl = 1;
222 ctl->line[col] = c;
223 }
224 }
225 }
226
227 int main(int argc, char **argv)
228 {
229 struct colcrt_control ctl = { NULL };
230 int opt;
231 enum { NO_UL_OPTION = CHAR_MAX + 1 };
232
233 static const struct option longopts[] = {
234 {"no-underlining", no_argument, NULL, NO_UL_OPTION},
235 {"half-lines", no_argument, NULL, '2'},
236 {"version", no_argument, NULL, 'V'},
237 {"help", no_argument, NULL, 'h'},
238 {NULL, 0, NULL, 0}
239 };
240
241 setlocale(LC_ALL, "");
242 bindtextdomain(PACKAGE, LOCALEDIR);
243 textdomain(PACKAGE);
244 close_stdout_atexit();
245
246 /* Take care of lonely hyphen option. */
247 for (opt = 0; opt < argc; opt++) {
248 if (argv[opt][0] == '-' && argv[opt][1] == '\0') {
249 ctl.no_underlining = 1;
250 argc--;
251 memmove(argv + opt, argv + opt + 1,
252 sizeof(char *) * (argc - opt));
253 opt--;
254 }
255 }
256
257 while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) {
258 switch (opt) {
259 case NO_UL_OPTION:
260 ctl.no_underlining = 1;
261 break;
262 case '2':
263 ctl.half_lines = 1;
264 break;
265
266 case 'V':
267 print_version(EXIT_SUCCESS);
268 case 'h':
269 usage();
270 default:
271 errtryhelp(EXIT_FAILURE);
272 }
273 }
274
275 argc -= optind;
276 argv += optind;
277
278 do {
279 wmemset(ctl.line, L'\0', OUTPUT_COLS);
280 wmemset(ctl.line_under, L' ', OUTPUT_COLS);
281
282 if (argc > 0) {
283 if (!(ctl.f = fopen(*argv, "r")))
284 err(EXIT_FAILURE, _("cannot open %s"), *argv);
285 argc--;
286 argv++;
287 } else
288 ctl.f = stdin;
289
290 colcrt(&ctl);
291 if (ctl.f != stdin)
292 fclose(ctl.f);
293 } while (argc > 0);
294
295 return EXIT_SUCCESS;
296 }