diff options
Diffstat (limited to 'text-utils/colcrt.c')
-rw-r--r-- | text-utils/colcrt.c | 419 |
1 files changed, 176 insertions, 243 deletions
diff --git a/text-utils/colcrt.c b/text-utils/colcrt.c index be7f84795..b54da8beb 100644 --- a/text-utils/colcrt.c +++ b/text-utils/colcrt.c @@ -40,26 +40,18 @@ #include <stdio.h> #include <stdlib.h> -#include <unistd.h> /* for close() */ -#include <string.h> #include <getopt.h> -#include "nls.h" +#include "nls.h" #include "widechar.h" #include "c.h" #include "closestream.h" -int plus(wchar_t c, wchar_t d); -void move(int l, int m); -void pflush(int ol); -static void __attribute__ ((__noreturn__)) usage(FILE * out); - /* * colcrt - replaces col for crts with new nroff esp. when using tbl. * Bill Joy UCB July 14, 1977 * - * This filter uses a screen buffer, 267 half-lines by 132 columns. - * It interprets the up and down sequences generated by the new + * This filter uses the up and down sequences generated by the new * nroff when used with tbl and by \u \d and \r. * General overstriking doesn't work correctly. * Underlining is split onto multiple lines, etc. @@ -68,266 +60,207 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out); * Option -2 forces printing of all half lines. */ -#define FLUSH_SIZE 62 -#define PAGE_ARRAY_ROWS 267 -#define PAGE_ARRAY_COLS 132 -wchar_t page[PAGE_ARRAY_ROWS + 1][PAGE_ARRAY_COLS + 1]; - -int outline = 1; -int outcol; +enum { OUTPUT_COLS = 132 }; -char suppresul; -char printall; - -void colcrt(FILE *f); - -int main(int argc, char **argv) { +struct colcrt_control { FILE *f; - int i, opt; - enum { NO_UL_OPTION = CHAR_MAX + 1 }; + wchar_t line[OUTPUT_COLS + 1]; + wchar_t line_under[OUTPUT_COLS + 1]; + unsigned int + print_nl:1, + need_line_under:1, + no_underlining:1, + half_lines:1; +}; - static const struct option longopts[] = { - { "no-underlining", no_argument, 0, NO_UL_OPTION }, - { "half-lines", no_argument, 0, '2' }, - { "version", no_argument, 0, 'V' }, - { "help", no_argument, 0, 'h' }, - { NULL, 0, 0, 0} - }; +static void __attribute__((__noreturn__)) usage(FILE *out) +{ + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name); + fputs(USAGE_SEPARATOR, out); + fputs(_("Filter nroff output for CRT previewing.\n"), out); + fputs(USAGE_OPTIONS, out); + fputs(_(" -, --no-underlining suppress all underlining\n"), out); + fputs(_(" -2, --half-lines print all half-lines\n"), out); + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); + fprintf(out, USAGE_MAN_TAIL("colcrt(1)")); + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - atexit(close_stdout); +static void trim_trailing_spaces(wchar_t *s) +{ + size_t size; + wchar_t *end; - /* Take care of lonely hyphen option. */ - for (i = 0; i < argc; i++) - if (argv[i][0] == '-' && argv[i][1] == '\0') { - suppresul = 1; - argc--; - memmove(argv + i, argv + i + 1, - sizeof(char *) * (argc - i)); - i--; - } + size = wcslen(s); + if (!size) + return; + end = s + size - 1; + while (s <= end && iswspace(*end)) + end--; + *(end + 1) = L'\0'; +} - while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) - switch (opt) { - case NO_UL_OPTION: - suppresul = 1; - break; - case '2': - printall = 1; - break; - case 'V': - printf(UTIL_LINUX_VERSION); - return EXIT_SUCCESS; - case 'h': - usage(stdout); - default: - usage(stderr); - } - argc -= optind; - argv += optind; - do { - if (argc > 0) { - if (!(f = fopen(argv[0], "r"))) { - fflush(stdout); - err(EXIT_FAILURE, "%s", argv[0]); - } - argc--; - argv++; - } else { - f = stdin; - } - colcrt(f); - if (f != stdin) - fclose(f); - } while (argc > 0); - fflush(stdout); - return EXIT_SUCCESS; +static void output_lines(struct colcrt_control *ctl, int col) +{ + /* first line */ + trim_trailing_spaces(ctl->line); + fputws(ctl->line, stdout); + if (ctl->print_nl) + fputwc(L'\n', stdout); + if (!ctl->half_lines && !ctl->no_underlining) + ctl->print_nl = 0; + wmemset(ctl->line, L'\0', OUTPUT_COLS); + /* second line */ + if (ctl->need_line_under) { + ctl->need_line_under = 0; + ctl->line_under[col] = L'\0'; + trim_trailing_spaces(ctl->line_under); + fputws(ctl->line_under, stdout); + fputwc(L'\n', stdout); + wmemset(ctl->line_under, L' ', OUTPUT_COLS); + } else if (ctl->half_lines && 0 < col) + fputwc(L'\n', stdout); } -void colcrt(FILE *f) { +static int rubchars(struct colcrt_control *ctl, int col, int n) +{ + while (0 < n && 0 < col) { + ctl->line[col] = L'\0'; + ctl->line_under[col] = L' '; + n--; + col--; + } + return col; +} + +static void colcrt(struct colcrt_control *ctl) +{ + int col; wint_t c; - wchar_t *cp, *dp; - int i, w; - for (;;) { - c = getwc(f); - if (c == WEOF) { - pflush(outline); - fflush(stdout); - break; + ctl->print_nl = 1; + if (ctl->half_lines) + fputwc(L'\n', stdout); + for (col = 0; /* nothing */; col++) { + if (OUTPUT_COLS - 1 < col) { + output_lines(ctl, col); + errno = 0; + while ((c = getwc(ctl->f)) != L'\n') { + if (errno == 0 && c == WEOF) + return; + else + errno = 0; + } + col = -1; + continue; } + c = getwc(ctl->f); switch (c) { - case '\n': - if (outline >= (PAGE_ARRAY_ROWS - 2)) - pflush(FLUSH_SIZE); - outline += 2; - outcol = 0; - continue; - case '\016': - case '\017': - continue; - case 033: - c = getwc(f); - switch (c) { - case '9': - if (outline >= (PAGE_ARRAY_ROWS - 1)) - pflush(FLUSH_SIZE); - outline++; - continue; - case '8': - if (outline >= 1) - outline--; - continue; - case '7': - outline -= 2; - if (outline < 0) - outline = 0; - continue; - default: + case 033: /* ESC */ + c = getwc(ctl->f); + if (c == L'8') { + col = rubchars(ctl, col, 1); continue; } - case '\b': - if (outcol) - outcol--; - continue; - case '\t': - outcol += 8; - outcol &= ~7; - outcol--; - c = ' '; - /* fallthrough */ - default: - w = wcwidth(c); - if (w < 0) - continue; - if (outcol + w > PAGE_ARRAY_COLS) { - outcol++; + if (c == L'7') { + col = rubchars(ctl, col, 2); continue; } - cp = &page[outline][outcol]; - outcol += w; - if (c == '_') { - if (suppresul) - continue; - cp += PAGE_ARRAY_COLS; - c = '-'; + continue; + case WEOF: + ctl->print_nl = 0; + output_lines(ctl, col); + return; + case L'\n': + output_lines(ctl, col); + col = -1; + continue; + case L'\t': + for (/* nothing */; col % 8 && col < OUTPUT_COLS; col++) { + ctl->line[col] = L' '; } - if (*cp == 0) { - /* trick! */ - for (i = 0; i < w; i++) - cp[i] = c; - dp = cp - (outcol - w); - for (cp--; cp >= dp && *cp == 0; cp--) - *cp = ' '; - } else { - if (plus(c, *cp) || plus(*cp, c)) - *cp = '+'; - else if (*cp == ' ' || *cp == 0) { - for (i = 1; i < w; i++) - if (cp[i] != ' ' && cp[i] != 0) - continue; - for (i = 0; i < w; i++) - cp[i] = c; - } + col--; + continue; + case L'_': + ctl->line[col] = L' '; + if (!ctl->no_underlining) { + ctl->need_line_under = 1; + ctl->line_under[col] = L'-'; } continue; + default: + if (!iswprint(c)) { + col--; + continue; + } + ctl->print_nl = 1; + ctl->line[col] = c; } } } -int plus(wchar_t c, wchar_t d) +int main(int argc, char **argv) { + struct colcrt_control ctl = { 0 }; + int opt; + enum { NO_UL_OPTION = CHAR_MAX + 1 }; - return (c == '|' && (d == '-' || d == '_')); -} - -int first; - -void pflush(int ol) -{ - register int i; - register wchar_t *cp; - char lastomit; - int l, w; + static const struct option longopts[] = { + {"no-underlining", no_argument, NULL, NO_UL_OPTION}, + {"half-lines", no_argument, NULL, '2'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; - l = ol; - lastomit = 0; - if (l > (PAGE_ARRAY_ROWS - 1)) - l = PAGE_ARRAY_ROWS - 1; - else - l |= 1; - for (i = first | 1; i < l; i++) { - move(i, i - 1); - move(i, i + 1); - } - for (i = first; i < l; i++) { - cp = page[i]; - if (printall == 0 && lastomit == 0 && *cp == 0) { - lastomit = 1; - continue; - } - lastomit = 0; - while (*cp) { - if ((w = wcwidth(*cp)) > 0) { - putwchar(*cp); - cp += w; - } else - cp++; + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + /* Take care of lonely hyphen option. */ + for (opt = 0; opt < argc; opt++) + if (argv[opt][0] == '-' && argv[opt][1] == '\0') { + ctl.no_underlining = 1; + argc--; + memmove(argv + opt, argv + opt + 1, + sizeof(char *) * (argc - opt)); + opt--; } - putwchar('\n'); - } - memmove(page, page[ol], (PAGE_ARRAY_ROWS - ol) * PAGE_ARRAY_COLS * sizeof(wchar_t)); - memset(page[PAGE_ARRAY_ROWS - ol], '\0', ol * PAGE_ARRAY_COLS * sizeof(wchar_t)); - outline -= ol; - outcol = 0; - first = 1; -} - -void move(int l, int m) -{ - register wchar_t *cp, *dp; - - for (cp = page[l], dp = page[m]; *cp; cp++, dp++) { - switch (*cp) { - case '|': - if (*dp != ' ' && *dp != '|' && *dp != 0) - return; - break; - case ' ': - break; - default: - return; + while ((opt = getopt_long(argc, argv, "2Vh", longopts, NULL)) != -1) + switch (opt) { + case NO_UL_OPTION: + ctl.no_underlining = 1; + break; + case '2': + ctl.half_lines = 1; + break; + case 'V': + printf(UTIL_LINUX_VERSION); + return EXIT_SUCCESS; + case 'h': + usage(stdout); + default: + usage(stderr); } - } - if (*cp == 0) { - for (cp = page[l], dp = page[m]; *cp; cp++, dp++) - if (*cp == '|') - *dp = '|'; - else if (*dp == 0) - *dp = ' '; - page[l][0] = 0; - } -} - -static void __attribute__ ((__noreturn__)) usage(FILE * out) -{ - fputs(USAGE_HEADER, out); - fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name); - - fputs(USAGE_SEPARATOR, out); - fputs(_("Filter nroff output for CRT previewing.\n"), out); - - fputs(USAGE_OPTIONS, out); - fputs(_(" -, --no-underlining suppress all underlining\n"), out); - fputs(_(" -2, --half-lines print all half-lines\n"), out); - - fputs(USAGE_SEPARATOR, out); - fputs(USAGE_HELP, out); - fputs(USAGE_VERSION, out); - fprintf(out, USAGE_MAN_TAIL("colcrt(1)")); - - exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + argc -= optind; + argv += optind; + do { + wmemset(ctl.line, L'\0', OUTPUT_COLS); + wmemset(ctl.line_under, L' ', OUTPUT_COLS); + if (argc > 0) { + if (!(ctl.f = fopen(argv[0], "r"))) + err(EXIT_FAILURE, _("cannot open %s"), argv[0]); + argc--; + argv++; + } else + ctl.f = stdin; + colcrt(&ctl); + if (ctl.f != stdin) + fclose(ctl.f); + } while (argc > 0); + return EXIT_SUCCESS; } |