From b4828720f7ea0eeb727e9691631cc596ddf16f88 Mon Sep 17 00:00:00 2001 From: "Tim J. Robbins" Date: Tue, 13 Jul 2004 04:35:43 +0000 Subject: [PATCH] Overhaul lputs() to deal with multibyte characters, characters that take up more than one column position, and null bytes. --- usr.bin/sed/process.c | 79 +++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c index 772fd0b92893..0d6399451091 100644 --- a/usr.bin/sed/process.c +++ b/usr.bin/sed/process.c @@ -57,6 +57,8 @@ static const char sccsid[] = "@(#)process.c 8.6 (Berkeley) 4/20/94"; #include #include #include +#include +#include #include "defs.h" #include "extern.h" @@ -70,7 +72,7 @@ static SPACE HS, PS, SS; static __inline int applies(struct s_command *); static void flush_appends(void); -static void lputs(char *); +static void lputs(char *, size_t); static __inline int regexec_e(regex_t *, const char *, int, int, size_t); static void regsub(SPACE *, char *, char *); static int substitute(struct s_command *); @@ -165,7 +167,7 @@ process(void) (void)fprintf(outfile, "%s", cp->t); break; case 'l': - lputs(ps); + lputs(ps, psl); break; case 'n': if (!nflag && !pd) @@ -462,13 +464,16 @@ flush_appends(void) } static void -lputs(char *s) +lputs(char *s, size_t len) { - int count; - const char *escapes; + static const char escapes[] = "\\\a\b\f\r\t\v"; + int c, col, width; char *p; struct winsize win; static int termwidth = -1; + size_t clen, i; + wchar_t wc; + mbstate_t mbs; if (outfile != stdout) termwidth = 60; @@ -482,30 +487,54 @@ lputs(char *s) termwidth = 60; } - for (count = 0; *s; ++s) { - if (count + 5 >= termwidth) { - (void)fprintf(outfile, "\\\n"); - count = 0; + memset(&mbs, 0, sizeof(mbs)); + col = 0; + while (len != 0) { + clen = mbrtowc(&wc, s, len, &mbs); + if (clen == 0) + clen = 1; + if (clen == (size_t)-1 || clen == (size_t)-2) { + wc = (unsigned char)*s; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); } - if (isprint((unsigned char)*s) && *s != '\\') { - (void)fputc(*s, outfile); - count++; - } else if (*s == '\n') { - (void)fputc('$', outfile); - (void)fputc('\n', outfile); - count = 0; - } else { - escapes = "\\\a\b\f\r\t\v"; - (void)fputc('\\', outfile); - if ((p = strchr(escapes, *s))) { - (void)fputc("\\abfrtv"[p - escapes], outfile); - count += 2; - } else { - (void)fprintf(outfile, "%03o", *(u_char *)s); - count += 4; + if (wc == '\n') { + if (col + 1 >= termwidth) + fprintf(outfile, "\\\n"); + fputc('$', outfile); + fputc('\n', outfile); + col = 0; + } else if (iswprint(wc)) { + width = wcwidth(wc); + if (col + width >= termwidth) { + fprintf(outfile, "\\\n"); + col = 0; } + fwrite(s, 1, clen, outfile); + col += width; + } else if (wc != L'\0' && (c = wctob(wc)) != EOF && + (p = strchr(escapes, c)) != NULL) { + if (col + 2 >= termwidth) { + fprintf(outfile, "\\\n"); + col = 0; + } + fprintf(outfile, "\\%c", "\\abfrtv"[p - escapes]); + col += 2; + } else { + if (col + 4 * clen >= termwidth) { + fprintf(outfile, "\\\n"); + col = 0; + } + for (i = 0; i < clen; i++) + fprintf(outfile, "\\%03o", + (int)(unsigned char)s[i]); + col += 4 * clen; } + s += clen; + len -= clen; } + if (col + 1 >= termwidth) + fprintf(outfile, "\\\n"); (void)fputc('$', outfile); (void)fputc('\n', outfile); if (ferror(outfile))