summaryrefslogtreecommitdiffstats
path: root/text-utils/colcrt.c
diff options
context:
space:
mode:
Diffstat (limited to 'text-utils/colcrt.c')
-rw-r--r--text-utils/colcrt.c419
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;
}