aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/mg/APKBUILD10
-rw-r--r--main/mg/unicode.patch1347
2 files changed, 4 insertions, 1353 deletions
diff --git a/main/mg/APKBUILD b/main/mg/APKBUILD
index 5b5a901fea..9331b2a6ee 100644
--- a/main/mg/APKBUILD
+++ b/main/mg/APKBUILD
@@ -1,8 +1,8 @@
# Contributor: Lee Hinman <hinman@gmail.com>
# Maintainer: Cág <ca6c@bitmessage.ch>
pkgname=mg
-pkgver=20170401
-pkgrel=1
+pkgver=20170828
+pkgrel=0
pkgdesc="microscopic EMACS style editor"
url="http://homepage.boetes.org/software/mg"
arch="all"
@@ -13,7 +13,6 @@ install=
subpackages="$pkgname-doc"
source="http://homepage.boetes.org/software/mg/$pkgname-$pkgver.tar.gz
missing-defines.patch
- unicode.patch
"
_builddir="$srcdir"/$pkgname-$pkgver
@@ -39,6 +38,5 @@ package() {
install -Dm644 tutorial "$pkgdir"/usr/share/doc/$pkgname/tutorial
}
-sha512sums="729b2d9ba7eb236cc8bcbcf3ac7604494980cbf2fd21dc5a3856011bc830eee75be29a246b0bf3dfa6c7a03fcf69a902ae50d05ea371ac4d0225a4da6089d7ce mg-20170401.tar.gz
-f1967dd33a025e11ff63ba797c2fb64ac0679cd6c09a332241a28e0976b96db467894e1e3573c5bc88b7feaecdb430695aa4f8fa2712b227d0947b3d8b05c97c missing-defines.patch
-586a622b6838bb5b4f2e958352cec6bd4ca9c7db93bcc0dfeb6d8e588fb1191bc5f01afd17a385c10ddbd6ceb631d2d9caccd4e080294d1fceb5db676ab6a4fc unicode.patch"
+sha512sums="1ea16b1dd5e9e08abf9fcf0889130b4f39d36872bb64df85470a9ced1db87c0eecb18cc6e8c3c5a04f9049d58ef4492d5a88cf3502ec3351abccb7bddfb90c14 mg-20170828.tar.gz
+f1967dd33a025e11ff63ba797c2fb64ac0679cd6c09a332241a28e0976b96db467894e1e3573c5bc88b7feaecdb430695aa4f8fa2712b227d0947b3d8b05c97c missing-defines.patch"
diff --git a/main/mg/unicode.patch b/main/mg/unicode.patch
deleted file mode 100644
index 39d8831f68..0000000000
--- a/main/mg/unicode.patch
+++ /dev/null
@@ -1,1347 +0,0 @@
-diff --git a/README.md b/README.md
-index 994d6be..2f5d2c1 100644
---- a/README.md
-+++ b/README.md
-@@ -1,49 +1,50 @@
--# PORTING MG AND USING LIBBSD
-+# mg with wide display support.
-
--I've maintained and ported mg for quite some time now and at first it
--was easy recently it got harder and harder since it was a moving
--target. Especially the inclusion of some system specific libraries since
--about 2 years ago made it too much of an effort for my humble coding
--skills.
--
--So recently Jasper Lievisse Adriaanse asked me to try it again and I
--restarted working on the project and ran into exactly the same problems
--again. While googling for solutions I ran into libbsd:
--
-- http://libbsd.freedesktop.org/wiki/
--
--It's a porting library for OpenBSD code! And after installing that it
--was a piece of pie to get mg ported again.
--
--## PORTING TO ALL OTHER PLATFORMS
--
--Okay, that was debian. Now I have to get the rest of all the previously
--suported platforms working again. All help is welcome and as always:
--Please provide patches that do not break stuff for other platforms.
--
--## BUILDING MG
--
--So, basic instructions for building mg:
--
-- - Get libbsd installed.
-- - Run the following commands:
-+I just received this amazing patch from S. Giles. For those impatient
-+people: check it out (tihihi) and add this line to your `.mg`
-
- ```
--make
--sudo make install
-+set-default-mode "wide"
- ```
-
--## USING CVS
--
--This code is the cvs checkout from the OpenBSD project so if you install
--cvs you can see what I changed to port mg. Like this:
--
--```
--cvs diff -uw
--```
--
--## ABOUT fgetln()
--
--Incase you are wondering about that deprecation warning, here is a nice explanation about why it is hard to fix:
--
-- http://niallohiggins.com/2009/10/03/read-a-file-line-by-line-in-c-secure-fgets-idiom/
-+## Introduction by S. Giles
-+
-+Hi,
-+
-+I've got a patch that allows mg to display wide characters, if you're
-+interested.
-+
-+It can be turned on by show-wide-mode (better name welcome), and is
-+fairly limited in regard to what types of wide characters are
-+displayed. Everything goes through mbrtowc(3), so you get exactly one
-+supported encoding: whatever LC_* says. Everything else is displayed
-+as octal escape sequences (as normal current behavior). Motion is
-+still on a byte level, so multibyte characters are slow to travel
-+through, and you can insert bytes in the middle of them (which works
-+fine). A limited version of insert-char is also included, which works
-+through wchar_t, so that on any system with __STDC_ISO_10646__ set,
-+inserting unicode codepoints by number is possible.
-+
-+It also fixes some odd bugs related to wide character display and
-+extended lines. For example: in a file with enough wide characters
-+(such as ABC) to make a line extend far (say, 200 characters on an
-+80-wide display), moving to the right one character at a time will (in
-+20160118) corrupt the display, then eventually segfault, because
-+vtpute doesn't perform the same octal expansion as vtputc and the
-+columns get out of sync. This patch makes display.c aware of the
-+possibility that the bytes and glyphs of the buffers aren't 1:1, so
-+protects against that.
-+
-+That said, wide character support complicates a lot of already
-+complicated logic (for example, vtputs) and relies on wchar_t for
-+almost everything, adding some unescapable overhead.
-+
-+If you want to take this patch, please do so. If you think it's too
-+ugly or not useful, that's also fine. Let me know if you want me to
-+rewrite parts of it (or if you see any bugs) or if there are style
-+conventions I didn't follow. It applies cleanly with patch -i, please
-+forgive the git-isms.
-+
-+(And, of course, many thanks for your work in maintaining the port.)
-+
-+S. Gilles
-diff --git a/basic.c b/basic.c
-index 85d9f70..123e115 100644
---- a/basic.c
-+++ b/basic.c
-@@ -18,6 +18,7 @@
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
-+#include <wchar.h>
-
- #include "def.h"
-
-@@ -269,12 +270,25 @@ setgoal(void)
- int
- getgoal(struct line *dlp)
- {
-- int c, i, col = 0;
-- char tmp[5];
-+ return getbyteofcol(dlp, 0, curgoal);
-+}
-
-+/*
-+ * Return the byte offset within lp that is targetcol columns beyond
-+ * startbyte
-+ */
-+size_t
-+getbyteofcol(const struct line *lp, const size_t startbyte,
-+ const size_t targetcol)
-+{
-+ int c;
-+ size_t i, col = 0;
-+ char tmp[5];
-+ size_t advance_by = 1;
-
-- for (i = 0; i < llength(dlp); i++) {
-- c = lgetc(dlp, i);
-+ for (i = startbyte; i < llength(lp); i += advance_by) {
-+ advance_by = 1;
-+ c = lgetc(lp, i);
- if (c == '\t'
- #ifdef NOTAB
- && !(curbp->b_flag & BFNOTAB)
-@@ -284,18 +298,86 @@ getgoal(struct line *dlp)
- col++;
- } else if (ISCTRL(c) != FALSE) {
- col += 2;
-- } else if (isprint(c))
-+ } else if (isprint(c)) {
- col++;
-- else {
-+ } else if (!(curbp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+ size_t consumed = mbrtowc(&wc, &lp->l_text[i],
-+ llength(lp) - i, &mbs);
-+ int width = -1;
-+ if (consumed < (size_t) -2) {
-+ width = wcwidth(wc);
-+ }
-+ if (width >= 0) {
-+ col += width;
-+ advance_by = consumed;
-+ } else {
-+ col += snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ }
-+ } else {
- col += snprintf(tmp, sizeof(tmp), "\\%o", c);
- }
-- if (col > curgoal)
-+ if (col > targetcol)
- break;
- }
- return (i);
- }
-
- /*
-+ * Return the column at which specified offset byte would appear, if
-+ * this were part of a longer string printed by vtputs, starting at
-+ * intial_col
-+ */
-+size_t
-+getcolofbyte(const struct line *lp, const size_t startbyte,
-+ const size_t initial_col, const size_t targetoffset)
-+{
-+ int c;
-+ size_t i, col = initial_col;
-+ char tmp[5];
-+ size_t advance_by = 1;
-+
-+ for (i = startbyte; i < llength(lp); i += advance_by) {
-+ if (i >= targetoffset)
-+ break;
-+ advance_by = 1;
-+ c = lgetc(lp, i);
-+ if (c == '\t'
-+#ifdef NOTAB
-+ && !(curbp->b_flag & BFNOTAB)
-+#endif
-+ ) {
-+ col |= 0x07;
-+ col++;
-+ } else if (ISCTRL(c) != FALSE) {
-+ col += 2;
-+ } else if (isprint(c)) {
-+ col++;
-+ } else if (!(curbp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+ size_t consumed = mbrtowc(&wc, &lp->l_text[i],
-+ llength(lp) - i, &mbs);
-+ int width = -1;
-+ if (consumed < (size_t) -2) {
-+ width = wcwidth(wc);
-+ }
-+ if (width >= 0) {
-+ col += width;
-+ advance_by = consumed;
-+ } else {
-+ col += snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ }
-+ } else {
-+ col += snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ }
-+ }
-+ return (col);
-+}
-+
-+
-+/*
- * Scroll forward by a specified number
- * of lines, or by a full page if no argument.
- * The "2" is the window overlap (this is the default
-diff --git a/cmode.c b/cmode.c
-index a238285..9d4cac3 100644
---- a/cmode.c
-+++ b/cmode.c
-@@ -14,6 +14,7 @@
- #include <ctype.h>
- #include <signal.h>
- #include <stdio.h>
-+#include <wchar.h>
-
- #include "def.h"
- #include "funmap.h"
-@@ -419,10 +420,25 @@ findcolpos(const struct buffer *bp, const struct line *lp, int lo)
- ) {
- col |= 0x07;
- col++;
-- } else if (ISCTRL(c) != FALSE)
-+ } else if (ISCTRL(c) != FALSE) {
- col += 2;
-- else if (isprint(c)) {
-+ } else if (isprint(c)) {
- col++;
-+ } else if (!(bp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+ size_t consumed = mbrtowc(&wc, &lp->l_text[i],
-+ llength(lp) - i, &mbs);
-+ int width = -1;
-+ if (consumed < (size_t) -2) {
-+ width = wcwidth(wc);
-+ }
-+ if (width >= 0) {
-+ col += width;
-+ i += (consumed - 1);
-+ } else {
-+ col += snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ }
- } else {
- col += snprintf(tmp, sizeof(tmp), "\\%o", c);
- }
-diff --git a/def.h b/def.h
-index 54b74ce..2fb289d 100644
---- a/def.h
-+++ b/def.h
-@@ -270,7 +270,7 @@ struct buffer {
- int b_marko; /* ditto for the "mark" */
- short b_nmodes; /* number of non-fundamental modes */
- char b_nwnd; /* Count of windows on buffer */
-- char b_flag; /* Flags */
-+ short b_flag; /* Flags */
- char b_fname[NFILEN]; /* File name */
- char b_cwd[NFILEN]; /* working directory */
- struct fileinfo b_fi; /* File attributes */
-@@ -297,6 +297,7 @@ struct buffer {
- #define BFDIRTY 0x20 /* Buffer was modified elsewhere */
- #define BFIGNDIRTY 0x40 /* Ignore modifications */
- #define BFDIREDDEL 0x80 /* Dired has a deleted 'D' file */
-+#define BFSHOWRAW 0x100 /* Show unprintable as octal */
- /*
- * This structure holds information about recent actions for the Undo command.
- */
-@@ -497,6 +498,7 @@ int digit_argument(int, int);
- int negative_argument(int, int);
- int selfinsert(int, int);
- int quote(int, int);
-+int insert_char(int, int);
-
- /* main.c */
- int ctrlg(int, int);
-@@ -519,6 +521,8 @@ int forwline(int, int);
- int backline(int, int);
- void setgoal(void);
- int getgoal(struct line *);
-+size_t getbyteofcol(const struct line *, size_t, size_t);
-+size_t getcolofbyte(const struct line *, size_t, size_t, size_t);
- int forwpage(int, int);
- int backpage(int, int);
- int forw1page(int, int);
-@@ -665,6 +669,7 @@ int notabmode(int, int);
- #endif /* NOTAB */
- int overwrite_mode(int, int);
- int set_default_mode(int,int);
-+int show_raw_mode(int, int);
-
- #ifdef REGEX
- /* re_search.c X */
-diff --git a/display.c b/display.c
-index 7af723c..104f873 100644
---- a/display.c
-+++ b/display.c
-@@ -7,7 +7,7 @@
- * redisplay system knows almost nothing about the editing
- * process; the editing functions do, however, set some
- * hints to eliminate a lot of the grinding. There is more
-- * that can be done; the "vtputc" interface is a real
-+ * that can be done; the "vtputs" interface is a real
- * pig.
- */
-
-@@ -18,6 +18,7 @@
- #include <stdlib.h>
- #include <string.h>
- #include <term.h>
-+#include <wchar.h>
-
- #include "def.h"
- #include "kbd.h"
-@@ -52,11 +53,10 @@ struct score {
- };
-
- void vtmove(int, int);
--void vtputc(int);
- void vtpute(int);
--int vtputs(const char *);
-+int vtputs(const char *, size_t, size_t);
- void vteeol(void);
--void updext(int, int);
-+int updext(int, int);
- void modeline(struct mgwin *, int);
- void setscores(int, int);
- void traceback(int, int, int, int);
-@@ -216,8 +216,8 @@ vtresize(int force, int newrow, int newcol)
- }
- if (rowchanged || colchanged || first_run) {
- for (i = 0; i < 2 * (newrow - 1); i++)
-- TRYREALLOC(video[i].v_text, newcol);
-- TRYREALLOC(blanks.v_text, newcol);
-+ TRYREALLOC(video[i].v_text, newcol * MB_CUR_MAX);
-+ TRYREALLOC(blanks.v_text, newcol * MB_CUR_MAX);
- }
-
- nrow = newrow;
-@@ -260,7 +260,7 @@ vtinit(void)
- */
-
- blanks.v_color = CTEXT;
-- for (i = 0; i < ncol; ++i)
-+ for (i = 0; i < ncol * MB_CUR_MAX; ++i)
- blanks.v_text[i] = ' ';
- }
-
-@@ -287,7 +287,7 @@ vttidy(void)
- * Move the virtual cursor to an origin
- * 0 spot on the virtual display screen. I could
- * store the column as a character pointer to the spot
-- * on the line, which would make "vtputc" a little bit
-+ * on the line, which would make "vtputs" a little bit
- * more efficient. No checking for errors.
- */
- void
-@@ -298,82 +298,6 @@ vtmove(int row, int col)
- }
-
- /*
-- * Write a character to the virtual display,
-- * dealing with long lines and the display of unprintable
-- * things like control characters. Also expand tabs every 8
-- * columns. This code only puts printing characters into
-- * the virtual display image. Special care must be taken when
-- * expanding tabs. On a screen whose width is not a multiple
-- * of 8, it is possible for the virtual cursor to hit the
-- * right margin before the next tab stop is reached. This
-- * makes the tab code loop if you are not careful.
-- * Three guesses how we found this.
-- */
--void
--vtputc(int c)
--{
-- struct video *vp;
--
-- c &= 0xff;
--
-- vp = vscreen[vtrow];
-- if (vtcol >= ncol)
-- vp->v_text[ncol - 1] = '$';
-- else if (c == '\t'
--#ifdef NOTAB
-- && !(curbp->b_flag & BFNOTAB)
--#endif
-- ) {
-- do {
-- vtputc(' ');
-- } while (vtcol < ncol && (vtcol & 0x07) != 0);
-- } else if (ISCTRL(c)) {
-- vtputc('^');
-- vtputc(CCHR(c));
-- } else if (isprint(c))
-- vp->v_text[vtcol++] = c;
-- else {
-- char bf[5];
--
-- snprintf(bf, sizeof(bf), "\\%o", c);
-- vtputs(bf);
-- }
--}
--
--/*
-- * Put a character to the virtual screen in an extended line. If we are not
-- * yet on left edge, don't print it yet. Check for overflow on the right
-- * margin.
-- */
--void
--vtpute(int c)
--{
-- struct video *vp;
--
-- c &= 0xff;
--
-- vp = vscreen[vtrow];
-- if (vtcol >= ncol)
-- vp->v_text[ncol - 1] = '$';
-- else if (c == '\t'
--#ifdef NOTAB
-- && !(curbp->b_flag & BFNOTAB)
--#endif
-- ) {
-- do {
-- vtpute(' ');
-- } while (((vtcol + lbound) & 0x07) != 0 && vtcol < ncol);
-- } else if (ISCTRL(c) != FALSE) {
-- vtpute('^');
-- vtpute(CCHR(c));
-- } else {
-- if (vtcol >= 0)
-- vp->v_text[vtcol] = c;
-- ++vtcol;
-- }
--}
--
--/*
- * Erase from the end of the software cursor to the end of the line on which
- * the software cursor is located. The display routines will decide if a
- * hardware erase to end of line command should be used to display this.
-@@ -384,7 +308,7 @@ vteeol(void)
- struct video *vp;
-
- vp = vscreen[vtrow];
-- while (vtcol < ncol)
-+ while (vtcol < ncol * MB_CUR_MAX)
- vp->v_text[vtcol++] = ' ';
- }
-
-@@ -404,7 +328,7 @@ update(int modelinecolor)
- struct mgwin *wp;
- struct video *vp1;
- struct video *vp2;
-- int c, i, j;
-+ int c, i;
- int hflag;
- int currow, curcol;
- int offs, size;
-@@ -479,8 +403,9 @@ update(int modelinecolor)
- vscreen[i]->v_color = CTEXT;
- vscreen[i]->v_flag |= (VFCHG | VFHBAD);
- vtmove(i, 0);
-- for (j = 0; j < llength(lp); ++j)
-- vtputc(lgetc(lp, j));
-+ if (llength(lp)) {
-+ vtputs(lp->l_text, llength(lp), 0);
-+ }
- vteeol();
- } else if ((wp->w_rflag & (WFEDIT | WFFULL)) != 0) {
- hflag = TRUE;
-@@ -489,8 +414,10 @@ update(int modelinecolor)
- vscreen[i]->v_flag |= (VFCHG | VFHBAD);
- vtmove(i, 0);
- if (lp != wp->w_bufp->b_headp) {
-- for (j = 0; j < llength(lp); ++j)
-- vtputc(lgetc(lp, j));
-+ if (llength(lp)) {
-+ vtputs(lp->l_text, llength(lp),
-+ 0);
-+ }
- lp = lforw(lp);
- }
- vteeol();
-@@ -508,32 +435,53 @@ update(int modelinecolor)
- ++currow;
- lp = lforw(lp);
- }
-+
- curcol = 0;
- i = 0;
- while (i < curwp->w_doto) {
-- c = lgetc(lp, i++);
-+ char tmp[5];
-+ c = lgetc(lp, i);
- if (c == '\t'
- #ifdef NOTAB
- && !(curbp->b_flag & BFNOTAB)
- #endif
- ) {
-- curcol |= 0x07;
- curcol++;
-+ while ((curcol - lbound) & 0x07) {
-+ curcol++;
-+ }
- } else if (ISCTRL(c) != FALSE)
- curcol += 2;
-- else if (isprint(c))
-+ else if (isprint(c)) {
- curcol++;
-- else {
-- char bf[5];
--
-- snprintf(bf, sizeof(bf), "\\%o", c);
-- curcol += strlen(bf);
-+ } else if (!(curbp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+ size_t consumed = mbrtowc(&wc, &lp->l_text[i],
-+ llength(lp) - i, &mbs);
-+ int width = -1;
-+ if (consumed < (size_t) -2) {
-+ width = wcwidth(wc);
-+ } else {
-+ memset(&mbs, 0, sizeof mbs);
-+ }
-+ if (width >= 0) {
-+ curcol += width;
-+ i += (consumed - 1);
-+ } else {
-+ snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ curcol += strlen(tmp);
-+ }
-+ } else {
-+ snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ curcol += strlen(tmp);
- }
-+ i++;
- }
- if (curcol >= ncol - 1) { /* extended line. */
- /* flag we are extended and changed */
- vscreen[currow]->v_flag |= VFEXT | VFCHG;
-- updext(currow, curcol); /* and output extended line */
-+ curcol = updext(currow, curcol);
- } else
- lbound = 0; /* not extended line */
-
-@@ -552,8 +500,10 @@ update(int modelinecolor)
- if ((wp != curwp) || (lp != wp->w_dotp) ||
- (curcol < ncol - 1)) {
- vtmove(i, 0);
-- for (j = 0; j < llength(lp); ++j)
-- vtputc(lgetc(lp, j));
-+ if (llength(lp)) {
-+ vtputs(lp->l_text, llength(lp),
-+ 0);
-+ }
- vteeol();
- /* this line no longer is extended */
- vscreen[i]->v_flag &= ~VFEXT;
-@@ -655,39 +605,44 @@ ucopy(struct video *vvp, struct video *pvp)
- pvp->v_hash = vvp->v_hash;
- pvp->v_cost = vvp->v_cost;
- pvp->v_color = vvp->v_color;
-- bcopy(vvp->v_text, pvp->v_text, ncol);
-+ bcopy(vvp->v_text, pvp->v_text, ncol * MB_CUR_MAX);
- }
-
- /*
-- * updext: update the extended line which the cursor is currently on at a
-- * column greater than the terminal width. The line will be scrolled right or
-- * left to let the user see where the cursor is.
-+ * updext: update the extended line which the cursor is currently on
-+ * at a column greater than the terminal width. The line will be
-+ * scrolled right or left to let the user see where the cursor
-+ * is. curcol may need to be adjusted, depending on how wide
-+ * characters and lbound interact, that adjusted position is returned.
- */
--void
-+int
- updext(int currow, int curcol)
- {
-- struct line *lp; /* pointer to current line */
-- int j; /* index into line */
-+ struct line *lp = curwp->w_dotp; /* pointer to current line */
-+ size_t startbyte;
-+ int bettercol = curcol;
-+ size_t fullextent;
-
- if (ncol < 2)
-- return;
-+ return curcol;
-
- /*
-- * calculate what column the left bound should be
-- * (force cursor into middle half of screen)
-+ * calculate what column the left bound should be (force
-+ * cursor into middle half of screen). Ensuring that it is at
-+ * a tabstop allows update() to calculate curcol without
-+ * wondering how tabstops are calculated before the first '$'.
- */
- lbound = curcol - (curcol % (ncol >> 1)) - (ncol >> 2);
--
-- /*
-- * scan through the line outputing characters to the virtual screen
-- * once we reach the left edge
-- */
-- vtmove(currow, -lbound); /* start scanning offscreen */
-- lp = curwp->w_dotp; /* line to output */
-- for (j = 0; j < llength(lp); ++j) /* until the end-of-line */
-- vtpute(lgetc(lp, j));
-- vteeol(); /* truncate the virtual line */
-- vscreen[currow]->v_text[0] = '$'; /* and put a '$' in column 1 */
-+ lbound = (lbound | 0x07) + 1;
-+ vscreen[currow]->v_text[0] = '$';
-+ vtmove(currow, 1);
-+ startbyte = getbyteofcol(lp, 0, lbound + 1);
-+ fullextent = getbyteofcol(lp, startbyte, ncol + 1);
-+ vtputs(lp->l_text + startbyte, fullextent - startbyte, 1);
-+ vteeol();
-+
-+ bettercol = lbound + getcolofbyte(lp, startbyte, 1, curwp->w_doto);
-+ return (bettercol);
- }
-
- /*
-@@ -702,12 +657,35 @@ updext(int currow, int curcol)
- void
- uline(int row, struct video *vvp, struct video *pvp)
- {
-- char *cp1;
-- char *cp2;
-- char *cp3;
-- char *cp4;
-- char *cp5;
-+ char *cp1; /* Pointer to the start of dirty region */
-+ char *cp2; /* pvp's counterpart for cp1 */
-+ char *cp3; /* Pointer to end of dirty region */
-+ char *cp4; /* pvp's counterpart for cp3 */
-+ char *cp5; /* After this, within dirty region, all is ' ' */
-+ char *mbcounter;
- int nbflag;
-+ int startcol; /* onscreen column matching cp1 */
-+ char *lastbyte; /* byte which handles last onscreen column */
-+ int seencols = 0;
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+
-+ lastbyte = vvp->v_text;
-+ while (seencols < ncol && *lastbyte) {
-+ size_t consumed = mbrtowc(&wc, lastbyte,
-+ (vvp->v_text + ncol * MB_CUR_MAX - lastbyte), &mbs);
-+ if (consumed < (size_t) -2) {
-+ lastbyte += consumed;
-+ seencols += wcwidth(wc);
-+ } else {
-+ lastbyte++;
-+ seencols++;
-+ memset(&mbs, 0, sizeof mbs);
-+ }
-+ }
-+ if (lastbyte - vvp->v_text < ncol) {
-+ lastbyte = &vvp->v_text[ncol];
-+ }
-
- if (vvp->v_color != pvp->v_color) { /* Wrong color, do a */
- ttmove(row, 0); /* full redraw. */
-@@ -723,11 +701,12 @@ uline(int row, struct video *vvp, struct video *pvp)
- * putting the invisible glitch character on the next line.
- * (Hazeltine executive 80 model 30)
- */
-- cp2 = &vvp->v_text[ncol - (magic_cookie_glitch >= 0 ?
-- (magic_cookie_glitch != 0 ? magic_cookie_glitch : 1) : 0)];
-+ cp2 = lastbyte -
-+ (magic_cookie_glitch >= 0 ? (magic_cookie_glitch != 0 ?
-+ magic_cookie_glitch : 1) : 0);
- #else
- cp1 = &vvp->v_text[0];
-- cp2 = &vvp->v_text[ncol];
-+ cp2 = lastbyte;
- #endif
- while (cp1 != cp2) {
- ttputc(*cp1++);
-@@ -738,21 +717,31 @@ uline(int row, struct video *vvp, struct video *pvp)
- }
- cp1 = &vvp->v_text[0]; /* Compute left match. */
- cp2 = &pvp->v_text[0];
-- while (cp1 != &vvp->v_text[ncol] && cp1[0] == cp2[0]) {
-+ while (cp1 != lastbyte && cp1[0] == cp2[0]) {
- ++cp1;
- ++cp2;
- }
-- if (cp1 == &vvp->v_text[ncol]) /* All equal. */
-+ if (cp1 == lastbyte) /* All equal. */
- return;
-+ while (cp1 != vvp->v_text && !isprint(*cp1) &&
-+ mbrtowc(&wc, cp1, (lastbyte - cp1), &mbs) >= (size_t) -2) {
-+ --cp1;
-+ --cp2;
-+ }
- nbflag = FALSE;
-- cp3 = &vvp->v_text[ncol]; /* Compute right match. */
-- cp4 = &pvp->v_text[ncol];
-+ cp3 = lastbyte; /* Compute right match. */
-+ cp4 = &pvp->v_text[lastbyte - vvp->v_text];
- while (cp3[-1] == cp4[-1]) {
- --cp3;
- --cp4;
- if (cp3[0] != ' ') /* Note non-blanks in */
- nbflag = TRUE; /* the right match. */
- }
-+ while (cp3 != lastbyte && !isprint(*cp3) &&
-+ mbrtowc(&wc, cp3, (lastbyte - cp3), &mbs) >= (size_t) -2) {
-+ ++cp3;
-+ ++cp4;
-+ }
- cp5 = cp3; /* Is erase good? */
- if (nbflag == FALSE && vvp->v_color == CTEXT) {
- while (cp5 != cp1 && cp5[-1] == ' ')
-@@ -762,13 +751,27 @@ uline(int row, struct video *vvp, struct video *pvp)
- cp5 = cp3;
- }
- /* Alcyon hack */
-- ttmove(row, (int) (cp1 - &vvp->v_text[0]));
-+ startcol = 0;
-+ mbcounter = vvp->v_text;
-+ while ((cp1 - mbcounter) > 0) {
-+ size_t consumed = mbrtowc(&wc, mbcounter, (cp1 - mbcounter),
-+ &mbs);
-+ if (consumed < (size_t) -2) {
-+ mbcounter += consumed;
-+ startcol += wcwidth(wc);
-+ } else {
-+ mbcounter++;
-+ startcol++;
-+ memset(&mbs, 0, sizeof mbs);
-+ }
-+ }
-+ ttmove(row, startcol);
- #ifdef STANDOUT_GLITCH
- if (vvp->v_color != CTEXT && magic_cookie_glitch > 0) {
- if (cp1 < &vvp->v_text[magic_cookie_glitch])
- cp1 = &vvp->v_text[magic_cookie_glitch];
-- if (cp5 > &vvp->v_text[ncol - magic_cookie_glitch])
-- cp5 = &vvp->v_text[ncol - magic_cookie_glitch];
-+ if (cp5 > lastbyte - magic_cookie_glitch)
-+ cp5 = lastbyte - magic_cookie_glitch;
- } else if (magic_cookie_glitch < 0)
- #endif
- ttcolor(vvp->v_color);
-@@ -801,46 +804,39 @@ modeline(struct mgwin *wp, int modelinecolor)
- vscreen[n]->v_flag |= (VFCHG | VFHBAD); /* Recompute, display. */
- vtmove(n, 0); /* Seek to right line. */
- bp = wp->w_bufp;
-- vtputc('-');
-- vtputc('-');
-+ n = vtputs("--", 0, 0);
- if ((bp->b_flag & BFREADONLY) != 0) {
-- vtputc('%');
-+ n += vtputs("%", 0, n);
- if ((bp->b_flag & BFCHG) != 0)
-- vtputc('*');
-+ n += vtputs("*", 0, n);
- else
-- vtputc('%');
-+ n += vtputs("%", 0, n);
- } else if ((bp->b_flag & BFCHG) != 0) { /* "*" if changed. */
-- vtputc('*');
-- vtputc('*');
-+ n += vtputs("**", 0, n);
- } else {
-- vtputc('-');
-- vtputc('-');
-+ n += vtputs("--", 0, n);
- }
-- vtputc('-');
-+ n += vtputs("-", 0, n);
- n = 5;
-- n += vtputs("Mg: ");
-+ n += vtputs("Mg: ", 0, n);
- if (bp->b_bname[0] != '\0')
-- n += vtputs(&(bp->b_bname[0]));
-+ n += vtputs(&(bp->b_bname[0]), 0, n);
- while (n < 42) { /* Pad out with blanks. */
-- vtputc(' ');
-- ++n;
-+ n += vtputs(" ", 0, n);
- }
-- vtputc('(');
-- ++n;
-+ n += vtputs("(", 0, n);
- for (md = 0; ; ) {
-- n += vtputs(bp->b_modes[md]->p_name);
-+ n += vtputs(bp->b_modes[md]->p_name, 0, n);
- if (++md > bp->b_nmodes)
- break;
-- vtputc('-');
-- ++n;
-+ n += vtputs("-", 0, n);
- }
- /* XXX These should eventually move to a real mode */
- if (macrodef == TRUE)
-- n += vtputs("-def");
-+ n += vtputs("-def", 0, n);
- if (globalwd == TRUE)
-- n += vtputs("-gwd");
-- vtputc(')');
-- ++n;
-+ n += vtputs("-gwd", 0, n);
-+ n += vtputs(")", 0, n);
-
- if (linenos && colnos)
- len = snprintf(sl, sizeof(sl), "--L%d--C%d", wp->w_dotline,
-@@ -850,27 +846,132 @@ modeline(struct mgwin *wp, int modelinecolor)
- else if (colnos)
- len = snprintf(sl, sizeof(sl), "--C%d", getcolpos(wp));
- if ((linenos || colnos) && len < sizeof(sl) && len != -1)
-- n += vtputs(sl);
-+ n += vtputs(sl, 0, n);
-
- while (n < ncol) { /* Pad out. */
-- vtputc('-');
-- ++n;
-+ n += vtputs("-", 0, n);
- }
- }
-
- /*
-- * Output a string to the mode line, report how long it was.
-+ * Output a string to the mode line, report how long it was,
-+ * dealing with long lines and the display of unprintable
-+ * things like control characters. Also expand tabs every 8
-+ * columns. This code only puts printing characters into
-+ * the virtual display image. Special care must be taken when
-+ * expanding tabs. On a screen whose width is not a multiple
-+ * of 8, it is possible for the virtual cursor to hit the
-+ * right margin before the next tab stop is reached. This
-+ * makes the tab code loop if you are not careful.
-+ * Three guesses how we found this.
- */
- int
--vtputs(const char *s)
-+vtputs(const char *s, const size_t max_bytes, const size_t initial_col)
- {
-- int n = 0;
-+ const unsigned char *us = (const unsigned char *) s;
-+ struct video *vp = vscreen[vtrow];
-+ size_t bytes_handled = 0;
-+ size_t last_full_byte_start = vtcol;
-+ size_t space_printed = 0;
-+
-+ if (!s) {
-+ return (0);
-+ }
-+
-+ while (*us && (!max_bytes || bytes_handled < max_bytes)) {
-+ if (space_printed + initial_col >= ncol) {
-+ break;
-+ } else if (*us == '\t'
-+#ifdef NOTAB
-+ && !(curbp->b_flag & BFNOTAB)
-+#endif
-+ ) {
-+ last_full_byte_start = vtcol;
-+ do {
-+ if (vtcol >= 0) {
-+ last_full_byte_start = vtcol;
-+ vp->v_text[vtcol] = ' ';
-+ }
-+ vtcol++;
-+ space_printed++;
-+ } while (space_printed + initial_col < ncol &&
-+ ((space_printed + initial_col) & 0x07));
-+ us++;
-+ bytes_handled++;
-+ } else if (ISCTRL(*us)) {
-+ last_full_byte_start = vtcol;
-+ if (vtcol >= 0) {
-+ vp->v_text[vtcol] = '^';
-+ }
-+ vtcol++;
-+ if (vtcol >= 0) {
-+ vp->v_text[vtcol] = CCHR(*us);
-+ }
-+ vtcol++;
-+ bytes_handled++;
-+ space_printed += 2;
-+ us++;
-+ } else if (isprint(*us)) {
-+ last_full_byte_start = vtcol;
-+ if (vtcol >= 0) {
-+ vp->v_text[vtcol] = *us++;
-+ }
-+ vtcol++;
-+ bytes_handled++;
-+ space_printed++;
-+ } else if (!(curbp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+ size_t consumable = max_bytes ?
-+ (max_bytes - bytes_handled) : -1;
-+ size_t consumed = mbrtowc(&wc, (const char *)us,
-+ consumable, &mbs);
-+ int width = -1;
-+ last_full_byte_start = vtcol;
-+ if (consumed < (size_t) -2) {
-+ width = wcwidth(wc);
-+ }
-+ if (width >= 0) {
-+ bytes_handled += consumed;
-+ space_printed += width;
-+ do {
-+ if (vtcol >= 0) {
-+ vp->v_text[vtcol] = *us++;
-+ }
-+ vtcol++;
-+ } while (--consumed);
-+ } else {
-+ char bf[5];
-+ snprintf(bf, sizeof(bf), "\\%o", *us);
-+ bytes_handled++;
-+ space_printed += vtputs(bf, 0,
-+ space_printed + initial_col);
-+ us++;
-+ }
-+ } else {
-+ char bf[5];
-+ last_full_byte_start = vtcol;
-+ snprintf(bf, sizeof(bf), "\\%o", *us);
-+ bytes_handled++;
-+ space_printed += vtputs(bf, 0,
-+ space_printed + initial_col);
-+ us++;
-+ }
-+ }
-
-- while (*s != '\0') {
-- vtputc(*s++);
-- ++n;
-+ if ((space_printed + initial_col > ncol) ||
-+ (space_printed + initial_col == ncol &&
-+ (*us && (!max_bytes || bytes_handled < max_bytes)))) {
-+ vp->v_text[last_full_byte_start] = '$';
-+ while (++last_full_byte_start <= vtcol) {
-+ vp->v_text[last_full_byte_start] = ' ';
-+ }
-+ bytes_handled++;
-+ space_printed++;
-+ us++;
- }
-- return (n);
-+
-+ return (space_printed);
- }
-
- /*
-@@ -888,11 +989,11 @@ hash(struct video *vp)
- char *s;
-
- if ((vp->v_flag & VFHBAD) != 0) { /* Hash bad. */
-- s = &vp->v_text[ncol - 1];
-- for (i = ncol; i != 0; --i, --s)
-+ s = &vp->v_text[ncol * MB_CUR_MAX - 1];
-+ for (i = ncol * MB_CUR_MAX; i != 0; --i, --s)
- if (*s != ' ')
- break;
-- n = ncol - i; /* Erase cheaper? */
-+ n = ncol * MB_CUR_MAX - i; /* Erase cheaper? */
- if (n > tceeol)
- n = tceeol;
- vp->v_cost = i + n; /* Bytes + blanks. */
-diff --git a/echo.c b/echo.c
-index 6966c00..22b8333 100644
---- a/echo.c
-+++ b/echo.c
-@@ -844,9 +844,11 @@ ewprintf(const char *fmt, ...)
- * %k prints the name of the current key (and takes no arguments).
- * %d prints a decimal integer
- * %o prints an octal integer
-+ * %x prints a hexadecimal integer
- * %p prints a pointer
- * %s prints a string
- * %ld prints a long word
-+ * %lx prints a hexadecimal long word
- * Anything else is echoed verbatim
- */
- static void
-@@ -885,6 +887,10 @@ eformat(const char *fp, va_list ap)
- eputi(va_arg(ap, int), 8);
- break;
-
-+ case 'x':
-+ eputi(va_arg(ap, int), 16);
-+ break;
-+
- case 'p':
- snprintf(tmp, sizeof(tmp), "%p",
- va_arg(ap, void *));
-@@ -902,6 +908,9 @@ eformat(const char *fp, va_list ap)
- case 'd':
- eputl(va_arg(ap, long), 10);
- break;
-+ case 'x':
-+ eputl(va_arg(ap, long), 16);
-+ break;
- default:
- eputc(c);
- break;
-@@ -939,6 +948,7 @@ static void
- eputl(long l, int r)
- {
- long q;
-+ int c;
-
- if (l < 0) {
- eputc('-');
-@@ -946,7 +956,10 @@ eputl(long l, int r)
- }
- if ((q = l / r) != 0)
- eputl(q, r);
-- eputc((int)(l % r) + '0');
-+ c = (int)(l % r) + '0';
-+ if (c > '9')
-+ c += 'a' - '9' - 1;
-+ eputc(c);
- }
-
- /*
-diff --git a/funmap.c b/funmap.c
-index bd555d6..7d88b75 100644
---- a/funmap.c
-+++ b/funmap.c
-@@ -114,6 +114,7 @@ static struct funmap functnames[] = {
- {bufferinsert, "insert-buffer",},
- {fileinsert, "insert-file",},
- {fillword, "insert-with-wrap",},
-+ {insert_char, "insert-char",},
- {backisearch, "isearch-backward",},
- {forwisearch, "isearch-forward",},
- {joinline, "join-line",},
-@@ -191,6 +192,7 @@ static struct funmap functnames[] = {
- {shellcommand, "shell-command",},
- {piperegion, "shell-command-on-region",},
- {shrinkwind, "shrink-window",},
-+ {show_raw_mode, "show-raw-mode",},
- #ifdef NOTAB
- {space_to_tabstop, "space-to-tabstop",},
- #endif /* NOTAB */
-diff --git a/kbd.c b/kbd.c
-index 1d7a1a2..f613b10 100644
---- a/kbd.c
-+++ b/kbd.c
-@@ -9,6 +9,8 @@
- #include <sys/queue.h>
- #include <signal.h>
- #include <stdio.h>
-+#include <stdlib.h>
-+#include <wchar.h>
-
- #include "def.h"
- #include "kbd.h"
-@@ -406,6 +408,43 @@ quote(int f, int n)
- }
-
- /*
-+ * Prompt for a codepoint in whatever the native system's encoding is,
-+ * insert it into the file
-+ */
-+int
-+insert_char(int f, int n)
-+{
-+ char *bufp;
-+ char inpbuf[32];
-+ wchar_t wc;
-+ char mb[MB_CUR_MAX + 1];
-+ mbstate_t mbs = { 0 };
-+ size_t mbslen;
-+ size_t i;
-+
-+ if ((bufp = eread("Insert character (hex): ", inpbuf, sizeof inpbuf,
-+ EFNEW)) == NULL) {
-+ return (ABORT);
-+ } else if (bufp[0] == '\0') {
-+ return (FALSE);
-+ }
-+
-+ wc = (wchar_t) strtoll(bufp, NULL, 16);
-+ mbslen = wcrtomb(mb, wc, &mbs);
-+ if (mbslen == (size_t) -1) {
-+ return (FALSE);
-+ }
-+
-+ for (i = 0; i < mbslen; ++i) {
-+ if (linsert(1, mb[i]) == FALSE) {
-+ return (FALSE);
-+ }
-+ }
-+
-+ return (TRUE);
-+}
-+
-+/*
- * Wraper function to count invocation repeats.
- * We ignore any function whose sole purpose is to get us
- * to the intended function.
-diff --git a/keymap.c b/keymap.c
-index ef71f84..ab23182 100644
---- a/keymap.c
-+++ b/keymap.c
-@@ -120,6 +120,21 @@ static struct KEYMAPE (2) cX4map = {
- }
- };
-
-+static PF cX8J[] = {
-+ insert_char /* ^M */
-+};
-+
-+static struct KEYMAPE (1) cX8map = {
-+ 1,
-+ 1,
-+ rescan,
-+ {
-+ {
-+ CCHR('M'), CCHR('M'), cX8J, NULL
-+ }
-+ }
-+};
-+
- static PF cXcB[] = {
- listbuffers, /* ^B */
- quit, /* ^C */
-@@ -158,6 +173,10 @@ static PF cX0[] = {
- NULL /* 4 */
- };
-
-+static PF cX8[] = {
-+ NULL /* 4 */
-+};
-+
- static PF cXeq[] = {
- showcpos /* = */
- };
-@@ -189,9 +208,9 @@ static PF cXcar[] = {
- undo /* u */
- };
-
--struct KEYMAPE (6) cXmap = {
-- 6,
-- 6,
-+struct KEYMAPE (7) cXmap = {
-+ 7,
-+ 7,
- rescan,
- {
- {
-@@ -207,6 +226,9 @@ struct KEYMAPE (6) cXmap = {
- '0', '4', cX0, (KEYMAP *) & cX4map
- },
- {
-+ '8', '8', cX8, (KEYMAP *) & cX8map
-+ },
-+ {
- '=', '=', cXeq, NULL
- },
- {
-@@ -491,6 +513,18 @@ static struct KEYMAPE (1) overwmap = {
- }
- };
-
-+static struct KEYMAPE (1) rawmap = {
-+ 0,
-+ 1, /* 1 to avoid 0 sized array */
-+ rescan,
-+ {
-+ /* unused dummy entry for VMS C */
-+ {
-+ (KCHAR)0, (KCHAR)0, NULL, NULL
-+ }
-+ }
-+};
-+
-
- /*
- * The basic (root) keyboard map
-@@ -513,6 +547,7 @@ static struct maps_s map_table[] = {
- {(KEYMAP *) &notabmap, "notab",},
- #endif /* NOTAB */
- {(KEYMAP *) &overwmap, "overwrite",},
-+ {(KEYMAP *) &rawmap, "raw",},
- {(KEYMAP *) &metamap, "esc prefix",},
- {(KEYMAP *) &cXmap, "c-x prefix",},
- {(KEYMAP *) &cX4map, "c-x 4 prefix",},
-diff --git a/modes.c b/modes.c
-index 027a5cd..2013bcb 100644
---- a/modes.c
-+++ b/modes.c
-@@ -111,6 +111,23 @@ overwrite_mode(int f, int n)
- }
-
- int
-+show_raw_mode(int f, int n)
-+{
-+ if (changemode(f, n, "raw") == FALSE)
-+ return (FALSE);
-+ if (f & FFARG) {
-+ if (n <= 0)
-+ curbp->b_flag &= ~BFSHOWRAW;
-+ else
-+ curbp->b_flag |= BFSHOWRAW;
-+ } else
-+ curbp->b_flag ^= BFSHOWRAW;
-+
-+ sgarbf = TRUE;
-+ return (TRUE);
-+}
-+
-+int
- set_default_mode(int f, int n)
- {
- int i;
-@@ -170,5 +187,11 @@ set_default_mode(int f, int n)
- defb_flag |= BFNOTAB;
- }
- #endif /* NOTAB */
-+ if (strcmp(modebuf, "raw") == 0) {
-+ if (n <= 0)
-+ defb_flag &= ~BFSHOWRAW;
-+ else
-+ defb_flag |= BFSHOWRAW;
-+ }
- return (TRUE);
- }
-diff --git a/util.c b/util.c
-index 9357d4d..dbfc058 100644
---- a/util.c
-+++ b/util.c
-@@ -13,6 +13,8 @@
- #include <ctype.h>
- #include <signal.h>
- #include <stdio.h>
-+#include <stdlib.h>
-+#include <wchar.h>
-
- #include "def.h"
-
-@@ -33,6 +35,9 @@ showcpos(int f, int n)
- int nline, row;
- int cline, cbyte; /* Current line/char/byte */
- int ratio;
-+ char ismb = 0;
-+ wchar_t wc = 0;
-+ char mbc[MB_CUR_MAX + 1];
-
- /* collect the data */
- clp = bfirstlp(curbp);
-@@ -69,8 +74,43 @@ showcpos(int f, int n)
- clp = lforw(clp);
- }
- ratio = nchar ? (100L * cchar) / nchar : 100;
-- ewprintf("Char: %c (0%o) point=%ld(%d%%) line=%d row=%d col=%d",
-- cbyte, cbyte, cchar, ratio, cline, row, getcolpos(curwp));
-+
-+ if (!(curbp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ size_t consumed = 0;
-+ size_t offset = 0;
-+ while (cbyte != '\n' && offset <= curwp->w_doto) {
-+ int c = lgetc(clp, curwp->w_doto - offset);
-+ if (isprint(c) || (ISCTRL(c) != FALSE)) {
-+ break;
-+ }
-+ consumed = mbrtowc(&wc,
-+ &clp->l_text[curwp->w_doto - offset],
-+ llength(clp) - curwp->w_doto + offset,
-+ &mbs);
-+ if (consumed < (size_t) -2) {
-+ ismb = (offset < consumed);
-+ snprintf(mbc, consumed + 1, "%s",
-+ &clp->l_text[curwp->w_doto - offset]);
-+ mbc[consumed + 1] = '\0';
-+ break;
-+ } else {
-+ memset(&mbs, 0, sizeof mbs);
-+ }
-+ offset++;
-+ }
-+ }
-+
-+ if (ismb) {
-+ ewprintf("Char: %s (codepoint 0x%lx) Byte: %c (0%o) "
-+ "point=%ld(%d%%) line=%d row=%d col=%d", mbc,
-+ (long) wc, cbyte, cbyte, cchar, ratio, cline, row,
-+ getcolpos(curwp));
-+ } else {
-+ ewprintf("Char: %c (0%o) point=%ld(%d%%) line=%d row=%d"
-+ "col=%d", cbyte, cbyte, cchar, ratio, cline, row,
-+ getcolpos(curwp));
-+ }
- return (TRUE);
- }
-
-@@ -96,6 +136,22 @@ getcolpos(struct mgwin *wp)
- col += 2;
- else if (isprint(c)) {
- col++;
-+ } else if (!(wp->w_bufp->b_flag & BFSHOWRAW)) {
-+ mbstate_t mbs = { 0 };
-+ wchar_t wc = 0;
-+ size_t consumed = mbrtowc(&wc, &wp->w_dotp->l_text[i],
-+ llength(wp->w_dotp) - i,
-+ &mbs);
-+ int width = -1;
-+ if (consumed < (size_t) -2) {
-+ width = wcwidth(wc);
-+ }
-+ if (width >= 0) {
-+ col += width;
-+ i += (consumed - 1);
-+ } else {
-+ col += snprintf(tmp, sizeof(tmp), "\\%o", c);
-+ }
- } else {
- col += snprintf(tmp, sizeof(tmp), "\\%o", c);
- }