/* * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * modified by Kars de Jong * to use terminfo instead of termcap. * 1999-02-22 Arkadiusz Mi¶kiewicz * added Native Language Support * 1999-09-19 Bruno Haible * modified to work correctly in multi-byte locales */ #include #include /* for getopt(), isatty() */ #include /* for memset(), strcpy() */ #include /* for setupterm() */ #include /* for getenv() */ #include /* for INT_MAX */ #include /* for signal() */ #include #include #include #include "nls.h" #include "xalloc.h" #include "widechar.h" #ifdef HAVE_WIDECHAR static int put1wc(int c) /* Output an ASCII character as a wide character */ { if (putwchar(c) == WEOF) return EOF; else return c; } #define putwp(s) tputs(s,1,put1wc) #else #define putwp(s) putp(s) #endif void filter(FILE *f); void flushln(void); void overstrike(void); void iattr(void); void initbuf(void); void fwd(void); void reverse(void); void initinfo(void); void outc(wint_t c, int width); void setmode(int newmode); static void setcol(int newcol); static void needcol(int col); static void sig_handler(int signo); #define IESC '\033' #define SO '\016' #define SI '\017' #define HFWD '9' #define HREV '8' #define FREV '7' #define NORMAL 000 #define ALTSET 001 /* Reverse */ #define SUPERSC 002 /* Dim */ #define SUBSC 004 /* Dim | Ul */ #define UNDERL 010 /* Ul */ #define BOLD 020 /* Bold */ #define INITBUF 512 int must_use_uc, must_overstrike; char *CURS_UP, *CURS_RIGHT, *CURS_LEFT, *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE, *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES; struct CHAR { char c_mode; wchar_t c_char; int c_width; } ; struct CHAR *obuf; int obuflen; /* Tracks number of elements in obuf. */ int col, maxcol; int mode; int halfpos; int upln; int iflag; #define PRINT(s) if (s == NULL) /* void */; else putwp(s) int main(int argc, char **argv) { int c, ret; char *termtype; FILE *f; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); termtype = getenv("TERM"); if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) termtype = "lpr"; while ((c = getopt(argc, argv, "it:T:")) != -1) switch(c) { case 't': case 'T': /* for nroff compatibility */ termtype = optarg; break; case 'i': iflag = 1; break; default: fprintf(stderr, _("Usage: %s [ -i ] [ -tTerm ] file...\n"), program_invocation_short_name); return EXIT_FAILURE; } setupterm(termtype, 1, &ret); switch(ret) { case 1: break; default: warnx(_("trouble reading terminfo")); /* fall through to ... */ case 0: /* No such terminal type - assume dumb */ setupterm("dumb", 1, (int *)0); break; } initinfo(); if ( (tigetflag("os") && ENTER_BOLD==NULL ) || (tigetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) must_overstrike = 1; initbuf(); if (optind == argc) filter(stdin); else for (; optind 0) { mode &= ~SUBSC; halfpos--; } else { halfpos = 0; reverse(); } continue; case HFWD: if (halfpos == 0) { mode |= SUBSC; halfpos++; } else if (halfpos < 0) { mode &= ~SUPERSC; halfpos++; } else { halfpos = 0; fwd(); } continue; case FREV: reverse(); continue; default: errx(EXIT_FAILURE, _("unknown escape sequence in input: %o, %o"), IESC, c); break; } continue; case '_': if (obuf[col].c_char || obuf[col].c_width < 0) { while(col > 0 && obuf[col].c_width < 0) col--; w = obuf[col].c_width; for (i = 0; i < w; i++) obuf[col++].c_mode |= UNDERL | mode; setcol(col); continue; } obuf[col].c_char = '_'; obuf[col].c_width = 1; /* fall through */ case ' ': setcol(col + 1); continue; case '\n': flushln(); continue; case '\f': flushln(); putwchar('\f'); continue; default: if (!iswprint(c)) /* non printing */ continue; w = wcwidth(c); needcol(col + w); if (obuf[col].c_char == '\0') { obuf[col].c_char = c; for (i = 0; i < w; i++) obuf[col+i].c_mode = mode; obuf[col].c_width = w; for (i = 1; i < w; i++) obuf[col+i].c_width = -1; } else if (obuf[col].c_char == '_') { obuf[col].c_char = c; for (i = 0; i < w; i++) obuf[col+i].c_mode |= UNDERL|mode; obuf[col].c_width = w; for (i = 1; i < w; i++) obuf[col+i].c_width = -1; } else if (obuf[col].c_char == c) { for (i = 0; i < w; i++) obuf[col+i].c_mode |= BOLD|mode; } else { w = obuf[col].c_width; for (i = 0; i < w; i++) obuf[col+i].c_mode = mode; } setcol(col + w); continue; } if (maxcol) flushln(); } void flushln(void) { int lastmode; int i; int hadmodes = 0; lastmode = NORMAL; for (i=0; i 1) i += obuf[i].c_width -1; } if (lastmode != NORMAL) { setmode(0); } if (must_overstrike && hadmodes) overstrike(); putwchar('\n'); if (iflag && hadmodes) iattr(); (void)fflush(stdout); if (upln) upln--; initbuf(); } /* * For terminals that can overstrike, overstrike underlines and bolds. * We don't do anything with halfline ups and downs, or Greek. */ void overstrike(void) { register int i; #ifdef __GNUC__ register wchar_t *lbuf = __builtin_alloca((maxcol+1)*sizeof(wchar_t)); #else wchar_t lbuf[256]; #endif register wchar_t *cp = lbuf; int hadbold=0; /* Set up overstrike buffer */ for (i=0; i 1) i += obuf[i].c_width - 1; hadbold=1; break; } putwchar('\r'); for (*cp=' '; *cp==' '; cp--) *cp = 0; for (cp=lbuf; *cp; cp++) putwchar(*cp); if (hadbold) { putwchar('\r'); for (cp=lbuf; *cp; cp++) putwchar(*cp=='_' ? ' ' : *cp); putwchar('\r'); for (cp=lbuf; *cp; cp++) putwchar(*cp=='_' ? ' ' : *cp); } } void iattr(void) { register int i; #ifdef __GNUC__ register char *lbuf = __builtin_alloca((maxcol+1)*sizeof(char)); #else char lbuf[256]; #endif register char *cp = lbuf; for (i=0; i maxcol) needcol(col); } static void needcol(int col) { maxcol = col; /* If col >= obuflen, expand obuf until obuflen > col. */ while (col >= obuflen) { /* Paranoid check for obuflen == INT_MAX. */ if (obuflen == INT_MAX) errx(EXIT_FAILURE, _("Input line too long.")); /* Similar paranoia: double only up to INT_MAX. */ obuflen = ((INT_MAX / 2) < obuflen) ? INT_MAX : obuflen * 2; /* Now we can try to expand obuf. */ obuf = xrealloc(obuf, sizeof(struct CHAR) * obuflen); } } static void sig_handler(int signo) { _exit(EXIT_SUCCESS); }