]>
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; | |
66ee8158 | 154 | wint_t c; |
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); |
ea4ccc9e | 166 | while ((c = getwc(ctl->f)) != L'\n') { |
962a7dc3 SK |
167 | long new_pos = ftell(ctl->f); |
168 | if (old_pos == new_pos) | |
169 | fseek(ctl->f, 1, SEEK_CUR); | |
170 | else | |
171 | old_pos = new_pos; | |
ea4ccc9e SK |
172 | if (errno == 0 && c == WEOF) |
173 | return; | |
174 | else | |
175 | errno = 0; | |
176 | } | |
177 | col = -1; | |
178 | continue; | |
66ee8158 | 179 | } |
ea4ccc9e | 180 | c = getwc(ctl->f); |
66ee8158 | 181 | switch (c) { |
ea4ccc9e SK |
182 | case 033: /* ESC */ |
183 | c = getwc(ctl->f); | |
184 | if (c == L'8') { | |
185 | col = rubchars(ctl, col, 1); | |
66ee8158 KZ |
186 | continue; |
187 | } | |
ea4ccc9e SK |
188 | if (c == L'7') { |
189 | col = rubchars(ctl, col, 2); | |
66ee8158 KZ |
190 | continue; |
191 | } | |
ea4ccc9e SK |
192 | continue; |
193 | case WEOF: | |
194 | ctl->print_nl = 0; | |
195 | output_lines(ctl, col); | |
196 | return; | |
197 | case L'\n': | |
198 | output_lines(ctl, col); | |
199 | col = -1; | |
200 | continue; | |
201 | case L'\t': | |
202 | for (/* nothing */; col % 8 && col < OUTPUT_COLS; col++) { | |
203 | ctl->line[col] = L' '; | |
66ee8158 | 204 | } |
ea4ccc9e SK |
205 | col--; |
206 | continue; | |
207 | case L'_': | |
208 | ctl->line[col] = L' '; | |
209 | if (!ctl->no_underlining) { | |
210 | ctl->need_line_under = 1; | |
211 | ctl->line_under[col] = L'-'; | |
66ee8158 KZ |
212 | } |
213 | continue; | |
ea4ccc9e SK |
214 | default: |
215 | if (!iswprint(c)) { | |
216 | col--; | |
217 | continue; | |
218 | } | |
219 | ctl->print_nl = 1; | |
220 | ctl->line[col] = c; | |
66ee8158 KZ |
221 | } |
222 | } | |
223 | } | |
224 | ||
ea4ccc9e | 225 | int main(int argc, char **argv) |
6dbe3af9 | 226 | { |
87918040 | 227 | struct colcrt_control ctl = { NULL }; |
ea4ccc9e SK |
228 | int opt; |
229 | enum { NO_UL_OPTION = CHAR_MAX + 1 }; | |
6dbe3af9 | 230 | |
ea4ccc9e SK |
231 | static const struct option longopts[] = { |
232 | {"no-underlining", no_argument, NULL, NO_UL_OPTION}, | |
233 | {"half-lines", no_argument, NULL, '2'}, | |
234 | {"version", no_argument, NULL, 'V'}, | |
235 | {"help", no_argument, NULL, 'h'}, | |
236 | {NULL, 0, NULL, 0} | |
237 | }; | |
6dbe3af9 | 238 | |
ea4ccc9e SK |
239 | setlocale(LC_ALL, ""); |
240 | bindtextdomain(PACKAGE, LOCALEDIR); | |
241 | textdomain(PACKAGE); | |
2c308875 | 242 | close_stdout_atexit(); |
79c10142 | 243 | |
ea4ccc9e | 244 | /* Take care of lonely hyphen option. */ |
79c10142 | 245 | for (opt = 0; opt < argc; opt++) { |
ea4ccc9e SK |
246 | if (argv[opt][0] == '-' && argv[opt][1] == '\0') { |
247 | ctl.no_underlining = 1; | |
248 | argc--; | |
249 | memmove(argv + opt, argv + opt + 1, | |
250 | sizeof(char *) * (argc - opt)); | |
251 | opt--; | |
66ee8158 | 252 | } |
79c10142 KZ |
253 | } |
254 | ||
255 | while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) { | |
ea4ccc9e SK |
256 | switch (opt) { |
257 | case NO_UL_OPTION: | |
258 | ctl.no_underlining = 1; | |
259 | break; | |
260 | case '2': | |
261 | ctl.half_lines = 1; | |
262 | break; | |
2c308875 | 263 | |
ea4ccc9e | 264 | case 'V': |
2c308875 | 265 | print_version(EXIT_SUCCESS); |
ea4ccc9e | 266 | case 'h': |
86be6a32 | 267 | usage(); |
ea4ccc9e | 268 | default: |
677ec86c | 269 | errtryhelp(EXIT_FAILURE); |
6dbe3af9 | 270 | } |
79c10142 KZ |
271 | } |
272 | ||
ea4ccc9e SK |
273 | argc -= optind; |
274 | argv += optind; | |
79c10142 | 275 | |
ea4ccc9e SK |
276 | do { |
277 | wmemset(ctl.line, L'\0', OUTPUT_COLS); | |
278 | wmemset(ctl.line_under, L' ', OUTPUT_COLS); | |
79c10142 | 279 | |
ea4ccc9e | 280 | if (argc > 0) { |
79c10142 KZ |
281 | if (!(ctl.f = fopen(*argv, "r"))) |
282 | err(EXIT_FAILURE, _("cannot open %s"), *argv); | |
ea4ccc9e SK |
283 | argc--; |
284 | argv++; | |
285 | } else | |
286 | ctl.f = stdin; | |
79c10142 | 287 | |
ea4ccc9e SK |
288 | colcrt(&ctl); |
289 | if (ctl.f != stdin) | |
290 | fclose(ctl.f); | |
291 | } while (argc > 0); | |
79c10142 | 292 | |
ea4ccc9e | 293 | return EXIT_SUCCESS; |
e71daef2 | 294 | } |