]> git.ipfire.org Git - thirdparty/util-linux.git/blame - text-utils/ul.c
po-man: add uk.po (from translationproject.org)
[thirdparty/util-linux.git] / text-utils / ul.c
CommitLineData
6dbe3af9
KZ
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
fd6b7a7f 34/*
eb63b9b8
KZ
35 * modified by Kars de Jong <jongk@cs.utwente.nl>
36 * to use terminfo instead of termcap.
b50945d4 37 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
50646353 38 * added Native Language Support
eb63b9b8 39 * 1999-09-19 Bruno Haible <haible@clisp.cons.org>
50646353 40 * modified to work correctly in multi-byte locales
eb63b9b8 41 */
fd6b7a7f 42
6dbe3af9 43#include <stdio.h>
fd6b7a7f 44#include <unistd.h> /* for getopt(), isatty() */
c0f19ccf 45#include <string.h> /* for memset(), strcpy() */
2b6fc908 46#include <stdlib.h> /* for getenv() */
5c36a0eb 47#include <limits.h> /* for INT_MAX */
4727b169 48#include <signal.h> /* for signal() */
59f8c787 49#include <errno.h>
a3b76180 50#include <getopt.h>
fd6b7a7f 51
3947ca4c
KZ
52#if defined(HAVE_NCURSESW_TERM_H)
53# include <ncursesw/term.h>
2ac1bc84
KZ
54#elif defined(HAVE_NCURSES_TERM_H)
55# include <ncurses/term.h>
3947ca4c
KZ
56#elif defined(HAVE_TERM_H)
57# include <term.h>
2ac1bc84
KZ
58#endif
59
f0961db2
DB
60#include "nls.h"
61#include "xalloc.h"
eb63b9b8 62#include "widechar.h"
eb76ca98 63#include "c.h"
b87cbe84 64#include "closestream.h"
eb63b9b8 65
9a59ee65 66#define ESC '\033'
6dbe3af9
KZ
67#define SO '\016'
68#define SI '\017'
69#define HFWD '9'
70#define HREV '8'
71#define FREV '7'
6dbe3af9 72
eaf68e30 73enum {
9a59ee65 74 NORMAL_CHARSET = 0, /* Must be zero, see initbuf() */
580c6325 75 ALTERNATIVE_CHARSET = 1 << 0, /* Reverse */
9a59ee65
SK
76 SUPERSCRIPT = 1 << 1, /* Dim */
77 SUBSCRIPT = 1 << 2, /* Dim | Ul */
78 UNDERLINE = 1 << 3, /* Ul */
79 BOLD = 1 << 4, /* Bold */
eaf68e30 80};
6dbe3af9 81
49421939
SK
82struct term_caps {
83 char *curs_up;
84 char *curs_right;
85 char *curs_left;
86 char *enter_standout;
87 char *exit_standout;
88 char *enter_underline;
89 char *exit_underline;
90 char *enter_dim;
91 char *enter_bold;
92 char *enter_reverse;
93 char *under_char;
94 char *exit_attributes;
95};
6dbe3af9 96
eaf68e30 97struct ul_char {
eb63b9b8 98 wchar_t c_char;
66ee8158 99 int c_width;
eaf68e30 100 char c_mode;
565239b0 101};
6dbe3af9 102
eaf68e30 103struct ul_ctl {
0186ff36
SK
104 size_t column;
105 size_t max_column;
9a59ee65
SK
106 int half_position;
107 int up_line;
eaf68e30 108 int mode;
9a59ee65 109 int current_mode;
0186ff36 110 size_t buflen;
9a59ee65 111 struct ul_char *buf;
eaf68e30 112 unsigned int
9a59ee65 113 indicated_opt:1,
eaf68e30
SK
114 must_use_uc:1,
115 must_overstrike:1;
116};
a2811907 117
86be6a32 118static void __attribute__((__noreturn__)) usage(void)
a3b76180 119{
86be6a32 120 FILE *out = stdout;
5b627d84 121
a2343e03
KZ
122 fputs(USAGE_HEADER, out);
123 fprintf(out, _(" %s [options] [<file> ...]\n"), program_invocation_short_name);
a3b76180 124
451dbcfa
BS
125 fputs(USAGE_SEPARATOR, out);
126 fputs(_("Do underlining.\n"), out);
127
128 fputs(USAGE_OPTIONS, out);
a2343e03
KZ
129 fputs(_(" -t, -T, --terminal TERMINAL override the TERM environment variable\n"), out);
130 fputs(_(" -i, --indicated underlining is indicated via a separate line\n"), out);
f45f3ec3 131 printf(USAGE_HELP_OPTIONS(30));
a2343e03 132
f45f3ec3 133 printf(USAGE_MAN_TAIL("ul(1)"));
a3b76180 134
86be6a32 135 exit(EXIT_SUCCESS);
a3b76180
SK
136}
137
0186ff36 138static void need_column(struct ul_ctl *ctl, size_t new_max)
6dbe3af9 139{
9a59ee65 140 ctl->max_column = new_max;
6dbe3af9 141
9a59ee65 142 while (new_max >= ctl->buflen) {
0186ff36 143 ctl->buflen *= 2;
9a59ee65 144 ctl->buf = xrealloc(ctl->buf, sizeof(struct ul_char) * ctl->buflen);
a2811907
SK
145 }
146}
4727b169 147
0186ff36 148static void set_column(struct ul_ctl *ctl, size_t column)
a2811907 149{
9a59ee65 150 ctl->column = column;
565239b0 151
0186ff36 152 if (ctl->max_column < ctl->column)
9a59ee65 153 need_column(ctl, ctl->column);
a2811907 154}
6dbe3af9 155
9a59ee65 156static void init_buffer(struct ul_ctl *ctl)
a2811907 157{
9a59ee65 158 if (ctl->buf == NULL) {
a2811907 159 /* First time. */
9a59ee65
SK
160 ctl->buflen = BUFSIZ;
161 ctl->buf = xcalloc(ctl->buflen, sizeof(struct ul_char));
a2811907 162 } else
580c6325 163 /* assumes NORMAL_CHARSET == 0 */
9a59ee65 164 memset(ctl->buf, 0, sizeof(struct ul_char) * ctl->max_column);
2c308875 165
9a59ee65
SK
166 set_column(ctl, 0);
167 ctl->max_column = 0;
580c6325 168 ctl->mode &= ALTERNATIVE_CHARSET;
a2811907 169}
6dbe3af9 170
9a59ee65 171static void init_term_caps(struct ul_ctl *ctl, struct term_caps *const tcs)
a2811907 172{
49421939
SK
173 tcs->curs_up = tigetstr("cuu1");
174 tcs->curs_right = tigetstr("cuf1");
175 tcs->curs_left = tigetstr("cub1");
176 if (tcs->curs_left == NULL)
177 tcs->curs_left = "\b";
178
179 tcs->enter_standout = tigetstr("smso");
180 tcs->exit_standout = tigetstr("rmso");
181 tcs->enter_underline = tigetstr("smul");
182 tcs->exit_underline = tigetstr("rmul");
183 tcs->enter_dim = tigetstr("dim");
184 tcs->enter_bold = tigetstr("bold");
185 tcs->enter_reverse = tigetstr("rev");
186 tcs->exit_attributes = tigetstr("sgr0");
187
188 if (!tcs->enter_bold && tcs->enter_reverse)
189 tcs->enter_bold = tcs->enter_reverse;
190
191 if (!tcs->enter_bold && tcs->enter_standout)
192 tcs->enter_bold = tcs->enter_standout;
193
194 if (!tcs->enter_underline && tcs->enter_standout) {
50646353
KZ
195 tcs->enter_underline = tcs->enter_standout;
196 tcs->exit_underline = tcs->exit_standout;
6dbe3af9 197 }
49421939
SK
198
199 if (!tcs->enter_dim && tcs->enter_standout)
50646353 200 tcs->enter_dim = tcs->enter_standout;
49421939
SK
201
202 if (!tcs->enter_reverse && tcs->enter_standout)
50646353 203 tcs->enter_reverse = tcs->enter_standout;
49421939
SK
204
205 if (!tcs->exit_attributes && tcs->exit_standout)
50646353 206 tcs->exit_attributes = tcs->exit_standout;
5b627d84 207
a2811907
SK
208 /*
209 * Note that we use REVERSE for the alternate character set,
210 * not the as/ae capabilities. This is because we are modeling
211 * the model 37 teletype (since that's what nroff outputs) and
212 * the typical as/ae is more of a graphics set, not the greek
213 * letters the 37 has.
214 */
49421939 215 tcs->under_char = tigetstr("uc");
eaf68e30 216 ctl->must_use_uc = (tcs->under_char && !tcs->enter_underline);
49421939
SK
217
218 if ((tigetflag("os") && tcs->enter_bold == NULL) ||
50646353
KZ
219 (tigetflag("ul") && tcs->enter_underline == NULL
220 && tcs->under_char == NULL))
eaf68e30 221 ctl->must_overstrike = 1;
6dbe3af9
KZ
222}
223
a2811907 224static void sig_handler(int signo __attribute__((__unused__)))
a4949aaa 225{
a2811907
SK
226 _exit(EXIT_SUCCESS);
227}
a4949aaa 228
52e3ce00
SK
229static int ul_putwchar(int c)
230{
231 if (putwchar(c) == WEOF)
232 return EOF;
233 return c;
234}
235
9a59ee65 236static void print_line(char *line)
a2811907
SK
237{
238 if (line == NULL)
239 return;
52e3ce00 240 tputs(line, STDOUT_FILENO, ul_putwchar);
a2811907
SK
241}
242
9a59ee65
SK
243static void ul_setmode(struct ul_ctl *ctl, struct term_caps const *const tcs,
244 int new_mode)
a2811907 245{
9a59ee65
SK
246 if (!ctl->indicated_opt) {
247 if (ctl->current_mode != NORMAL_CHARSET && new_mode != NORMAL_CHARSET)
248 ul_setmode(ctl, tcs, NORMAL_CHARSET);
50646353 249
9a59ee65 250 switch (new_mode) {
580c6325 251 case NORMAL_CHARSET:
9a59ee65 252 switch (ctl->current_mode) {
580c6325 253 case NORMAL_CHARSET:
a2811907 254 break;
580c6325 255 case UNDERLINE:
9a59ee65 256 print_line(tcs->exit_underline);
a2811907
SK
257 break;
258 default:
259 /* This includes standout */
9a59ee65 260 print_line(tcs->exit_attributes);
a2811907
SK
261 break;
262 }
263 break;
580c6325 264 case ALTERNATIVE_CHARSET:
9a59ee65 265 print_line(tcs->enter_reverse);
a2811907 266 break;
580c6325 267 case SUPERSCRIPT:
a2811907
SK
268 /*
269 * This only works on a few terminals.
270 * It should be fixed.
271 */
9a59ee65
SK
272 print_line(tcs->enter_underline);
273 print_line(tcs->enter_dim);
a2811907 274 break;
580c6325 275 case SUBSCRIPT:
9a59ee65 276 print_line(tcs->enter_dim);
a2811907 277 break;
580c6325 278 case UNDERLINE:
9a59ee65 279 print_line(tcs->enter_underline);
a2811907
SK
280 break;
281 case BOLD:
9a59ee65 282 print_line(tcs->enter_bold);
a2811907
SK
283 break;
284 default:
285 /*
286 * We should have some provision here for multiple modes
287 * on at once. This will have to come later.
288 */
9a59ee65 289 print_line(tcs->enter_standout);
a2811907 290 break;
a4949aaa 291 }
a4949aaa 292 }
9a59ee65 293 ctl->current_mode = new_mode;
a4949aaa
SK
294}
295
9a59ee65 296static void indicate_attribute(struct ul_ctl *ctl)
6dbe3af9 297{
0186ff36 298 size_t i;
9a59ee65
SK
299 wchar_t *buf = xcalloc(ctl->max_column + 1, sizeof(wchar_t));
300 wchar_t *p = buf;
301
50646353 302 for (i = 0; i < ctl->max_column; i++) {
9a59ee65
SK
303 switch (ctl->buf[i].c_mode) {
304 case NORMAL_CHARSET: *p++ = ' '; break;
305 case ALTERNATIVE_CHARSET: *p++ = 'g'; break;
306 case SUPERSCRIPT: *p++ = '^'; break;
307 case SUBSCRIPT: *p++ = 'v'; break;
308 case UNDERLINE: *p++ = '_'; break;
309 case BOLD: *p++ = '!'; break;
310 default: *p++ = 'X'; break;
66ee8158 311 }
50646353
KZ
312 }
313
9a59ee65
SK
314 for (*p = ' '; *p == ' '; p--)
315 *p = 0;
50646353 316
9a59ee65 317 fputws(buf, stdout);
a2811907 318 putwchar('\n');
9a59ee65 319 free(buf);
6dbe3af9
KZ
320}
321
9a59ee65
SK
322static void output_char(struct ul_ctl *ctl, struct term_caps const *const tcs,
323 wint_t c, int width)
6dbe3af9 324{
5c36a0eb 325 int i;
6dbe3af9 326
a2811907 327 putwchar(c);
9a59ee65 328 if (ctl->must_use_uc && (ctl->current_mode & UNDERLINE)) {
a2811907 329 for (i = 0; i < width; i++)
9a59ee65 330 print_line(tcs->curs_left);
a2811907 331 for (i = 0; i < width; i++)
9a59ee65 332 print_line(tcs->under_char);
6dbe3af9 333 }
6dbe3af9
KZ
334}
335
336/*
337 * For terminals that can overstrike, overstrike underlines and bolds.
338 * We don't do anything with halfline ups and downs, or Greek.
339 */
eaf68e30 340static void overstrike(struct ul_ctl *ctl)
6dbe3af9 341{
0186ff36 342 size_t i;
9a59ee65
SK
343 wchar_t *buf = xcalloc(ctl->max_column + 1, sizeof(wchar_t));
344 wchar_t *p = buf;
345 int had_bold = 0;
6dbe3af9
KZ
346
347 /* Set up overstrike buffer */
50646353 348 for (i = 0; i < ctl->max_column; i++) {
9a59ee65 349 switch (ctl->buf[i].c_mode) {
580c6325 350 case NORMAL_CHARSET:
6dbe3af9 351 default:
9a59ee65 352 *p++ = ' ';
6dbe3af9 353 break;
580c6325 354 case UNDERLINE:
9a59ee65 355 *p++ = '_';
6dbe3af9
KZ
356 break;
357 case BOLD:
9a59ee65 358 *p++ = ctl->buf[i].c_char;
1a3f71b2 359 if (1 < ctl->buf[i].c_width)
9a59ee65
SK
360 i += ctl->buf[i].c_width - 1;
361 had_bold = 1;
6dbe3af9
KZ
362 break;
363 }
50646353
KZ
364 }
365
eb63b9b8 366 putwchar('\r');
9a59ee65
SK
367 for (*p = ' '; *p == ' '; p--)
368 *p = 0;
369 fputws(buf, stdout);
50646353 370
9a59ee65 371 if (had_bold) {
eb63b9b8 372 putwchar('\r');
9a59ee65
SK
373 for (p = buf; *p; p++)
374 putwchar(*p == '_' ? ' ' : *p);
eb63b9b8 375 putwchar('\r');
9a59ee65
SK
376 for (p = buf; *p; p++)
377 putwchar(*p == '_' ? ' ' : *p);
6dbe3af9 378 }
9a59ee65 379 free(buf);
6dbe3af9
KZ
380}
381
9a59ee65 382static void flush_line(struct ul_ctl *ctl, struct term_caps const *const tcs)
6dbe3af9 383{
9a59ee65 384 int last_mode;
0186ff36 385 size_t i;
9a59ee65
SK
386 int had_mode = 0;
387
388 last_mode = NORMAL_CHARSET;
389 for (i = 0; i < ctl->max_column; i++) {
390 if (ctl->buf[i].c_mode != last_mode) {
391 had_mode = 1;
392 ul_setmode(ctl, tcs, ctl->buf[i].c_mode);
393 last_mode = ctl->buf[i].c_mode;
6dbe3af9 394 }
9a59ee65
SK
395 if (ctl->buf[i].c_char == '\0') {
396 if (ctl->up_line)
397 print_line(tcs->curs_right);
a2811907 398 else
9a59ee65 399 output_char(ctl, tcs, ' ', 1);
a2811907 400 } else
9a59ee65 401 output_char(ctl, tcs, ctl->buf[i].c_char, ctl->buf[i].c_width);
1a3f71b2 402 if (1 < ctl->buf[i].c_width)
9a59ee65 403 i += ctl->buf[i].c_width - 1;
a2811907 404 }
9a59ee65
SK
405 if (last_mode != NORMAL_CHARSET)
406 ul_setmode(ctl, tcs, NORMAL_CHARSET);
407 if (ctl->must_overstrike && had_mode)
eaf68e30 408 overstrike(ctl);
eb63b9b8 409 putwchar('\n');
9a59ee65
SK
410 if (ctl->indicated_opt && had_mode)
411 indicate_attribute(ctl);
a2811907 412 fflush(stdout);
9a59ee65
SK
413 if (ctl->up_line)
414 ctl->up_line--;
415 init_buffer(ctl);
6dbe3af9
KZ
416}
417
9a59ee65 418static void forward(struct ul_ctl *ctl, struct term_caps const *const tcs)
6dbe3af9 419{
9a59ee65 420 int old_column, old_maximum;
6dbe3af9 421
9a59ee65
SK
422 old_column = ctl->column;
423 old_maximum = ctl->max_column;
424 flush_line(ctl, tcs);
425 set_column(ctl, old_column);
426 ctl->max_column = old_maximum;
6dbe3af9
KZ
427}
428
eaf68e30 429static void reverse(struct ul_ctl *ctl, struct term_caps const *const tcs)
6dbe3af9 430{
9a59ee65
SK
431 ctl->up_line++;
432 forward(ctl, tcs);
433 print_line(tcs->curs_up);
434 print_line(tcs->curs_up);
435 ctl->up_line++;
6dbe3af9
KZ
436}
437
eaf68e30 438static int handle_escape(struct ul_ctl *ctl, struct term_caps const *const tcs, FILE *f)
6dbe3af9 439{
a2811907 440 wint_t c;
6dbe3af9 441
a2811907
SK
442 switch (c = getwc(f)) {
443 case HREV:
1a3f71b2 444 if (0 < ctl->half_position) {
580c6325 445 ctl->mode &= ~SUBSCRIPT;
9a59ee65 446 ctl->half_position--;
1a3f71b2
SK
447 } else if (ctl->half_position == 0) {
448 ctl->mode |= SUPERSCRIPT;
449 ctl->half_position--;
a2811907 450 } else {
9a59ee65 451 ctl->half_position = 0;
eaf68e30 452 reverse(ctl, tcs);
a2811907
SK
453 }
454 return 0;
455 case HFWD:
1a3f71b2 456 if (ctl->half_position < 0) {
580c6325 457 ctl->mode &= ~SUPERSCRIPT;
9a59ee65 458 ctl->half_position++;
1a3f71b2
SK
459 } else if (ctl->half_position == 0) {
460 ctl->mode |= SUBSCRIPT;
461 ctl->half_position++;
a2811907 462 } else {
9a59ee65
SK
463 ctl->half_position = 0;
464 forward(ctl, tcs);
a2811907
SK
465 }
466 return 0;
467 case FREV:
eaf68e30 468 reverse(ctl, tcs);
a2811907
SK
469 return 0;
470 default:
471 /* unknown escape */
472 ungetwc(c, f);
473 return 1;
6dbe3af9 474 }
6dbe3af9
KZ
475}
476
eaf68e30 477static void filter(struct ul_ctl *ctl, struct term_caps const *const tcs, FILE *f)
5b627d84 478{
a2811907 479 wint_t c;
9a59ee65 480 int i, width;
6dbe3af9 481
a2811907
SK
482 while ((c = getwc(f)) != WEOF) {
483 switch (c) {
484 case '\b':
792ff9fc 485 set_column(ctl, ctl->column && 0 < ctl->column ? ctl->column - 1 : 0);
a2811907
SK
486 continue;
487 case '\t':
9a59ee65 488 set_column(ctl, (ctl->column + 8) & ~07);
a2811907
SK
489 continue;
490 case '\r':
9a59ee65 491 set_column(ctl, 0);
a2811907
SK
492 continue;
493 case SO:
580c6325 494 ctl->mode |= ALTERNATIVE_CHARSET;
a2811907
SK
495 continue;
496 case SI:
580c6325 497 ctl->mode &= ~ALTERNATIVE_CHARSET;
a2811907 498 continue;
9a59ee65 499 case ESC:
eaf68e30 500 if (handle_escape(ctl, tcs, f)) {
a2811907
SK
501 c = getwc(f);
502 errx(EXIT_FAILURE,
9a59ee65 503 _("unknown escape sequence in input: %o, %o"), ESC, c);
6dbe3af9 504 }
a2811907
SK
505 continue;
506 case '_':
9a59ee65 507 if (ctl->buf[ctl->column].c_char || ctl->buf[ctl->column].c_width < 0) {
1a3f71b2 508 while (ctl->buf[ctl->column].c_width < 0 && 0 < ctl->column)
9a59ee65
SK
509 ctl->column--;
510 width = ctl->buf[ctl->column].c_width;
511 for (i = 0; i < width; i++)
512 ctl->buf[ctl->column++].c_mode |= UNDERLINE | ctl->mode;
0186ff36 513 set_column(ctl, 0 < ctl->column ? ctl->column : 0);
a2811907
SK
514 continue;
515 }
9a59ee65
SK
516 ctl->buf[ctl->column].c_char = '_';
517 ctl->buf[ctl->column].c_width = 1;
a2811907
SK
518 /* fallthrough */
519 case ' ':
9a59ee65 520 set_column(ctl, ctl->column + 1);
a2811907
SK
521 continue;
522 case '\n':
9a59ee65 523 flush_line(ctl, tcs);
a2811907
SK
524 continue;
525 case '\f':
9a59ee65 526 flush_line(ctl, tcs);
a2811907
SK
527 putwchar('\f');
528 continue;
6dbe3af9 529 default:
a2811907
SK
530 if (!iswprint(c))
531 /* non printable */
532 continue;
9a59ee65
SK
533 width = wcwidth(c);
534 need_column(ctl, ctl->column + width);
535 if (ctl->buf[ctl->column].c_char == '\0') {
536 ctl->buf[ctl->column].c_char = c;
537 for (i = 0; i < width; i++)
538 ctl->buf[ctl->column + i].c_mode = ctl->mode;
539 ctl->buf[ctl->column].c_width = width;
540 for (i = 1; i < width; i++)
541 ctl->buf[ctl->column + i].c_width = -1;
542 } else if (ctl->buf[ctl->column].c_char == '_') {
543 ctl->buf[ctl->column].c_char = c;
544 for (i = 0; i < width; i++)
545 ctl->buf[ctl->column + i].c_mode |= UNDERLINE | ctl->mode;
546 ctl->buf[ctl->column].c_width = width;
547 for (i = 1; i < width; i++)
548 ctl->buf[ctl->column + i].c_width = -1;
549 } else if ((wint_t) ctl->buf[ctl->column].c_char == c) {
550 for (i = 0; i < width; i++)
551 ctl->buf[ctl->column + i].c_mode |= BOLD | ctl->mode;
a2811907 552 } else {
9a59ee65
SK
553 width = ctl->buf[ctl->column].c_width;
554 for (i = 0; i < width; i++)
555 ctl->buf[ctl->column + i].c_mode = ctl->mode;
a2811907 556 }
9a59ee65 557 set_column(ctl, ctl->column + width);
a2811907 558 continue;
6dbe3af9
KZ
559 }
560 }
9a59ee65
SK
561 if (ctl->max_column)
562 flush_line(ctl, tcs);
6dbe3af9 563}
5c36a0eb 564
a2811907 565int main(int argc, char **argv)
5b627d84 566{
9a59ee65 567 int c, ret, opt_terminal = 0;
a2811907 568 char *termtype;
49421939 569 struct term_caps tcs = { 0 };
9a59ee65 570 struct ul_ctl ctl = { .current_mode = NORMAL_CHARSET };
a2811907 571 FILE *f;
5c36a0eb 572
a2811907
SK
573 static const struct option longopts[] = {
574 { "terminal", required_argument, NULL, 't' },
575 { "indicated", no_argument, NULL, 'i' },
576 { "version", no_argument, NULL, 'V' },
577 { "help", no_argument, NULL, 'h' },
578 { NULL, 0, NULL, 0 }
579 };
5c36a0eb 580
a2811907
SK
581 setlocale(LC_ALL, "");
582 bindtextdomain(PACKAGE, LOCALEDIR);
583 textdomain(PACKAGE);
584 close_stdout_atexit();
66ee8158 585
a2811907
SK
586 signal(SIGINT, sig_handler);
587 signal(SIGTERM, sig_handler);
66ee8158 588
a2811907 589 termtype = getenv("TERM");
66ee8158 590
50646353 591 while ((c = getopt_long(argc, argv, "it:T:Vh", longopts, NULL)) != -1) {
a2811907 592 switch (c) {
4727b169 593
a2811907
SK
594 case 't':
595 case 'T':
596 /* for nroff compatibility */
597 termtype = optarg;
9a59ee65 598 opt_terminal = 1;
a2811907
SK
599 break;
600 case 'i':
9a59ee65 601 ctl.indicated_opt = 1;
a2811907 602 break;
4727b169 603
a2811907
SK
604 case 'V':
605 print_version(EXIT_SUCCESS);
606 case 'h':
607 usage();
608 default:
609 errtryhelp(EXIT_FAILURE);
610 }
50646353
KZ
611 }
612
a2811907
SK
613 setupterm(termtype, STDOUT_FILENO, &ret);
614 switch (ret) {
a2811907
SK
615 case 1:
616 break;
a2811907
SK
617 default:
618 warnx(_("trouble reading terminfo"));
619 /* fallthrough */
a2811907 620 case 0:
9a59ee65 621 if (opt_terminal)
a2811907
SK
622 warnx(_("terminal `%s' is not known, defaulting to `dumb'"),
623 termtype);
624 setupterm("dumb", STDOUT_FILENO, (int *)0);
625 break;
626 }
627
9a59ee65
SK
628 init_term_caps(&ctl, &tcs);
629 init_buffer(&ctl);
50646353 630
a2811907 631 if (optind == argc)
eaf68e30 632 filter(&ctl, &tcs, stdin);
50646353 633 else {
a2811907
SK
634 for (; optind < argc; optind++) {
635 f = fopen(argv[optind], "r");
636 if (!f)
637 err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
eaf68e30 638 filter(&ctl, &tcs, f);
a2811907
SK
639 fclose(f);
640 }
50646353
KZ
641 }
642
9a59ee65 643 free(ctl.buf);
1962d5cf 644 del_curterm(cur_term);
a2811907 645 return EXIT_SUCCESS;
cdbe31fc 646}