]>
Commit | Line | Data |
---|---|---|
6dbe3af9 | 1 | /* |
79c10142 KZ |
2 | * Copyright (C) 2016 Sami Kerola <kerolasa@iki.fi> |
3 | * Copyright (C) 2016 Karel Zak <kzak@redhat.com> | |
4 | * | |
6dbe3af9 KZ |
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 | ||
eb63b9b8 | 37 | /* |
b50945d4 | 38 | * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> |
79c10142 | 39 | * added Native Language Support |
eb63b9b8 | 40 | * 1999-09-19 Bruno Haible <haible@clisp.cons.org> |
79c10142 | 41 | * modified to work correctly in multi-byte locales |
eb63b9b8 | 42 | */ |
7eda085c | 43 | |
6dbe3af9 | 44 | #include <stdio.h> |
66ee8158 | 45 | #include <stdlib.h> |
e71daef2 | 46 | #include <getopt.h> |
fd6b7a7f | 47 | |
ea4ccc9e | 48 | #include "nls.h" |
e71daef2 | 49 | #include "c.h" |
9ea8ded3 | 50 | #include "widechar.h" |
b87cbe84 | 51 | #include "closestream.h" |
12707a49 | 52 | #include "fgetwc_or_err.h" |
eb63b9b8 | 53 | |
6dbe3af9 KZ |
54 | /* |
55 | * colcrt - replaces col for crts with new nroff esp. when using tbl. | |
56 | * Bill Joy UCB July 14, 1977 | |
57 | * | |
ea4ccc9e | 58 | * This filter uses the up and down sequences generated by the new |
6dbe3af9 KZ |
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 | ||
ea4ccc9e | 67 | enum { OUTPUT_COLS = 132 }; |
6dbe3af9 | 68 | |
ea4ccc9e | 69 | struct colcrt_control { |
79c10142 KZ |
70 | FILE *f; |
71 | wchar_t line[OUTPUT_COLS + 1]; | |
72 | wchar_t line_under[OUTPUT_COLS + 1]; | |
73 | unsigned int print_nl:1, | |
74 | need_line_under:1, | |
75 | no_underlining:1, | |
76 | half_lines:1; | |
ea4ccc9e | 77 | }; |
e71daef2 | 78 | |
86be6a32 | 79 | static void __attribute__((__noreturn__)) usage(void) |
ea4ccc9e | 80 | { |
86be6a32 | 81 | FILE *out = stdout; |
ea4ccc9e SK |
82 | fputs(USAGE_HEADER, out); |
83 | fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name); | |
79c10142 | 84 | |
ea4ccc9e SK |
85 | fputs(USAGE_SEPARATOR, out); |
86 | fputs(_("Filter nroff output for CRT previewing.\n"), out); | |
79c10142 | 87 | |
ea4ccc9e SK |
88 | fputs(USAGE_OPTIONS, out); |
89 | fputs(_(" -, --no-underlining suppress all underlining\n"), out); | |
90 | fputs(_(" -2, --half-lines print all half-lines\n"), out); | |
79c10142 | 91 | |
ea4ccc9e | 92 | fputs(USAGE_SEPARATOR, out); |
bad4c729 | 93 | fprintf(out, USAGE_HELP_OPTIONS(25)); |
79c10142 | 94 | |
bad4c729 | 95 | fprintf(out, USAGE_MAN_TAIL("colcrt(1)")); |
79c10142 | 96 | |
86be6a32 | 97 | exit(EXIT_SUCCESS); |
ea4ccc9e | 98 | } |
6dbe3af9 | 99 | |
ea4ccc9e SK |
100 | static void trim_trailing_spaces(wchar_t *s) |
101 | { | |
102 | size_t size; | |
103 | wchar_t *end; | |
7eda085c | 104 | |
ea4ccc9e SK |
105 | size = wcslen(s); |
106 | if (!size) | |
107 | return; | |
108 | end = s + size - 1; | |
109 | while (s <= end && iswspace(*end)) | |
110 | end--; | |
111 | *(end + 1) = L'\0'; | |
112 | } | |
e71daef2 | 113 | |
e71daef2 | 114 | |
ea4ccc9e SK |
115 | static void output_lines(struct colcrt_control *ctl, int col) |
116 | { | |
117 | /* first line */ | |
118 | trim_trailing_spaces(ctl->line); | |
119 | fputws(ctl->line, stdout); | |
79c10142 | 120 | |
ea4ccc9e SK |
121 | if (ctl->print_nl) |
122 | fputwc(L'\n', stdout); | |
123 | if (!ctl->half_lines && !ctl->no_underlining) | |
124 | ctl->print_nl = 0; | |
79c10142 | 125 | |
ea4ccc9e | 126 | wmemset(ctl->line, L'\0', OUTPUT_COLS); |
79c10142 | 127 | |
ea4ccc9e SK |
128 | /* second line */ |
129 | if (ctl->need_line_under) { | |
130 | ctl->need_line_under = 0; | |
131 | ctl->line_under[col] = L'\0'; | |
132 | trim_trailing_spaces(ctl->line_under); | |
133 | fputws(ctl->line_under, stdout); | |
134 | fputwc(L'\n', stdout); | |
135 | wmemset(ctl->line_under, L' ', OUTPUT_COLS); | |
79c10142 | 136 | |
ea4ccc9e SK |
137 | } else if (ctl->half_lines && 0 < col) |
138 | fputwc(L'\n', stdout); | |
6dbe3af9 KZ |
139 | } |
140 | ||
ea4ccc9e SK |
141 | static int rubchars(struct colcrt_control *ctl, int col, int n) |
142 | { | |
143 | while (0 < n && 0 < col) { | |
144 | ctl->line[col] = L'\0'; | |
145 | ctl->line_under[col] = L' '; | |
146 | n--; | |
147 | col--; | |
148 | } | |
149 | return col; | |
150 | } | |
151 | ||
152 | static void colcrt(struct colcrt_control *ctl) | |
153 | { | |
154 | int col; | |
d3565072 | 155 | wint_t c = 0; |
962a7dc3 | 156 | long old_pos; |
66ee8158 | 157 | |
ea4ccc9e SK |
158 | ctl->print_nl = 1; |
159 | if (ctl->half_lines) | |
160 | fputwc(L'\n', stdout); | |
79c10142 | 161 | |
ea4ccc9e SK |
162 | for (col = 0; /* nothing */; col++) { |
163 | if (OUTPUT_COLS - 1 < col) { | |
164 | output_lines(ctl, col); | |
165 | errno = 0; | |
962a7dc3 | 166 | old_pos = ftell(ctl->f); |
d3565072 | 167 | |
12707a49 | 168 | while (fgetwc_or_err(ctl->f) != L'\n') { |
d3565072 KZ |
169 | long new_pos; |
170 | ||
171 | if (ferror(ctl->f) || feof(ctl->f)) | |
ea4ccc9e | 172 | return; |
d3565072 KZ |
173 | new_pos = ftell(ctl->f); |
174 | if (old_pos == new_pos) { | |
175 | if (fseek(ctl->f, 1, SEEK_CUR) < 1) | |
176 | return; | |
177 | } else | |
178 | old_pos = new_pos; | |
ea4ccc9e SK |
179 | } |
180 | col = -1; | |
181 | continue; | |
66ee8158 | 182 | } |
12707a49 | 183 | c = fgetwc_or_err(ctl->f); |
66ee8158 | 184 | switch (c) { |
ea4ccc9e | 185 | case 033: /* ESC */ |
12707a49 | 186 | c = fgetwc_or_err(ctl->f); |
ea4ccc9e SK |
187 | if (c == L'8') { |
188 | col = rubchars(ctl, col, 1); | |
66ee8158 KZ |
189 | continue; |
190 | } | |
ea4ccc9e SK |
191 | if (c == L'7') { |
192 | col = rubchars(ctl, col, 2); | |
66ee8158 KZ |
193 | continue; |
194 | } | |
ea4ccc9e SK |
195 | continue; |
196 | case WEOF: | |
197 | ctl->print_nl = 0; | |
198 | output_lines(ctl, col); | |
199 | return; | |
200 | case L'\n': | |
201 | output_lines(ctl, col); | |
202 | col = -1; | |
203 | continue; | |
204 | case L'\t': | |
205 | for (/* nothing */; col % 8 && col < OUTPUT_COLS; col++) { | |
206 | ctl->line[col] = L' '; | |
66ee8158 | 207 | } |
ea4ccc9e SK |
208 | col--; |
209 | continue; | |
210 | case L'_': | |
211 | ctl->line[col] = L' '; | |
212 | if (!ctl->no_underlining) { | |
213 | ctl->need_line_under = 1; | |
214 | ctl->line_under[col] = L'-'; | |
66ee8158 KZ |
215 | } |
216 | continue; | |
ea4ccc9e SK |
217 | default: |
218 | if (!iswprint(c)) { | |
219 | col--; | |
220 | continue; | |
221 | } | |
222 | ctl->print_nl = 1; | |
223 | ctl->line[col] = c; | |
66ee8158 KZ |
224 | } |
225 | } | |
226 | } | |
227 | ||
ea4ccc9e | 228 | int main(int argc, char **argv) |
6dbe3af9 | 229 | { |
87918040 | 230 | struct colcrt_control ctl = { NULL }; |
ea4ccc9e SK |
231 | int opt; |
232 | enum { NO_UL_OPTION = CHAR_MAX + 1 }; | |
6dbe3af9 | 233 | |
ea4ccc9e SK |
234 | static const struct option longopts[] = { |
235 | {"no-underlining", no_argument, NULL, NO_UL_OPTION}, | |
236 | {"half-lines", no_argument, NULL, '2'}, | |
237 | {"version", no_argument, NULL, 'V'}, | |
238 | {"help", no_argument, NULL, 'h'}, | |
239 | {NULL, 0, NULL, 0} | |
240 | }; | |
6dbe3af9 | 241 | |
ea4ccc9e SK |
242 | setlocale(LC_ALL, ""); |
243 | bindtextdomain(PACKAGE, LOCALEDIR); | |
244 | textdomain(PACKAGE); | |
2c308875 | 245 | close_stdout_atexit(); |
79c10142 | 246 | |
ea4ccc9e | 247 | /* Take care of lonely hyphen option. */ |
79c10142 | 248 | for (opt = 0; opt < argc; opt++) { |
ea4ccc9e SK |
249 | if (argv[opt][0] == '-' && argv[opt][1] == '\0') { |
250 | ctl.no_underlining = 1; | |
251 | argc--; | |
252 | memmove(argv + opt, argv + opt + 1, | |
253 | sizeof(char *) * (argc - opt)); | |
254 | opt--; | |
66ee8158 | 255 | } |
79c10142 KZ |
256 | } |
257 | ||
258 | while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) { | |
ea4ccc9e SK |
259 | switch (opt) { |
260 | case NO_UL_OPTION: | |
261 | ctl.no_underlining = 1; | |
262 | break; | |
263 | case '2': | |
264 | ctl.half_lines = 1; | |
265 | break; | |
2c308875 | 266 | |
ea4ccc9e | 267 | case 'V': |
2c308875 | 268 | print_version(EXIT_SUCCESS); |
ea4ccc9e | 269 | case 'h': |
86be6a32 | 270 | usage(); |
ea4ccc9e | 271 | default: |
677ec86c | 272 | errtryhelp(EXIT_FAILURE); |
6dbe3af9 | 273 | } |
79c10142 KZ |
274 | } |
275 | ||
ea4ccc9e SK |
276 | argc -= optind; |
277 | argv += optind; | |
79c10142 | 278 | |
ea4ccc9e SK |
279 | do { |
280 | wmemset(ctl.line, L'\0', OUTPUT_COLS); | |
281 | wmemset(ctl.line_under, L' ', OUTPUT_COLS); | |
79c10142 | 282 | |
ea4ccc9e | 283 | if (argc > 0) { |
79c10142 KZ |
284 | if (!(ctl.f = fopen(*argv, "r"))) |
285 | err(EXIT_FAILURE, _("cannot open %s"), *argv); | |
ea4ccc9e SK |
286 | argc--; |
287 | argv++; | |
288 | } else | |
289 | ctl.f = stdin; | |
79c10142 | 290 | |
ea4ccc9e SK |
291 | colcrt(&ctl); |
292 | if (ctl.f != stdin) | |
293 | fclose(ctl.f); | |
294 | } while (argc > 0); | |
79c10142 | 295 | |
ea4ccc9e | 296 | return EXIT_SUCCESS; |
e71daef2 | 297 | } |