1*dc5a8425Srobbin /* 2*dc5a8425Srobbin * Copyright 2000 Sun Microsystems, Inc. All rights reserved. 3*dc5a8425Srobbin * Use is subject to license terms. 4*dc5a8425Srobbin */ 5*dc5a8425Srobbin 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*dc5a8425Srobbin #pragma ident "%Z%%M% %I% %E% SMI" 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate #include <stdio.h> 187c478bd9Sstevel@tonic-gate #include <locale.h> 197c478bd9Sstevel@tonic-gate #include <wctype.h> 207c478bd9Sstevel@tonic-gate #include <widec.h> 217c478bd9Sstevel@tonic-gate #include <euc.h> 22*dc5a8425Srobbin #include <getwidth.h> 237c478bd9Sstevel@tonic-gate #include <limits.h> 247c478bd9Sstevel@tonic-gate #include <stdlib.h> 25*dc5a8425Srobbin #include <curses.h> 26*dc5a8425Srobbin #include <term.h> 27*dc5a8425Srobbin #include <string.h> 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #define IESC L'\033' 307c478bd9Sstevel@tonic-gate #define SO L'\016' 317c478bd9Sstevel@tonic-gate #define SI L'\017' 327c478bd9Sstevel@tonic-gate #define HFWD L'9' 337c478bd9Sstevel@tonic-gate #define HREV L'8' 347c478bd9Sstevel@tonic-gate #define FREV L'7' 357c478bd9Sstevel@tonic-gate #define CDUMMY -1 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #define NORMAL 000 387c478bd9Sstevel@tonic-gate #define ALTSET 001 /* Reverse */ 397c478bd9Sstevel@tonic-gate #define SUPERSC 002 /* Dim */ 407c478bd9Sstevel@tonic-gate #define SUBSC 004 /* Dim | Ul */ 417c478bd9Sstevel@tonic-gate #define UNDERL 010 /* Ul */ 427c478bd9Sstevel@tonic-gate #define BOLD 020 /* Bold */ 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #define MEMFCT 16 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * MEMFCT is a number that is likely to be large enough as a factor for 477c478bd9Sstevel@tonic-gate * allocating more memory and to be small enough so as not wasting memory 487c478bd9Sstevel@tonic-gate */ 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate int must_use_uc, must_overstrike; 517c478bd9Sstevel@tonic-gate char *CURS_UP, *CURS_RIGHT, *CURS_LEFT, 527c478bd9Sstevel@tonic-gate *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE, 537c478bd9Sstevel@tonic-gate *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate struct CHAR { 567c478bd9Sstevel@tonic-gate char c_mode; 577c478bd9Sstevel@tonic-gate wchar_t c_char; 587c478bd9Sstevel@tonic-gate }; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate struct CHAR obuf[LINE_MAX]; 617c478bd9Sstevel@tonic-gate int col, maxcol; 627c478bd9Sstevel@tonic-gate int mode; 637c478bd9Sstevel@tonic-gate int halfpos; 647c478bd9Sstevel@tonic-gate int upln; 657c478bd9Sstevel@tonic-gate int iflag; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate eucwidth_t wp; 687c478bd9Sstevel@tonic-gate int scrw[4]; 697c478bd9Sstevel@tonic-gate 70*dc5a8425Srobbin void setmode(int newmode); 71*dc5a8425Srobbin void outc(wchar_t c); 72*dc5a8425Srobbin int outchar(char c); 73*dc5a8425Srobbin void initcap(void); 74*dc5a8425Srobbin void reverse(void); 75*dc5a8425Srobbin void fwd(void); 76*dc5a8425Srobbin void initbuf(void); 77*dc5a8425Srobbin void iattr(void); 78*dc5a8425Srobbin void overstrike(void); 79*dc5a8425Srobbin void flushln(void); 80*dc5a8425Srobbin void ul_filter(FILE *f); 81*dc5a8425Srobbin void ul_puts(char *str); 82*dc5a8425Srobbin 83*dc5a8425Srobbin int 84*dc5a8425Srobbin main(int argc, char **argv) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate int c; 87*dc5a8425Srobbin char *termtype; 887c478bd9Sstevel@tonic-gate FILE *f; 897c478bd9Sstevel@tonic-gate char termcap[1024]; 907c478bd9Sstevel@tonic-gate extern int optind; 917c478bd9Sstevel@tonic-gate extern char *optarg; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 947c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 957c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 967c478bd9Sstevel@tonic-gate #endif 977c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate getwidth(&wp); 1007c478bd9Sstevel@tonic-gate scrw[0] = 1; 1017c478bd9Sstevel@tonic-gate scrw[1] = wp._scrw1; 1027c478bd9Sstevel@tonic-gate scrw[2] = wp._scrw2; 1037c478bd9Sstevel@tonic-gate scrw[3] = wp._scrw3; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate termtype = getenv("TERM"); 1067c478bd9Sstevel@tonic-gate if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) 1077c478bd9Sstevel@tonic-gate termtype = "lpr"; 1087c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "it:T:")) != EOF) 1097c478bd9Sstevel@tonic-gate switch (c) { 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate case 't': 1127c478bd9Sstevel@tonic-gate case 'T': /* for nroff compatibility */ 1137c478bd9Sstevel@tonic-gate termtype = optarg; 1147c478bd9Sstevel@tonic-gate break; 1157c478bd9Sstevel@tonic-gate case 'i': 1167c478bd9Sstevel@tonic-gate iflag = 1; 1177c478bd9Sstevel@tonic-gate break; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate default: 120*dc5a8425Srobbin (void) fprintf(stderr, 1217c478bd9Sstevel@tonic-gate gettext("\ 1227c478bd9Sstevel@tonic-gate Usage: %s [ -i ] [ -t terminal ] [ filename...]\n"), 1237c478bd9Sstevel@tonic-gate argv[0]); 1247c478bd9Sstevel@tonic-gate exit(1); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate switch (tgetent(termcap, termtype)) { 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate case 1: 1307c478bd9Sstevel@tonic-gate break; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate default: 133*dc5a8425Srobbin (void) fprintf(stderr, gettext("trouble reading termcap")); 134*dc5a8425Srobbin /*FALLTHROUGH*/ 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate case 0: 1377c478bd9Sstevel@tonic-gate /* No such terminal type - assume dumb */ 138*dc5a8425Srobbin (void) strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:"); 1397c478bd9Sstevel@tonic-gate break; 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate initcap(); 142*dc5a8425Srobbin if ((tgetflag("os") && ENTER_BOLD == NULL) || (tgetflag("ul") && 143*dc5a8425Srobbin ENTER_UNDERLINE == NULL && UNDER_CHAR == NULL)) 1447c478bd9Sstevel@tonic-gate must_overstrike = 1; 1457c478bd9Sstevel@tonic-gate initbuf(); 1467c478bd9Sstevel@tonic-gate if (optind == argc) 147*dc5a8425Srobbin ul_filter(stdin); 1487c478bd9Sstevel@tonic-gate else for (; optind < argc; optind++) { 1497c478bd9Sstevel@tonic-gate f = fopen(argv[optind], "r"); 1507c478bd9Sstevel@tonic-gate if (f == NULL) { 1517c478bd9Sstevel@tonic-gate perror(argv[optind]); 1527c478bd9Sstevel@tonic-gate exit(1); 1537c478bd9Sstevel@tonic-gate } else 154*dc5a8425Srobbin ul_filter(f); 1557c478bd9Sstevel@tonic-gate } 156*dc5a8425Srobbin return (0); 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 159*dc5a8425Srobbin void 160*dc5a8425Srobbin ul_filter(FILE *f) 1617c478bd9Sstevel@tonic-gate { 162*dc5a8425Srobbin wchar_t c; 163*dc5a8425Srobbin int i; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate while ((c = getwc(f)) != EOF) { 166*dc5a8425Srobbin if (maxcol >= LINE_MAX) { 167*dc5a8425Srobbin (void) fprintf(stderr, 1687c478bd9Sstevel@tonic-gate gettext("Input line longer than %d characters\n"), LINE_MAX); 1697c478bd9Sstevel@tonic-gate exit(1); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate switch (c) { 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate case L'\b': 1747c478bd9Sstevel@tonic-gate if (col > 0) 1757c478bd9Sstevel@tonic-gate col--; 1767c478bd9Sstevel@tonic-gate continue; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate case L'\t': 1797c478bd9Sstevel@tonic-gate col = (col+8) & ~07; 1807c478bd9Sstevel@tonic-gate if (col > maxcol) 1817c478bd9Sstevel@tonic-gate maxcol = col; 1827c478bd9Sstevel@tonic-gate continue; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate case L'\r': 1857c478bd9Sstevel@tonic-gate col = 0; 1867c478bd9Sstevel@tonic-gate continue; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate case SO: 1897c478bd9Sstevel@tonic-gate mode |= ALTSET; 1907c478bd9Sstevel@tonic-gate continue; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate case SI: 1937c478bd9Sstevel@tonic-gate mode &= ~ALTSET; 1947c478bd9Sstevel@tonic-gate continue; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate case IESC: 1977c478bd9Sstevel@tonic-gate switch (c = getwc(f)) { 1987c478bd9Sstevel@tonic-gate case HREV: 1997c478bd9Sstevel@tonic-gate if (halfpos == 0) { 2007c478bd9Sstevel@tonic-gate mode |= SUPERSC; 2017c478bd9Sstevel@tonic-gate halfpos--; 2027c478bd9Sstevel@tonic-gate } else if (halfpos > 0) { 2037c478bd9Sstevel@tonic-gate mode &= ~SUBSC; 2047c478bd9Sstevel@tonic-gate halfpos--; 2057c478bd9Sstevel@tonic-gate } else { 2067c478bd9Sstevel@tonic-gate halfpos = 0; 2077c478bd9Sstevel@tonic-gate reverse(); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate continue; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate case HFWD: 2127c478bd9Sstevel@tonic-gate if (halfpos == 0) { 2137c478bd9Sstevel@tonic-gate mode |= SUBSC; 2147c478bd9Sstevel@tonic-gate halfpos++; 2157c478bd9Sstevel@tonic-gate } else if (halfpos < 0) { 2167c478bd9Sstevel@tonic-gate mode &= ~SUPERSC; 2177c478bd9Sstevel@tonic-gate halfpos++; 2187c478bd9Sstevel@tonic-gate } else { 2197c478bd9Sstevel@tonic-gate halfpos = 0; 2207c478bd9Sstevel@tonic-gate fwd(); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate continue; 2237c478bd9Sstevel@tonic-gate case FREV: 2247c478bd9Sstevel@tonic-gate reverse(); 2257c478bd9Sstevel@tonic-gate continue; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate default: 228*dc5a8425Srobbin (void) fprintf(stderr, 2297c478bd9Sstevel@tonic-gate gettext("Unknown escape sequence in input: %o, %o\n"), 2307c478bd9Sstevel@tonic-gate IESC, c); 2317c478bd9Sstevel@tonic-gate exit(1); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate continue; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate case L'_': 2367c478bd9Sstevel@tonic-gate if (obuf[col].c_char) 2377c478bd9Sstevel@tonic-gate obuf[col].c_mode |= UNDERL | mode; 2387c478bd9Sstevel@tonic-gate else 2397c478bd9Sstevel@tonic-gate obuf[col].c_char = '_'; 240*dc5a8425Srobbin /*FALLTHROUGH*/ 241*dc5a8425Srobbin 2427c478bd9Sstevel@tonic-gate case L' ': 2437c478bd9Sstevel@tonic-gate col++; 2447c478bd9Sstevel@tonic-gate if (col > maxcol) 2457c478bd9Sstevel@tonic-gate maxcol = col; 2467c478bd9Sstevel@tonic-gate continue; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate case L'\n': 2497c478bd9Sstevel@tonic-gate flushln(); 2507c478bd9Sstevel@tonic-gate continue; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate default: 2537c478bd9Sstevel@tonic-gate if (c < L' ') /* non printing */ 2547c478bd9Sstevel@tonic-gate continue; 2557c478bd9Sstevel@tonic-gate if (obuf[col].c_char == L'\0') { 2567c478bd9Sstevel@tonic-gate obuf[col].c_char = c; 2577c478bd9Sstevel@tonic-gate obuf[col].c_mode = mode; 2587c478bd9Sstevel@tonic-gate i = scrw[wcsetno(c)]; 2597c478bd9Sstevel@tonic-gate while (--i > 0) 2607c478bd9Sstevel@tonic-gate obuf[++col].c_char = CDUMMY; 2617c478bd9Sstevel@tonic-gate } else if (obuf[col].c_char == L'_') { 2627c478bd9Sstevel@tonic-gate obuf[col].c_char = c; 2637c478bd9Sstevel@tonic-gate obuf[col].c_mode |= UNDERL|mode; 2647c478bd9Sstevel@tonic-gate i = scrw[wcsetno(c)]; 2657c478bd9Sstevel@tonic-gate while (--i > 0) 2667c478bd9Sstevel@tonic-gate obuf[++col].c_char = CDUMMY; 2677c478bd9Sstevel@tonic-gate } else if (obuf[col].c_char == c) 2687c478bd9Sstevel@tonic-gate obuf[col].c_mode |= BOLD|mode; 2697c478bd9Sstevel@tonic-gate else { 2707c478bd9Sstevel@tonic-gate obuf[col].c_char = c; 2717c478bd9Sstevel@tonic-gate obuf[col].c_mode = mode; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate col++; 2747c478bd9Sstevel@tonic-gate if (col > maxcol) 2757c478bd9Sstevel@tonic-gate maxcol = col; 2767c478bd9Sstevel@tonic-gate continue; 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate if (maxcol) 2807c478bd9Sstevel@tonic-gate flushln(); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 283*dc5a8425Srobbin void 284*dc5a8425Srobbin flushln(void) 2857c478bd9Sstevel@tonic-gate { 286*dc5a8425Srobbin int lastmode; 287*dc5a8425Srobbin int i; 2887c478bd9Sstevel@tonic-gate int hadmodes = 0; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate lastmode = NORMAL; 2917c478bd9Sstevel@tonic-gate for (i = 0; i < maxcol; i++) { 2927c478bd9Sstevel@tonic-gate if (obuf[i].c_mode != lastmode) { 2937c478bd9Sstevel@tonic-gate hadmodes++; 2947c478bd9Sstevel@tonic-gate setmode(obuf[i].c_mode); 2957c478bd9Sstevel@tonic-gate lastmode = obuf[i].c_mode; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate if (obuf[i].c_char == L'\0') { 2987c478bd9Sstevel@tonic-gate if (upln) { 299*dc5a8425Srobbin ul_puts(CURS_RIGHT); 3007c478bd9Sstevel@tonic-gate } else 3017c478bd9Sstevel@tonic-gate outc(L' '); 3027c478bd9Sstevel@tonic-gate } else 3037c478bd9Sstevel@tonic-gate outc(obuf[i].c_char); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate if (lastmode != NORMAL) { 3067c478bd9Sstevel@tonic-gate setmode(0); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate if (must_overstrike && hadmodes) 3097c478bd9Sstevel@tonic-gate overstrike(); 310*dc5a8425Srobbin (void) putwchar(L'\n'); 3117c478bd9Sstevel@tonic-gate if (iflag && hadmodes) 3127c478bd9Sstevel@tonic-gate iattr(); 3137c478bd9Sstevel@tonic-gate if (upln) 3147c478bd9Sstevel@tonic-gate upln--; 3157c478bd9Sstevel@tonic-gate initbuf(); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * For terminals that can overstrike, overstrike underlines and bolds. 3207c478bd9Sstevel@tonic-gate * We don't do anything with halfline ups and downs, or Greek. 3217c478bd9Sstevel@tonic-gate */ 322*dc5a8425Srobbin void 323*dc5a8425Srobbin overstrike(void) 3247c478bd9Sstevel@tonic-gate { 325*dc5a8425Srobbin int i, n; 3267c478bd9Sstevel@tonic-gate wchar_t *cp, *scp; 3277c478bd9Sstevel@tonic-gate size_t szbf = 256, tszbf; 3287c478bd9Sstevel@tonic-gate int hadbold = 0; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate scp = (wchar_t *)malloc(sizeof (wchar_t) * szbf); 3317c478bd9Sstevel@tonic-gate if (!scp) { 3327c478bd9Sstevel@tonic-gate /* this kind of message need not to be gettext'ed */ 3337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n"); 3347c478bd9Sstevel@tonic-gate exit(1); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate cp = scp; 3377c478bd9Sstevel@tonic-gate tszbf = szbf; 3387c478bd9Sstevel@tonic-gate #ifdef DEBUG 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * to allocate a memory after the chunk of the current scp 3417c478bd9Sstevel@tonic-gate * and to make sure the following realloc() allocates 3427c478bd9Sstevel@tonic-gate * memory from different chunks. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate (void) malloc(1024 * 1024); 3457c478bd9Sstevel@tonic-gate #endif 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* Set up overstrike buffer */ 3487c478bd9Sstevel@tonic-gate for (i = 0; i < maxcol; i++) { 3497c478bd9Sstevel@tonic-gate n = scrw[wcsetno(obuf[i].c_char)]; 3507c478bd9Sstevel@tonic-gate if (tszbf <= n) { 3517c478bd9Sstevel@tonic-gate /* may not enough buffer for this char */ 3527c478bd9Sstevel@tonic-gate size_t pos; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* obtain the offset of cp */ 3557c478bd9Sstevel@tonic-gate pos = cp - scp; 3567c478bd9Sstevel@tonic-gate /* reallocate another (n * MEMFCT) * sizeof (wchar_t) */ 3577c478bd9Sstevel@tonic-gate scp = (wchar_t *)realloc(scp, 3587c478bd9Sstevel@tonic-gate sizeof (wchar_t) * (szbf + (n * MEMFCT))); 3597c478bd9Sstevel@tonic-gate if (!scp) { 3607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n"); 3617c478bd9Sstevel@tonic-gate exit(1); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate /* get the new address of cp */ 3647c478bd9Sstevel@tonic-gate cp = scp + pos; 3657c478bd9Sstevel@tonic-gate szbf += n * MEMFCT; 3667c478bd9Sstevel@tonic-gate tszbf += n * MEMFCT; 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate switch (obuf[i].c_mode) { 3697c478bd9Sstevel@tonic-gate case NORMAL: 3707c478bd9Sstevel@tonic-gate default: 3717c478bd9Sstevel@tonic-gate tszbf -= n; 3727c478bd9Sstevel@tonic-gate *cp++ = L' '; 3737c478bd9Sstevel@tonic-gate while (--n > 0) { 3747c478bd9Sstevel@tonic-gate *cp++ = L' '; 3757c478bd9Sstevel@tonic-gate i++; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate break; 3787c478bd9Sstevel@tonic-gate case UNDERL: 3797c478bd9Sstevel@tonic-gate tszbf -= n; 3807c478bd9Sstevel@tonic-gate *cp++ = L'_'; 3817c478bd9Sstevel@tonic-gate while (--n > 0) { 3827c478bd9Sstevel@tonic-gate *cp++ = L'_'; 3837c478bd9Sstevel@tonic-gate i++; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate break; 3867c478bd9Sstevel@tonic-gate case BOLD: 3877c478bd9Sstevel@tonic-gate tszbf--; 3887c478bd9Sstevel@tonic-gate *cp++ = obuf[i].c_char; 3897c478bd9Sstevel@tonic-gate hadbold = 1; 3907c478bd9Sstevel@tonic-gate break; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate } 393*dc5a8425Srobbin (void) putwchar(L'\r'); 3947c478bd9Sstevel@tonic-gate for (*cp = L' '; *cp == L' '; cp--) 3957c478bd9Sstevel@tonic-gate *cp = L'\0'; 3967c478bd9Sstevel@tonic-gate for (cp = scp; *cp; cp++) 397*dc5a8425Srobbin (void) putwchar(*cp); 3987c478bd9Sstevel@tonic-gate if (hadbold) { 399*dc5a8425Srobbin (void) putwchar(L'\r'); 4007c478bd9Sstevel@tonic-gate for (cp = scp; *cp; cp++) 401*dc5a8425Srobbin (void) putwchar(*cp == L'_' ? L' ' : *cp); 402*dc5a8425Srobbin (void) putwchar(L'\r'); 4037c478bd9Sstevel@tonic-gate for (cp = scp; *cp; cp++) 404*dc5a8425Srobbin (void) putwchar(*cp == L'_' ? L' ' : *cp); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate free(scp); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 409*dc5a8425Srobbin void 410*dc5a8425Srobbin iattr(void) 4117c478bd9Sstevel@tonic-gate { 412*dc5a8425Srobbin int i, n; 4137c478bd9Sstevel@tonic-gate wchar_t *cp, *scp; 414*dc5a8425Srobbin wchar_t cx; 4157c478bd9Sstevel@tonic-gate size_t szbf = 256, tszbf; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate scp = (wchar_t *)malloc(sizeof (wchar_t) * szbf); 4187c478bd9Sstevel@tonic-gate if (!scp) { 4197c478bd9Sstevel@tonic-gate /* this kind of message need not to be gettext'ed */ 4207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n"); 4217c478bd9Sstevel@tonic-gate exit(1); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate cp = scp; 4247c478bd9Sstevel@tonic-gate tszbf = szbf; 4257c478bd9Sstevel@tonic-gate #ifdef DEBUG 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * to allocate a memory after the chunk of the current scp 4287c478bd9Sstevel@tonic-gate * and to make sure the following realloc() allocates 4297c478bd9Sstevel@tonic-gate * memory from different chunks. 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate (void) malloc(1024 * 1024); 4327c478bd9Sstevel@tonic-gate #endif 4337c478bd9Sstevel@tonic-gate for (i = 0; i < maxcol; i++) { 4347c478bd9Sstevel@tonic-gate switch (obuf[i].c_mode) { 4357c478bd9Sstevel@tonic-gate case NORMAL: cx = ' '; break; 4367c478bd9Sstevel@tonic-gate case ALTSET: cx = 'g'; break; 4377c478bd9Sstevel@tonic-gate case SUPERSC: cx = '^'; break; 4387c478bd9Sstevel@tonic-gate case SUBSC: cx = 'v'; break; 4397c478bd9Sstevel@tonic-gate case UNDERL: cx = '_'; break; 4407c478bd9Sstevel@tonic-gate case BOLD: cx = '!'; break; 4417c478bd9Sstevel@tonic-gate default: cx = 'X'; break; 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate n = scrw[wcsetno(obuf[i].c_char)]; 4447c478bd9Sstevel@tonic-gate if (tszbf <= n) { 4457c478bd9Sstevel@tonic-gate /* may not enough buffer for this char */ 4467c478bd9Sstevel@tonic-gate size_t pos; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* obtain the offset of cp */ 4497c478bd9Sstevel@tonic-gate pos = cp - scp; 4507c478bd9Sstevel@tonic-gate /* reallocate another (n * MEMFCT) * sizeof (wchar_t) */ 4517c478bd9Sstevel@tonic-gate scp = (wchar_t *)realloc(scp, 4527c478bd9Sstevel@tonic-gate sizeof (wchar_t) * (szbf + (n * MEMFCT))); 4537c478bd9Sstevel@tonic-gate if (!scp) { 4547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "malloc failed\n"); 4557c478bd9Sstevel@tonic-gate exit(1); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate /* get the new address of cp */ 4587c478bd9Sstevel@tonic-gate cp = scp + pos; 4597c478bd9Sstevel@tonic-gate szbf += n * MEMFCT; 4607c478bd9Sstevel@tonic-gate tszbf += n * MEMFCT; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate tszbf -= n; 4637c478bd9Sstevel@tonic-gate *cp++ = cx; 4647c478bd9Sstevel@tonic-gate while (--n > 0) { 4657c478bd9Sstevel@tonic-gate *cp++ = cx; 4667c478bd9Sstevel@tonic-gate i++; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate for (*cp = L' '; *cp == L' '; cp--) 4707c478bd9Sstevel@tonic-gate *cp = L'\0'; 4717c478bd9Sstevel@tonic-gate for (cp = scp; *cp; cp++) 472*dc5a8425Srobbin (void) putwchar(*cp); 473*dc5a8425Srobbin (void) putwchar(L'\n'); 4747c478bd9Sstevel@tonic-gate free(scp); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 477*dc5a8425Srobbin void 478*dc5a8425Srobbin initbuf(void) 4797c478bd9Sstevel@tonic-gate { 480*dc5a8425Srobbin int i; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* following depends on NORMAL == 000 */ 4837c478bd9Sstevel@tonic-gate for (i = 0; i < LINE_MAX; i++) 4847c478bd9Sstevel@tonic-gate obuf[i].c_char = obuf[i].c_mode = 0; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate col = 0; 4877c478bd9Sstevel@tonic-gate maxcol = 0; 4887c478bd9Sstevel@tonic-gate mode &= ALTSET; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 491*dc5a8425Srobbin void 492*dc5a8425Srobbin fwd(void) 4937c478bd9Sstevel@tonic-gate { 494*dc5a8425Srobbin int oldcol, oldmax; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate oldcol = col; 4977c478bd9Sstevel@tonic-gate oldmax = maxcol; 4987c478bd9Sstevel@tonic-gate flushln(); 4997c478bd9Sstevel@tonic-gate col = oldcol; 5007c478bd9Sstevel@tonic-gate maxcol = oldmax; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 503*dc5a8425Srobbin void 504*dc5a8425Srobbin reverse(void) 5057c478bd9Sstevel@tonic-gate { 5067c478bd9Sstevel@tonic-gate upln++; 5077c478bd9Sstevel@tonic-gate fwd(); 508*dc5a8425Srobbin ul_puts(CURS_UP); 509*dc5a8425Srobbin ul_puts(CURS_UP); 5107c478bd9Sstevel@tonic-gate upln++; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 513*dc5a8425Srobbin void 514*dc5a8425Srobbin initcap(void) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate static char tcapbuf[512]; 5177c478bd9Sstevel@tonic-gate char *bp = tcapbuf; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* This nonsense attempts to work with both old and new termcap */ 5207c478bd9Sstevel@tonic-gate CURS_UP = tgetstr("up", &bp); 5217c478bd9Sstevel@tonic-gate CURS_RIGHT = tgetstr("ri", &bp); 5227c478bd9Sstevel@tonic-gate if (CURS_RIGHT == NULL) 5237c478bd9Sstevel@tonic-gate CURS_RIGHT = tgetstr("nd", &bp); 5247c478bd9Sstevel@tonic-gate CURS_LEFT = tgetstr("le", &bp); 5257c478bd9Sstevel@tonic-gate if (CURS_LEFT == NULL) 5267c478bd9Sstevel@tonic-gate CURS_LEFT = tgetstr("bc", &bp); 5277c478bd9Sstevel@tonic-gate if (CURS_LEFT == NULL && tgetflag("bs")) 5287c478bd9Sstevel@tonic-gate CURS_LEFT = "\b"; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate ENTER_STANDOUT = tgetstr("so", &bp); 5317c478bd9Sstevel@tonic-gate EXIT_STANDOUT = tgetstr("se", &bp); 5327c478bd9Sstevel@tonic-gate ENTER_UNDERLINE = tgetstr("us", &bp); 5337c478bd9Sstevel@tonic-gate EXIT_UNDERLINE = tgetstr("ue", &bp); 5347c478bd9Sstevel@tonic-gate ENTER_DIM = tgetstr("mh", &bp); 5357c478bd9Sstevel@tonic-gate ENTER_BOLD = tgetstr("md", &bp); 5367c478bd9Sstevel@tonic-gate ENTER_REVERSE = tgetstr("mr", &bp); 5377c478bd9Sstevel@tonic-gate EXIT_ATTRIBUTES = tgetstr("me", &bp); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate if (!ENTER_BOLD && ENTER_REVERSE) 5407c478bd9Sstevel@tonic-gate ENTER_BOLD = ENTER_REVERSE; 5417c478bd9Sstevel@tonic-gate if (!ENTER_BOLD && ENTER_STANDOUT) 5427c478bd9Sstevel@tonic-gate ENTER_BOLD = ENTER_STANDOUT; 5437c478bd9Sstevel@tonic-gate if (!ENTER_UNDERLINE && ENTER_STANDOUT) { 5447c478bd9Sstevel@tonic-gate ENTER_UNDERLINE = ENTER_STANDOUT; 5457c478bd9Sstevel@tonic-gate EXIT_UNDERLINE = EXIT_STANDOUT; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate if (!ENTER_DIM && ENTER_STANDOUT) 5487c478bd9Sstevel@tonic-gate ENTER_DIM = ENTER_STANDOUT; 5497c478bd9Sstevel@tonic-gate if (!ENTER_REVERSE && ENTER_STANDOUT) 5507c478bd9Sstevel@tonic-gate ENTER_REVERSE = ENTER_STANDOUT; 5517c478bd9Sstevel@tonic-gate if (!EXIT_ATTRIBUTES && EXIT_STANDOUT) 5527c478bd9Sstevel@tonic-gate EXIT_ATTRIBUTES = EXIT_STANDOUT; 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * Note that we use REVERSE for the alternate character set, 5567c478bd9Sstevel@tonic-gate * not the as/ae capabilities. This is because we are modelling 5577c478bd9Sstevel@tonic-gate * the model 37 teletype (since that's what nroff outputs) and 5587c478bd9Sstevel@tonic-gate * the typical as/ae is more of a graphics set, not the greek 5597c478bd9Sstevel@tonic-gate * letters the 37 has. 5607c478bd9Sstevel@tonic-gate */ 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate #ifdef notdef 5637c478bd9Sstevel@tonic-gate printf("so %s se %s us %s ue %s me %s\n", 5647c478bd9Sstevel@tonic-gate ENTER_STANDOUT, EXIT_STANDOUT, ENTER_UNDERLINE, 5657c478bd9Sstevel@tonic-gate EXIT_UNDERLINE, EXIT_ATTRIBUTES); 5667c478bd9Sstevel@tonic-gate #endif 5677c478bd9Sstevel@tonic-gate UNDER_CHAR = tgetstr("uc", &bp); 5687c478bd9Sstevel@tonic-gate must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 571*dc5a8425Srobbin int 572*dc5a8425Srobbin outchar(char c) 5737c478bd9Sstevel@tonic-gate { 574*dc5a8425Srobbin (void) putchar(c&0177); 575*dc5a8425Srobbin return (0); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 578*dc5a8425Srobbin void 579*dc5a8425Srobbin ul_puts(char *str) 5807c478bd9Sstevel@tonic-gate { 5817c478bd9Sstevel@tonic-gate if (str) 582*dc5a8425Srobbin (void) tputs(str, 1, outchar); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 585*dc5a8425Srobbin static int curmode = 0; 586*dc5a8425Srobbin 587*dc5a8425Srobbin void 588*dc5a8425Srobbin outc(wchar_t c) 5897c478bd9Sstevel@tonic-gate { 590*dc5a8425Srobbin int m, n; 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate if (c == CDUMMY) 5937c478bd9Sstevel@tonic-gate return; 594*dc5a8425Srobbin (void) putwchar(c); 5957c478bd9Sstevel@tonic-gate if (must_use_uc && (curmode & UNDERL)) { 5967c478bd9Sstevel@tonic-gate m = n = scrw[wcsetno(c)]; 597*dc5a8425Srobbin ul_puts(CURS_LEFT); 5987c478bd9Sstevel@tonic-gate while (--m > 0) 599*dc5a8425Srobbin ul_puts(CURS_LEFT); 600*dc5a8425Srobbin ul_puts(UNDER_CHAR); 6017c478bd9Sstevel@tonic-gate while (--n > 0) 602*dc5a8425Srobbin ul_puts(UNDER_CHAR); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 606*dc5a8425Srobbin void 607*dc5a8425Srobbin setmode(int newmode) 6087c478bd9Sstevel@tonic-gate { 609*dc5a8425Srobbin if (!iflag) { 6107c478bd9Sstevel@tonic-gate if (curmode != NORMAL && newmode != NORMAL) 6117c478bd9Sstevel@tonic-gate setmode(NORMAL); 6127c478bd9Sstevel@tonic-gate switch (newmode) { 6137c478bd9Sstevel@tonic-gate case NORMAL: 6147c478bd9Sstevel@tonic-gate switch (curmode) { 6157c478bd9Sstevel@tonic-gate case NORMAL: 6167c478bd9Sstevel@tonic-gate break; 6177c478bd9Sstevel@tonic-gate case UNDERL: 618*dc5a8425Srobbin ul_puts(EXIT_UNDERLINE); 6197c478bd9Sstevel@tonic-gate break; 6207c478bd9Sstevel@tonic-gate default: 6217c478bd9Sstevel@tonic-gate /* This includes standout */ 622*dc5a8425Srobbin ul_puts(EXIT_ATTRIBUTES); 6237c478bd9Sstevel@tonic-gate break; 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate break; 6267c478bd9Sstevel@tonic-gate case ALTSET: 627*dc5a8425Srobbin ul_puts(ENTER_REVERSE); 6287c478bd9Sstevel@tonic-gate break; 6297c478bd9Sstevel@tonic-gate case SUPERSC: 6307c478bd9Sstevel@tonic-gate /* 6317c478bd9Sstevel@tonic-gate * This only works on a few terminals. 6327c478bd9Sstevel@tonic-gate * It should be fixed. 6337c478bd9Sstevel@tonic-gate */ 634*dc5a8425Srobbin ul_puts(ENTER_UNDERLINE); 635*dc5a8425Srobbin ul_puts(ENTER_DIM); 6367c478bd9Sstevel@tonic-gate break; 6377c478bd9Sstevel@tonic-gate case SUBSC: 638*dc5a8425Srobbin ul_puts(ENTER_DIM); 6397c478bd9Sstevel@tonic-gate break; 6407c478bd9Sstevel@tonic-gate case UNDERL: 641*dc5a8425Srobbin ul_puts(ENTER_UNDERLINE); 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate case BOLD: 644*dc5a8425Srobbin ul_puts(ENTER_BOLD); 6457c478bd9Sstevel@tonic-gate break; 6467c478bd9Sstevel@tonic-gate default: 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * We should have some provision here for multiple modes 6497c478bd9Sstevel@tonic-gate * on at once. This will have to come later. 6507c478bd9Sstevel@tonic-gate */ 651*dc5a8425Srobbin ul_puts(ENTER_STANDOUT); 6527c478bd9Sstevel@tonic-gate break; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate curmode = newmode; 6567c478bd9Sstevel@tonic-gate } 657