]>
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" |
eb63b9b8 | 52 | |
6dbe3af9 KZ |
53 | /* |
54 | * colcrt - replaces col for crts with new nroff esp. when using tbl. | |
55 | * Bill Joy UCB July 14, 1977 | |
56 | * | |
ea4ccc9e | 57 | * This filter uses the up and down sequences generated by the new |
6dbe3af9 KZ |
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 | ||
ea4ccc9e | 66 | enum { OUTPUT_COLS = 132 }; |
6dbe3af9 | 67 | |
ea4ccc9e | 68 | struct colcrt_control { |
79c10142 KZ |
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; | |
ea4ccc9e | 76 | }; |
e71daef2 | 77 | |
86be6a32 | 78 | static void __attribute__((__noreturn__)) usage(void) |
ea4ccc9e | 79 | { |
86be6a32 | 80 | FILE *out = stdout; |
ea4ccc9e SK |
81 | fputs(USAGE_HEADER, out); |
82 | fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name); | |
79c10142 | 83 | |
ea4ccc9e SK |
84 | fputs(USAGE_SEPARATOR, out); |
85 | fputs(_("Filter nroff output for CRT previewing.\n"), out); | |
79c10142 | 86 | |
ea4ccc9e SK |
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); | |
79c10142 | 90 | |
ea4ccc9e | 91 | fputs(USAGE_SEPARATOR, out); |
f45f3ec3 | 92 | printf(USAGE_HELP_OPTIONS(25)); |
79c10142 | 93 | |
f45f3ec3 | 94 | printf(USAGE_MAN_TAIL("colcrt(1)")); |
79c10142 | 95 | |
86be6a32 | 96 | exit(EXIT_SUCCESS); |
ea4ccc9e | 97 | } |
6dbe3af9 | 98 | |
ea4ccc9e SK |
99 | static void trim_trailing_spaces(wchar_t *s) |
100 | { | |
101 | size_t size; | |
102 | wchar_t *end; | |
7eda085c | 103 | |
ea4ccc9e SK |
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 | } | |
e71daef2 | 112 | |
e71daef2 | 113 | |
ea4ccc9e SK |
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); | |
79c10142 | 119 | |
ea4ccc9e SK |
120 | if (ctl->print_nl) |
121 | fputwc(L'\n', stdout); | |
122 | if (!ctl->half_lines && !ctl->no_underlining) | |
123 | ctl->print_nl = 0; | |
79c10142 | 124 | |
ea4ccc9e | 125 | wmemset(ctl->line, L'\0', OUTPUT_COLS); |
79c10142 | 126 | |
ea4ccc9e SK |
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); | |
79c10142 | 135 | |
ea4ccc9e SK |
136 | } else if (ctl->half_lines && 0 < col) |
137 | fputwc(L'\n', stdout); | |
6dbe3af9 KZ |
138 | } |
139 | ||
ea4ccc9e SK |
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; | |
d3565072 | 154 | wint_t c = 0; |
962a7dc3 | 155 | long old_pos; |
66ee8158 | 156 | |
ea4ccc9e SK |
157 | ctl->print_nl = 1; |
158 | if (ctl->half_lines) | |
159 | fputwc(L'\n', stdout); | |
79c10142 | 160 | |
ea4ccc9e SK |
161 | for (col = 0; /* nothing */; col++) { |
162 | if (OUTPUT_COLS - 1 < col) { | |
163 | output_lines(ctl, col); | |
164 | errno = 0; | |
962a7dc3 | 165 | old_pos = ftell(ctl->f); |
d3565072 KZ |
166 | |
167 | while (getwc(ctl->f) != L'\n') { | |
168 | long new_pos; | |
169 | ||
170 | if (ferror(ctl->f) || feof(ctl->f)) | |
ea4ccc9e | 171 | return; |
d3565072 KZ |
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; | |
ea4ccc9e SK |
178 | } |
179 | col = -1; | |
180 | continue; | |
66ee8158 | 181 | } |
ea4ccc9e | 182 | c = getwc(ctl->f); |
66ee8158 | 183 | switch (c) { |
ea4ccc9e SK |
184 | case 033: /* ESC */ |
185 | c = getwc(ctl->f); | |
186 | if (c == L'8') { | |
187 | col = rubchars(ctl, col, 1); | |
66ee8158 KZ |
188 | continue; |
189 | } | |
ea4ccc9e SK |
190 | if (c == L'7') { |
191 | col = rubchars(ctl, col, 2); | |
66ee8158 KZ |
192 | continue; |
193 | } | |
ea4ccc9e SK |
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' '; | |
66ee8158 | 206 | } |
ea4ccc9e SK |
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'-'; | |
66ee8158 KZ |
214 | } |
215 | continue; | |
ea4ccc9e SK |
216 | default: |
217 | if (!iswprint(c)) { | |
218 | col--; | |
219 | continue; | |
220 | } | |
221 | ctl->print_nl = 1; | |
222 | ctl->line[col] = c; | |
66ee8158 KZ |
223 | } |
224 | } | |
225 | } | |
226 | ||
ea4ccc9e | 227 | int main(int argc, char **argv) |
6dbe3af9 | 228 | { |
87918040 | 229 | struct colcrt_control ctl = { NULL }; |
ea4ccc9e SK |
230 | int opt; |
231 | enum { NO_UL_OPTION = CHAR_MAX + 1 }; | |
6dbe3af9 | 232 | |
ea4ccc9e SK |
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 | }; | |
6dbe3af9 | 240 | |
ea4ccc9e SK |
241 | setlocale(LC_ALL, ""); |
242 | bindtextdomain(PACKAGE, LOCALEDIR); | |
243 | textdomain(PACKAGE); | |
2c308875 | 244 | close_stdout_atexit(); |
79c10142 | 245 | |
ea4ccc9e | 246 | /* Take care of lonely hyphen option. */ |
79c10142 | 247 | for (opt = 0; opt < argc; opt++) { |
ea4ccc9e SK |
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--; | |
66ee8158 | 254 | } |
79c10142 KZ |
255 | } |
256 | ||
257 | while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) { | |
ea4ccc9e SK |
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; | |
2c308875 | 265 | |
ea4ccc9e | 266 | case 'V': |
2c308875 | 267 | print_version(EXIT_SUCCESS); |
ea4ccc9e | 268 | case 'h': |
86be6a32 | 269 | usage(); |
ea4ccc9e | 270 | default: |
677ec86c | 271 | errtryhelp(EXIT_FAILURE); |
6dbe3af9 | 272 | } |
79c10142 KZ |
273 | } |
274 | ||
ea4ccc9e SK |
275 | argc -= optind; |
276 | argv += optind; | |
79c10142 | 277 | |
ea4ccc9e SK |
278 | do { |
279 | wmemset(ctl.line, L'\0', OUTPUT_COLS); | |
280 | wmemset(ctl.line_under, L' ', OUTPUT_COLS); | |
79c10142 | 281 | |
ea4ccc9e | 282 | if (argc > 0) { |
79c10142 KZ |
283 | if (!(ctl.f = fopen(*argv, "r"))) |
284 | err(EXIT_FAILURE, _("cannot open %s"), *argv); | |
ea4ccc9e SK |
285 | argc--; |
286 | argv++; | |
287 | } else | |
288 | ctl.f = stdin; | |
79c10142 | 289 | |
ea4ccc9e SK |
290 | colcrt(&ctl); |
291 | if (ctl.f != stdin) | |
292 | fclose(ctl.f); | |
293 | } while (argc > 0); | |
79c10142 | 294 | |
ea4ccc9e | 295 | return EXIT_SUCCESS; |
e71daef2 | 296 | } |