1dc5a8425Srobbin /*
2dc5a8425Srobbin * Copyright 2000 Sun Microsystems, Inc. All rights reserved.
3dc5a8425Srobbin * Use is subject to license terms.
4dc5a8425Srobbin */
5dc5a8425Srobbin
67c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
77c478bd9Sstevel@tonic-gate /* All Rights Reserved */
87c478bd9Sstevel@tonic-gate
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
127c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate */
147c478bd9Sstevel@tonic-gate
15*bc54f855SJohn Levon /*
16*bc54f855SJohn Levon * Copyright (c) 2018, Joyent, Inc.
17*bc54f855SJohn Levon */
187c478bd9Sstevel@tonic-gate
197c478bd9Sstevel@tonic-gate #include <stdio.h>
207c478bd9Sstevel@tonic-gate #include <locale.h>
217c478bd9Sstevel@tonic-gate #include <wctype.h>
227c478bd9Sstevel@tonic-gate #include <widec.h>
237c478bd9Sstevel@tonic-gate #include <euc.h>
24dc5a8425Srobbin #include <getwidth.h>
257c478bd9Sstevel@tonic-gate #include <limits.h>
267c478bd9Sstevel@tonic-gate #include <stdlib.h>
27dc5a8425Srobbin #include <curses.h>
28dc5a8425Srobbin #include <term.h>
29dc5a8425Srobbin #include <string.h>
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #define IESC L'\033'
327c478bd9Sstevel@tonic-gate #define SO L'\016'
337c478bd9Sstevel@tonic-gate #define SI L'\017'
347c478bd9Sstevel@tonic-gate #define HFWD L'9'
357c478bd9Sstevel@tonic-gate #define HREV L'8'
367c478bd9Sstevel@tonic-gate #define FREV L'7'
377c478bd9Sstevel@tonic-gate #define CDUMMY -1
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #define NORMAL 000
407c478bd9Sstevel@tonic-gate #define ALTSET 001 /* Reverse */
417c478bd9Sstevel@tonic-gate #define SUPERSC 002 /* Dim */
427c478bd9Sstevel@tonic-gate #define SUBSC 004 /* Dim | Ul */
437c478bd9Sstevel@tonic-gate #define UNDERL 010 /* Ul */
447c478bd9Sstevel@tonic-gate #define BOLD 020 /* Bold */
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #define MEMFCT 16
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate * MEMFCT is a number that is likely to be large enough as a factor for
497c478bd9Sstevel@tonic-gate * allocating more memory and to be small enough so as not wasting memory
507c478bd9Sstevel@tonic-gate */
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate int must_use_uc, must_overstrike;
537c478bd9Sstevel@tonic-gate char *CURS_UP, *CURS_RIGHT, *CURS_LEFT,
547c478bd9Sstevel@tonic-gate *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
557c478bd9Sstevel@tonic-gate *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate struct CHAR {
587c478bd9Sstevel@tonic-gate char c_mode;
597c478bd9Sstevel@tonic-gate wchar_t c_char;
607c478bd9Sstevel@tonic-gate };
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate struct CHAR obuf[LINE_MAX];
637c478bd9Sstevel@tonic-gate int col, maxcol;
647c478bd9Sstevel@tonic-gate int mode;
657c478bd9Sstevel@tonic-gate int halfpos;
667c478bd9Sstevel@tonic-gate int upln;
677c478bd9Sstevel@tonic-gate int iflag;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate eucwidth_t wp;
707c478bd9Sstevel@tonic-gate int scrw[4];
717c478bd9Sstevel@tonic-gate
72dc5a8425Srobbin void setmode(int newmode);
73dc5a8425Srobbin void outc(wchar_t c);
74dc5a8425Srobbin int outchar(char c);
75dc5a8425Srobbin void initcap(void);
76dc5a8425Srobbin void reverse(void);
77dc5a8425Srobbin void fwd(void);
78dc5a8425Srobbin void initbuf(void);
79dc5a8425Srobbin void iattr(void);
80dc5a8425Srobbin void overstrike(void);
81dc5a8425Srobbin void flushln(void);
82dc5a8425Srobbin void ul_filter(FILE *f);
83dc5a8425Srobbin void ul_puts(char *str);
84dc5a8425Srobbin
85dc5a8425Srobbin int
main(int argc,char ** argv)86dc5a8425Srobbin main(int argc, char **argv)
877c478bd9Sstevel@tonic-gate {
887c478bd9Sstevel@tonic-gate int c;
89dc5a8425Srobbin char *termtype;
907c478bd9Sstevel@tonic-gate FILE *f;
917c478bd9Sstevel@tonic-gate char termcap[1024];
927c478bd9Sstevel@tonic-gate extern int optind;
937c478bd9Sstevel@tonic-gate extern char *optarg;
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
967c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
977c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
987c478bd9Sstevel@tonic-gate #endif
997c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate getwidth(&wp);
1027c478bd9Sstevel@tonic-gate scrw[0] = 1;
1037c478bd9Sstevel@tonic-gate scrw[1] = wp._scrw1;
1047c478bd9Sstevel@tonic-gate scrw[2] = wp._scrw2;
1057c478bd9Sstevel@tonic-gate scrw[3] = wp._scrw3;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate termtype = getenv("TERM");
1087c478bd9Sstevel@tonic-gate if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
1097c478bd9Sstevel@tonic-gate termtype = "lpr";
110dc5a8425Srobbin while ((c = getopt(argc, argv, "it:T:")) != EOF)
1117c478bd9Sstevel@tonic-gate switch (c) {
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate case 't':
1147c478bd9Sstevel@tonic-gate case 'T': /* for nroff compatibility */
1157c478bd9Sstevel@tonic-gate termtype = optarg;
1167c478bd9Sstevel@tonic-gate break;
1177c478bd9Sstevel@tonic-gate case 'i':
1187c478bd9Sstevel@tonic-gate iflag = 1;
1197c478bd9Sstevel@tonic-gate break;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate default:
122dc5a8425Srobbin (void) fprintf(stderr,
1237c478bd9Sstevel@tonic-gate gettext("\
1247c478bd9Sstevel@tonic-gate Usage: %s [ -i ] [ -t terminal ] [ filename...]\n"),
1257c478bd9Sstevel@tonic-gate argv[0]);
1267c478bd9Sstevel@tonic-gate exit(1);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate switch (tgetent(termcap, termtype)) {
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate case 1:
1327c478bd9Sstevel@tonic-gate break;
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate default:
135dc5a8425Srobbin (void) fprintf(stderr, gettext("trouble reading termcap"));
136dc5a8425Srobbin /*FALLTHROUGH*/
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate case 0:
1397c478bd9Sstevel@tonic-gate /* No such terminal type - assume dumb */
140dc5a8425Srobbin (void) strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:");
1417c478bd9Sstevel@tonic-gate break;
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate initcap();
144dc5a8425Srobbin if ((tgetflag("os") && ENTER_BOLD == NULL) || (tgetflag("ul") &&
145dc5a8425Srobbin ENTER_UNDERLINE == NULL && UNDER_CHAR == NULL))
1467c478bd9Sstevel@tonic-gate must_overstrike = 1;
1477c478bd9Sstevel@tonic-gate initbuf();
1487c478bd9Sstevel@tonic-gate if (optind == argc)
149dc5a8425Srobbin ul_filter(stdin);
150dc5a8425Srobbin else for (; optind < argc; optind++) {
1517c478bd9Sstevel@tonic-gate f = fopen(argv[optind], "r");
1527c478bd9Sstevel@tonic-gate if (f == NULL) {
1537c478bd9Sstevel@tonic-gate perror(argv[optind]);
1547c478bd9Sstevel@tonic-gate exit(1);
1557c478bd9Sstevel@tonic-gate } else
156dc5a8425Srobbin ul_filter(f);
1577c478bd9Sstevel@tonic-gate }
158dc5a8425Srobbin return (0);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate
161dc5a8425Srobbin void
ul_filter(FILE * f)162dc5a8425Srobbin ul_filter(FILE *f)
1637c478bd9Sstevel@tonic-gate {
164dc5a8425Srobbin wchar_t c;
165dc5a8425Srobbin int i;
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate while ((c = getwc(f)) != EOF) {
168dc5a8425Srobbin if (maxcol >= LINE_MAX) {
169dc5a8425Srobbin (void) fprintf(stderr,
1707c478bd9Sstevel@tonic-gate gettext("Input line longer than %d characters\n"), LINE_MAX);
1717c478bd9Sstevel@tonic-gate exit(1);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate switch (c) {
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate case L'\b':
1767c478bd9Sstevel@tonic-gate if (col > 0)
1777c478bd9Sstevel@tonic-gate col--;
1787c478bd9Sstevel@tonic-gate continue;
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate case L'\t':
1817c478bd9Sstevel@tonic-gate col = (col+8) & ~07;
1827c478bd9Sstevel@tonic-gate if (col > maxcol)
1837c478bd9Sstevel@tonic-gate maxcol = col;
1847c478bd9Sstevel@tonic-gate continue;
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate case L'\r':
1877c478bd9Sstevel@tonic-gate col = 0;
1887c478bd9Sstevel@tonic-gate continue;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate case SO:
1917c478bd9Sstevel@tonic-gate mode |= ALTSET;
1927c478bd9Sstevel@tonic-gate continue;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate case SI:
1957c478bd9Sstevel@tonic-gate mode &= ~ALTSET;
1967c478bd9Sstevel@tonic-gate continue;
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate case IESC:
1997c478bd9Sstevel@tonic-gate switch (c = getwc(f)) {
2007c478bd9Sstevel@tonic-gate case HREV:
2017c478bd9Sstevel@tonic-gate if (halfpos == 0) {
2027c478bd9Sstevel@tonic-gate mode |= SUPERSC;
2037c478bd9Sstevel@tonic-gate halfpos--;
2047c478bd9Sstevel@tonic-gate } else if (halfpos > 0) {
2057c478bd9Sstevel@tonic-gate mode &= ~SUBSC;
2067c478bd9Sstevel@tonic-gate halfpos--;
2077c478bd9Sstevel@tonic-gate } else {
2087c478bd9Sstevel@tonic-gate halfpos = 0;
2097c478bd9Sstevel@tonic-gate reverse();
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate continue;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate case HFWD:
2147c478bd9Sstevel@tonic-gate if (halfpos == 0) {
2157c478bd9Sstevel@tonic-gate mode |= SUBSC;
2167c478bd9Sstevel@tonic-gate halfpos++;
2177c478bd9Sstevel@tonic-gate } else if (halfpos < 0) {
2187c478bd9Sstevel@tonic-gate mode &= ~SUPERSC;
2197c478bd9Sstevel@tonic-gate halfpos++;
2207c478bd9Sstevel@tonic-gate } else {
2217c478bd9Sstevel@tonic-gate halfpos = 0;
2227c478bd9Sstevel@tonic-gate fwd();
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate continue;
2257c478bd9Sstevel@tonic-gate case FREV:
2267c478bd9Sstevel@tonic-gate reverse();
2277c478bd9Sstevel@tonic-gate continue;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate default:
230dc5a8425Srobbin (void) fprintf(stderr,
2317c478bd9Sstevel@tonic-gate gettext("Unknown escape sequence in input: %o, %o\n"),
2327c478bd9Sstevel@tonic-gate IESC, c);
2337c478bd9Sstevel@tonic-gate exit(1);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate continue;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate case L'_':
2387c478bd9Sstevel@tonic-gate if (obuf[col].c_char)
2397c478bd9Sstevel@tonic-gate obuf[col].c_mode |= UNDERL | mode;
2407c478bd9Sstevel@tonic-gate else
2417c478bd9Sstevel@tonic-gate obuf[col].c_char = '_';
242dc5a8425Srobbin /*FALLTHROUGH*/
243dc5a8425Srobbin
2447c478bd9Sstevel@tonic-gate case L' ':
2457c478bd9Sstevel@tonic-gate col++;
2467c478bd9Sstevel@tonic-gate if (col > maxcol)
2477c478bd9Sstevel@tonic-gate maxcol = col;
2487c478bd9Sstevel@tonic-gate continue;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate case L'\n':
2517c478bd9Sstevel@tonic-gate flushln();
2527c478bd9Sstevel@tonic-gate continue;
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate default:
2557c478bd9Sstevel@tonic-gate if (c < L' ') /* non printing */
2567c478bd9Sstevel@tonic-gate continue;
2577c478bd9Sstevel@tonic-gate if (obuf[col].c_char == L'\0') {
2587c478bd9Sstevel@tonic-gate obuf[col].c_char = c;
2597c478bd9Sstevel@tonic-gate obuf[col].c_mode = mode;
2607c478bd9Sstevel@tonic-gate i = scrw[wcsetno(c)];
2617c478bd9Sstevel@tonic-gate while (--i > 0)
2627c478bd9Sstevel@tonic-gate obuf[++col].c_char = CDUMMY;
2637c478bd9Sstevel@tonic-gate } else if (obuf[col].c_char == L'_') {
2647c478bd9Sstevel@tonic-gate obuf[col].c_char = c;
2657c478bd9Sstevel@tonic-gate obuf[col].c_mode |= UNDERL|mode;
2667c478bd9Sstevel@tonic-gate i = scrw[wcsetno(c)];
2677c478bd9Sstevel@tonic-gate while (--i > 0)
2687c478bd9Sstevel@tonic-gate obuf[++col].c_char = CDUMMY;
2697c478bd9Sstevel@tonic-gate } else if (obuf[col].c_char == c)
2707c478bd9Sstevel@tonic-gate obuf[col].c_mode |= BOLD|mode;
2717c478bd9Sstevel@tonic-gate else {
2727c478bd9Sstevel@tonic-gate obuf[col].c_char = c;
2737c478bd9Sstevel@tonic-gate obuf[col].c_mode = mode;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate col++;
2767c478bd9Sstevel@tonic-gate if (col > maxcol)
2777c478bd9Sstevel@tonic-gate maxcol = col;
2787c478bd9Sstevel@tonic-gate continue;
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate if (maxcol)
2827c478bd9Sstevel@tonic-gate flushln();
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
285dc5a8425Srobbin void
flushln(void)286dc5a8425Srobbin flushln(void)
2877c478bd9Sstevel@tonic-gate {
288dc5a8425Srobbin int lastmode;
289dc5a8425Srobbin int i;
2907c478bd9Sstevel@tonic-gate int hadmodes = 0;
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate lastmode = NORMAL;
293dc5a8425Srobbin for (i = 0; i < maxcol; i++) {
2947c478bd9Sstevel@tonic-gate if (obuf[i].c_mode != lastmode) {
2957c478bd9Sstevel@tonic-gate hadmodes++;
2967c478bd9Sstevel@tonic-gate setmode(obuf[i].c_mode);
2977c478bd9Sstevel@tonic-gate lastmode = obuf[i].c_mode;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate if (obuf[i].c_char == L'\0') {
3007c478bd9Sstevel@tonic-gate if (upln) {
301dc5a8425Srobbin ul_puts(CURS_RIGHT);
3027c478bd9Sstevel@tonic-gate } else
3037c478bd9Sstevel@tonic-gate outc(L' ');
3047c478bd9Sstevel@tonic-gate } else
3057c478bd9Sstevel@tonic-gate outc(obuf[i].c_char);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate if (lastmode != NORMAL) {
3087c478bd9Sstevel@tonic-gate setmode(0);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate if (must_overstrike && hadmodes)
3117c478bd9Sstevel@tonic-gate overstrike();
312dc5a8425Srobbin (void) putwchar(L'\n');
3137c478bd9Sstevel@tonic-gate if (iflag && hadmodes)
3147c478bd9Sstevel@tonic-gate iattr();
3157c478bd9Sstevel@tonic-gate if (upln)
3167c478bd9Sstevel@tonic-gate upln--;
3177c478bd9Sstevel@tonic-gate initbuf();
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate * For terminals that can overstrike, overstrike underlines and bolds.
3227c478bd9Sstevel@tonic-gate * We don't do anything with halfline ups and downs, or Greek.
3237c478bd9Sstevel@tonic-gate */
324dc5a8425Srobbin void
overstrike(void)325dc5a8425Srobbin overstrike(void)
3267c478bd9Sstevel@tonic-gate {
327dc5a8425Srobbin int i, n;
3287c478bd9Sstevel@tonic-gate wchar_t *cp, *scp;
3297c478bd9Sstevel@tonic-gate size_t szbf = 256, tszbf;
330dc5a8425Srobbin int hadbold = 0;
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate scp = (wchar_t *)malloc(sizeof (wchar_t) * szbf);
3337c478bd9Sstevel@tonic-gate if (!scp) {
3347c478bd9Sstevel@tonic-gate /* this kind of message need not to be gettext'ed */
3357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n");
3367c478bd9Sstevel@tonic-gate exit(1);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate cp = scp;
3397c478bd9Sstevel@tonic-gate tszbf = szbf;
3407c478bd9Sstevel@tonic-gate #ifdef DEBUG
3417c478bd9Sstevel@tonic-gate /*
3427c478bd9Sstevel@tonic-gate * to allocate a memory after the chunk of the current scp
3437c478bd9Sstevel@tonic-gate * and to make sure the following realloc() allocates
3447c478bd9Sstevel@tonic-gate * memory from different chunks.
3457c478bd9Sstevel@tonic-gate */
3467c478bd9Sstevel@tonic-gate (void) malloc(1024 * 1024);
3477c478bd9Sstevel@tonic-gate #endif
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate /* Set up overstrike buffer */
350dc5a8425Srobbin for (i = 0; i < maxcol; i++) {
3517c478bd9Sstevel@tonic-gate n = scrw[wcsetno(obuf[i].c_char)];
3527c478bd9Sstevel@tonic-gate if (tszbf <= n) {
3537c478bd9Sstevel@tonic-gate /* may not enough buffer for this char */
3547c478bd9Sstevel@tonic-gate size_t pos;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /* obtain the offset of cp */
3577c478bd9Sstevel@tonic-gate pos = cp - scp;
3587c478bd9Sstevel@tonic-gate /* reallocate another (n * MEMFCT) * sizeof (wchar_t) */
3597c478bd9Sstevel@tonic-gate scp = (wchar_t *)realloc(scp,
3607c478bd9Sstevel@tonic-gate sizeof (wchar_t) * (szbf + (n * MEMFCT)));
3617c478bd9Sstevel@tonic-gate if (!scp) {
3627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n");
3637c478bd9Sstevel@tonic-gate exit(1);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate /* get the new address of cp */
3667c478bd9Sstevel@tonic-gate cp = scp + pos;
3677c478bd9Sstevel@tonic-gate szbf += n * MEMFCT;
3687c478bd9Sstevel@tonic-gate tszbf += n * MEMFCT;
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate switch (obuf[i].c_mode) {
3717c478bd9Sstevel@tonic-gate case NORMAL:
3727c478bd9Sstevel@tonic-gate default:
3737c478bd9Sstevel@tonic-gate tszbf -= n;
3747c478bd9Sstevel@tonic-gate *cp++ = L' ';
3757c478bd9Sstevel@tonic-gate while (--n > 0) {
3767c478bd9Sstevel@tonic-gate *cp++ = L' ';
3777c478bd9Sstevel@tonic-gate i++;
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate break;
3807c478bd9Sstevel@tonic-gate case UNDERL:
3817c478bd9Sstevel@tonic-gate tszbf -= n;
3827c478bd9Sstevel@tonic-gate *cp++ = L'_';
3837c478bd9Sstevel@tonic-gate while (--n > 0) {
3847c478bd9Sstevel@tonic-gate *cp++ = L'_';
3857c478bd9Sstevel@tonic-gate i++;
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate break;
3887c478bd9Sstevel@tonic-gate case BOLD:
3897c478bd9Sstevel@tonic-gate tszbf--;
3907c478bd9Sstevel@tonic-gate *cp++ = obuf[i].c_char;
391dc5a8425Srobbin hadbold = 1;
3927c478bd9Sstevel@tonic-gate break;
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate }
395dc5a8425Srobbin (void) putwchar(L'\r');
396dc5a8425Srobbin for (*cp = L' '; *cp == L' '; cp--)
3977c478bd9Sstevel@tonic-gate *cp = L'\0';
398dc5a8425Srobbin for (cp = scp; *cp; cp++)
399dc5a8425Srobbin (void) putwchar(*cp);
4007c478bd9Sstevel@tonic-gate if (hadbold) {
401dc5a8425Srobbin (void) putwchar(L'\r');
402dc5a8425Srobbin for (cp = scp; *cp; cp++)
403dc5a8425Srobbin (void) putwchar(*cp == L'_' ? L' ' : *cp);
404dc5a8425Srobbin (void) putwchar(L'\r');
405dc5a8425Srobbin for (cp = scp; *cp; cp++)
406dc5a8425Srobbin (void) putwchar(*cp == L'_' ? L' ' : *cp);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate free(scp);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
411dc5a8425Srobbin void
iattr(void)412dc5a8425Srobbin iattr(void)
4137c478bd9Sstevel@tonic-gate {
414dc5a8425Srobbin int i, n;
4157c478bd9Sstevel@tonic-gate wchar_t *cp, *scp;
416dc5a8425Srobbin wchar_t cx;
4177c478bd9Sstevel@tonic-gate size_t szbf = 256, tszbf;
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate scp = (wchar_t *)malloc(sizeof (wchar_t) * szbf);
4207c478bd9Sstevel@tonic-gate if (!scp) {
4217c478bd9Sstevel@tonic-gate /* this kind of message need not to be gettext'ed */
4227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n");
4237c478bd9Sstevel@tonic-gate exit(1);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate cp = scp;
4267c478bd9Sstevel@tonic-gate tszbf = szbf;
4277c478bd9Sstevel@tonic-gate #ifdef DEBUG
4287c478bd9Sstevel@tonic-gate /*
4297c478bd9Sstevel@tonic-gate * to allocate a memory after the chunk of the current scp
4307c478bd9Sstevel@tonic-gate * and to make sure the following realloc() allocates
4317c478bd9Sstevel@tonic-gate * memory from different chunks.
4327c478bd9Sstevel@tonic-gate */
4337c478bd9Sstevel@tonic-gate (void) malloc(1024 * 1024);
4347c478bd9Sstevel@tonic-gate #endif
435dc5a8425Srobbin for (i = 0; i < maxcol; i++) {
4367c478bd9Sstevel@tonic-gate switch (obuf[i].c_mode) {
4377c478bd9Sstevel@tonic-gate case NORMAL: cx = ' '; break;
4387c478bd9Sstevel@tonic-gate case ALTSET: cx = 'g'; break;
4397c478bd9Sstevel@tonic-gate case SUPERSC: cx = '^'; break;
4407c478bd9Sstevel@tonic-gate case SUBSC: cx = 'v'; break;
4417c478bd9Sstevel@tonic-gate case UNDERL: cx = '_'; break;
4427c478bd9Sstevel@tonic-gate case BOLD: cx = '!'; break;
4437c478bd9Sstevel@tonic-gate default: cx = 'X'; break;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate n = scrw[wcsetno(obuf[i].c_char)];
4467c478bd9Sstevel@tonic-gate if (tszbf <= n) {
4477c478bd9Sstevel@tonic-gate /* may not enough buffer for this char */
4487c478bd9Sstevel@tonic-gate size_t pos;
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /* obtain the offset of cp */
4517c478bd9Sstevel@tonic-gate pos = cp - scp;
4527c478bd9Sstevel@tonic-gate /* reallocate another (n * MEMFCT) * sizeof (wchar_t) */
4537c478bd9Sstevel@tonic-gate scp = (wchar_t *)realloc(scp,
4547c478bd9Sstevel@tonic-gate sizeof (wchar_t) * (szbf + (n * MEMFCT)));
4557c478bd9Sstevel@tonic-gate if (!scp) {
4567c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n");
4577c478bd9Sstevel@tonic-gate exit(1);
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate /* get the new address of cp */
4607c478bd9Sstevel@tonic-gate cp = scp + pos;
4617c478bd9Sstevel@tonic-gate szbf += n * MEMFCT;
4627c478bd9Sstevel@tonic-gate tszbf += n * MEMFCT;
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate tszbf -= n;
465*bc54f855SJohn Levon *cp++ = cx;
4667c478bd9Sstevel@tonic-gate while (--n > 0) {
4677c478bd9Sstevel@tonic-gate *cp++ = cx;
4687c478bd9Sstevel@tonic-gate i++;
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate }
471dc5a8425Srobbin for (*cp = L' '; *cp == L' '; cp--)
4727c478bd9Sstevel@tonic-gate *cp = L'\0';
473dc5a8425Srobbin for (cp = scp; *cp; cp++)
474dc5a8425Srobbin (void) putwchar(*cp);
475dc5a8425Srobbin (void) putwchar(L'\n');
4767c478bd9Sstevel@tonic-gate free(scp);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
479dc5a8425Srobbin void
initbuf(void)480dc5a8425Srobbin initbuf(void)
4817c478bd9Sstevel@tonic-gate {
482dc5a8425Srobbin int i;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate /* following depends on NORMAL == 000 */
4857c478bd9Sstevel@tonic-gate for (i = 0; i < LINE_MAX; i++)
4867c478bd9Sstevel@tonic-gate obuf[i].c_char = obuf[i].c_mode = 0;
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate col = 0;
4897c478bd9Sstevel@tonic-gate maxcol = 0;
4907c478bd9Sstevel@tonic-gate mode &= ALTSET;
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
493dc5a8425Srobbin void
fwd(void)494dc5a8425Srobbin fwd(void)
4957c478bd9Sstevel@tonic-gate {
496dc5a8425Srobbin int oldcol, oldmax;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate oldcol = col;
4997c478bd9Sstevel@tonic-gate oldmax = maxcol;
5007c478bd9Sstevel@tonic-gate flushln();
5017c478bd9Sstevel@tonic-gate col = oldcol;
5027c478bd9Sstevel@tonic-gate maxcol = oldmax;
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate
505dc5a8425Srobbin void
reverse(void)506dc5a8425Srobbin reverse(void)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate upln++;
5097c478bd9Sstevel@tonic-gate fwd();
510dc5a8425Srobbin ul_puts(CURS_UP);
511dc5a8425Srobbin ul_puts(CURS_UP);
5127c478bd9Sstevel@tonic-gate upln++;
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate
515dc5a8425Srobbin void
initcap(void)516dc5a8425Srobbin initcap(void)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate static char tcapbuf[512];
5197c478bd9Sstevel@tonic-gate char *bp = tcapbuf;
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate /* This nonsense attempts to work with both old and new termcap */
5227c478bd9Sstevel@tonic-gate CURS_UP = tgetstr("up", &bp);
5237c478bd9Sstevel@tonic-gate CURS_RIGHT = tgetstr("ri", &bp);
5247c478bd9Sstevel@tonic-gate if (CURS_RIGHT == NULL)
5257c478bd9Sstevel@tonic-gate CURS_RIGHT = tgetstr("nd", &bp);
5267c478bd9Sstevel@tonic-gate CURS_LEFT = tgetstr("le", &bp);
5277c478bd9Sstevel@tonic-gate if (CURS_LEFT == NULL)
5287c478bd9Sstevel@tonic-gate CURS_LEFT = tgetstr("bc", &bp);
5297c478bd9Sstevel@tonic-gate if (CURS_LEFT == NULL && tgetflag("bs"))
5307c478bd9Sstevel@tonic-gate CURS_LEFT = "\b";
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate ENTER_STANDOUT = tgetstr("so", &bp);
5337c478bd9Sstevel@tonic-gate EXIT_STANDOUT = tgetstr("se", &bp);
5347c478bd9Sstevel@tonic-gate ENTER_UNDERLINE = tgetstr("us", &bp);
5357c478bd9Sstevel@tonic-gate EXIT_UNDERLINE = tgetstr("ue", &bp);
5367c478bd9Sstevel@tonic-gate ENTER_DIM = tgetstr("mh", &bp);
5377c478bd9Sstevel@tonic-gate ENTER_BOLD = tgetstr("md", &bp);
5387c478bd9Sstevel@tonic-gate ENTER_REVERSE = tgetstr("mr", &bp);
5397c478bd9Sstevel@tonic-gate EXIT_ATTRIBUTES = tgetstr("me", &bp);
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate if (!ENTER_BOLD && ENTER_REVERSE)
5427c478bd9Sstevel@tonic-gate ENTER_BOLD = ENTER_REVERSE;
5437c478bd9Sstevel@tonic-gate if (!ENTER_BOLD && ENTER_STANDOUT)
5447c478bd9Sstevel@tonic-gate ENTER_BOLD = ENTER_STANDOUT;
5457c478bd9Sstevel@tonic-gate if (!ENTER_UNDERLINE && ENTER_STANDOUT) {
5467c478bd9Sstevel@tonic-gate ENTER_UNDERLINE = ENTER_STANDOUT;
5477c478bd9Sstevel@tonic-gate EXIT_UNDERLINE = EXIT_STANDOUT;
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate if (!ENTER_DIM && ENTER_STANDOUT)
5507c478bd9Sstevel@tonic-gate ENTER_DIM = ENTER_STANDOUT;
5517c478bd9Sstevel@tonic-gate if (!ENTER_REVERSE && ENTER_STANDOUT)
5527c478bd9Sstevel@tonic-gate ENTER_REVERSE = ENTER_STANDOUT;
5537c478bd9Sstevel@tonic-gate if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
5547c478bd9Sstevel@tonic-gate EXIT_ATTRIBUTES = EXIT_STANDOUT;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate * Note that we use REVERSE for the alternate character set,
5587c478bd9Sstevel@tonic-gate * not the as/ae capabilities. This is because we are modelling
5597c478bd9Sstevel@tonic-gate * the model 37 teletype (since that's what nroff outputs) and
5607c478bd9Sstevel@tonic-gate * the typical as/ae is more of a graphics set, not the greek
5617c478bd9Sstevel@tonic-gate * letters the 37 has.
5627c478bd9Sstevel@tonic-gate */
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate #ifdef notdef
5657c478bd9Sstevel@tonic-gate printf("so %s se %s us %s ue %s me %s\n",
5667c478bd9Sstevel@tonic-gate ENTER_STANDOUT, EXIT_STANDOUT, ENTER_UNDERLINE,
5677c478bd9Sstevel@tonic-gate EXIT_UNDERLINE, EXIT_ATTRIBUTES);
5687c478bd9Sstevel@tonic-gate #endif
5697c478bd9Sstevel@tonic-gate UNDER_CHAR = tgetstr("uc", &bp);
5707c478bd9Sstevel@tonic-gate must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate
573dc5a8425Srobbin int
outchar(char c)574dc5a8425Srobbin outchar(char c)
5757c478bd9Sstevel@tonic-gate {
576dc5a8425Srobbin (void) putchar(c&0177);
577dc5a8425Srobbin return (0);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
580dc5a8425Srobbin void
ul_puts(char * str)581dc5a8425Srobbin ul_puts(char *str)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate if (str)
584dc5a8425Srobbin (void) tputs(str, 1, outchar);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
587dc5a8425Srobbin static int curmode = 0;
588dc5a8425Srobbin
589dc5a8425Srobbin void
outc(wchar_t c)590dc5a8425Srobbin outc(wchar_t c)
5917c478bd9Sstevel@tonic-gate {
592dc5a8425Srobbin int m, n;
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if (c == CDUMMY)
5957c478bd9Sstevel@tonic-gate return;
596dc5a8425Srobbin (void) putwchar(c);
5977c478bd9Sstevel@tonic-gate if (must_use_uc && (curmode & UNDERL)) {
5987c478bd9Sstevel@tonic-gate m = n = scrw[wcsetno(c)];
599dc5a8425Srobbin ul_puts(CURS_LEFT);
6007c478bd9Sstevel@tonic-gate while (--m > 0)
601dc5a8425Srobbin ul_puts(CURS_LEFT);
602dc5a8425Srobbin ul_puts(UNDER_CHAR);
6037c478bd9Sstevel@tonic-gate while (--n > 0)
604dc5a8425Srobbin ul_puts(UNDER_CHAR);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate
608dc5a8425Srobbin void
setmode(int newmode)609dc5a8425Srobbin setmode(int newmode)
6107c478bd9Sstevel@tonic-gate {
611dc5a8425Srobbin if (!iflag) {
6127c478bd9Sstevel@tonic-gate if (curmode != NORMAL && newmode != NORMAL)
6137c478bd9Sstevel@tonic-gate setmode(NORMAL);
6147c478bd9Sstevel@tonic-gate switch (newmode) {
6157c478bd9Sstevel@tonic-gate case NORMAL:
6167c478bd9Sstevel@tonic-gate switch (curmode) {
6177c478bd9Sstevel@tonic-gate case NORMAL:
6187c478bd9Sstevel@tonic-gate break;
6197c478bd9Sstevel@tonic-gate case UNDERL:
620dc5a8425Srobbin ul_puts(EXIT_UNDERLINE);
6217c478bd9Sstevel@tonic-gate break;
6227c478bd9Sstevel@tonic-gate default:
6237c478bd9Sstevel@tonic-gate /* This includes standout */
624dc5a8425Srobbin ul_puts(EXIT_ATTRIBUTES);
6257c478bd9Sstevel@tonic-gate break;
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate break;
6287c478bd9Sstevel@tonic-gate case ALTSET:
629dc5a8425Srobbin ul_puts(ENTER_REVERSE);
6307c478bd9Sstevel@tonic-gate break;
6317c478bd9Sstevel@tonic-gate case SUPERSC:
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate * This only works on a few terminals.
6347c478bd9Sstevel@tonic-gate * It should be fixed.
6357c478bd9Sstevel@tonic-gate */
636dc5a8425Srobbin ul_puts(ENTER_UNDERLINE);
637dc5a8425Srobbin ul_puts(ENTER_DIM);
6387c478bd9Sstevel@tonic-gate break;
6397c478bd9Sstevel@tonic-gate case SUBSC:
640dc5a8425Srobbin ul_puts(ENTER_DIM);
6417c478bd9Sstevel@tonic-gate break;
6427c478bd9Sstevel@tonic-gate case UNDERL:
643dc5a8425Srobbin ul_puts(ENTER_UNDERLINE);
6447c478bd9Sstevel@tonic-gate break;
6457c478bd9Sstevel@tonic-gate case BOLD:
646dc5a8425Srobbin ul_puts(ENTER_BOLD);
6477c478bd9Sstevel@tonic-gate break;
6487c478bd9Sstevel@tonic-gate default:
6497c478bd9Sstevel@tonic-gate /*
6507c478bd9Sstevel@tonic-gate * We should have some provision here for multiple modes
6517c478bd9Sstevel@tonic-gate * on at once. This will have to come later.
6527c478bd9Sstevel@tonic-gate */
653dc5a8425Srobbin ul_puts(ENTER_STANDOUT);
6547c478bd9Sstevel@tonic-gate break;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate curmode = newmode;
6587c478bd9Sstevel@tonic-gate }
659