From 3d22c61072a3b89837dc33e0e21a82ec5cea1329 Mon Sep 17 00:00:00 2001 From: tjr Date: Thu, 29 Jul 2004 22:51:54 +0000 Subject: Add support for multibyte characters, based on Bruno Haible's work in the util-linux package. --- usr.bin/ul/ul.1 | 25 ++++--------- usr.bin/ul/ul.c | 112 +++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 81 insertions(+), 56 deletions(-) diff --git a/usr.bin/ul/ul.1 b/usr.bin/ul/ul.1 index 919efa1..6220dc8 100644 --- a/usr.bin/ul/ul.1 +++ b/usr.bin/ul/ul.1 @@ -32,7 +32,7 @@ .\" @(#)ul.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd July 16, 2004 +.Dd July 30, 2004 .Dt UL 1 .Os .Sh NAME @@ -76,23 +76,14 @@ Overrides the terminal type specified in the environment with .Ar terminal . .El .Sh ENVIRONMENT -The following environment variable is used: -.Bl -tag -width TERM -.It Ev TERM The +.Ev LANG , LC_ALL , LC_CTYPE +and .Ev TERM -variable is used to relate a tty device -with its device capability description (see -.Xr termcap 5 ) . -.Ev TERM -is set at login time, either by the default terminal type -specified in -.Pa /etc/ttys -or as set during the login process by the user in their -.Pa login -file (see -.Xr environ 7 ) . -.El +environment variables affect the execution of +.Nm +as described in +.Xr environ 7 . .Sh SEE ALSO .Xr colcrt 1 , .Xr man 1 , @@ -104,8 +95,6 @@ command usually outputs a series of backspaces and underlines intermixed with the text to indicate underlining. No attempt is made to optimize the backward motion. -.Pp -Multibyte characters are not recognized. .Sh HISTORY The .Nm diff --git a/usr.bin/ul/ul.c b/usr.bin/ul/ul.c index de779b1c..6e9a035 100644 --- a/usr.bin/ul/ul.c +++ b/usr.bin/ul/ul.c @@ -46,11 +46,14 @@ static const char rcsid[] = #endif /* not lint */ #include +#include #include #include #include #include #include +#include +#include #define IESC '\033' #define SO '\016' @@ -75,7 +78,8 @@ const char struct CHAR { char c_mode; - char c_char; + wchar_t c_char; + int c_width; /* width or -1 if multi-column char. filler */ } ; struct CHAR obuf[MAXBUF]; @@ -96,7 +100,7 @@ void iattr(void); void overstrike(void); void flushln(void); void filter(FILE *); -void outc(int); +void outc(wint_t, int); #define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar) @@ -108,6 +112,8 @@ main(int argc, char **argv) FILE *f; char termcap[1024]; + setlocale(LC_ALL, ""); + termtype = getenv("TERM"); if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) termtype = "lpr"; @@ -166,9 +172,10 @@ usage(void) void filter(FILE *f) { - int c; + wint_t c; + int i, w; - while ((c = getc(f)) != EOF && col < MAXBUF) switch(c) { + while ((c = getwc(f)) != WEOF && col < MAXBUF) switch(c) { case '\b': if (col > 0) @@ -194,7 +201,7 @@ filter(FILE *f) continue; case IESC: - switch (c = getc(f)) { + switch (c = getwc(f)) { case HREV: if (halfpos == 0) { @@ -232,10 +239,19 @@ filter(FILE *f) continue; case '_': - if (obuf[col].c_char) - obuf[col].c_mode |= UNDERL | mode; - else - obuf[col].c_char = '_'; + 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; + if (col > maxcol) + maxcol = col; + continue; + } + obuf[col].c_char = '_'; + obuf[col].c_width = 1; + /* FALLTHROUGH */ case ' ': col++; if (col > maxcol) @@ -248,23 +264,35 @@ filter(FILE *f) case '\f': flushln(); - putchar('\f'); + putwchar('\f'); continue; default: - if (c < ' ') /* non printing */ + if ((w = wcwidth(c)) <= 0) /* non printing */ continue; if (obuf[col].c_char == '\0') { obuf[col].c_char = c; - obuf[col].c_mode = mode; + 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; - obuf[col].c_mode |= UNDERL|mode; - } else if (obuf[col].c_char == c) - obuf[col].c_mode |= BOLD|mode; - else - obuf[col].c_mode = mode; - col++; + 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; + } + col += w; if (col > maxcol) maxcol = col; continue; @@ -291,16 +319,18 @@ flushln(void) if (upln) PRINT(CURS_RIGHT); else - outc(' '); + outc(' ', 1); } else - outc(obuf[i].c_char); + outc(obuf[i].c_char, obuf[i].c_width); + if (obuf[i].c_width > 1) + i += obuf[i].c_width - 1; } if (lastmode != NORMAL) { setnewmode(0); } if (must_overstrike && hadmodes) overstrike(); - putchar('\n'); + putwchar('\n'); if (iflag && hadmodes) iattr(); (void)fflush(stdout); @@ -317,8 +347,8 @@ void overstrike(void) { int i; - char lbuf[256]; - char *cp = lbuf; + wchar_t lbuf[256]; + wchar_t *cp = lbuf; int hadbold=0; /* Set up overstrike buffer */ @@ -333,21 +363,23 @@ overstrike(void) break; case BOLD: *cp++ = obuf[i].c_char; + if (obuf[i].c_width > 1) + i += obuf[i].c_width - 1; hadbold=1; break; } - putchar('\r'); + putwchar('\r'); for (*cp=' '; *cp==' '; cp--) *cp = 0; for (cp=lbuf; *cp; cp++) - putchar(*cp); + putwchar(*cp); if (hadbold) { - putchar('\r'); + putwchar('\r'); for (cp=lbuf; *cp; cp++) - putchar(*cp=='_' ? ' ' : *cp); - putchar('\r'); + putwchar(*cp=='_' ? ' ' : *cp); + putwchar('\r'); for (cp=lbuf; *cp; cp++) - putchar(*cp=='_' ? ' ' : *cp); + putwchar(*cp=='_' ? ' ' : *cp); } } @@ -355,8 +387,8 @@ void iattr(void) { int i; - char lbuf[256]; - char *cp = lbuf; + wchar_t lbuf[256]; + wchar_t *cp = lbuf; for (i=0; i