mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2026-01-21 16:41:52 +01:00
1348 lines
35 KiB
Diff
1348 lines
35 KiB
Diff
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);
|
||
}
|