diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/mg/APKBUILD | 10 | ||||
-rw-r--r-- | main/mg/unicode.patch | 1347 |
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 *) ¬abmap, "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); - } |