top: enable processing utf8 multi-byte character input
This program was well equipped to properly handle utf8 multi-byte characters - except for one important area! If users typed any unicode character (shift+ctrl+u) or pasted a utf-8 multi-byte string as a response to some input prompt, those characters would simply be ignored since they would not pass the internal 'isprint' test. Well, now we can handle such data while preserving all line editing provisions such as insertions, deletions, destructive backspace, prior line recall (up/down) and those all important cursor left plus right arrow keys. [ we even support overtype mode for multi-byte stuff ] [ even though our gui emulator will not let us alter ] [ the cursor as confirmation (as we do at a console) ] Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
parent
970a3dc990
commit
c20fef1d7d
110
top/top.c
110
top/top.c
@ -1157,7 +1157,7 @@ static int iokey (int action) {
|
|||||||
#ifdef TERMIOS_ONLY
|
#ifdef TERMIOS_ONLY
|
||||||
char buf[SMLBUFSIZ], *pb;
|
char buf[SMLBUFSIZ], *pb;
|
||||||
#else
|
#else
|
||||||
static char buf[SMLBUFSIZ];
|
static char buf[MEDBUFSIZ];
|
||||||
static int pos, len;
|
static int pos, len;
|
||||||
char *pb;
|
char *pb;
|
||||||
#endif
|
#endif
|
||||||
@ -1196,7 +1196,7 @@ static int iokey (int action) {
|
|||||||
pos = len = 0;
|
pos = len = 0;
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
if (1 > ioch(0, buf, sizeof(buf)-1)) return 0;
|
if (1 > ioch(0, buf, sizeof(buf)-1)) return 0;
|
||||||
if (isprint(buf[0])) { // no need for translation
|
if (!iscntrl(buf[0])) { // no need for translation
|
||||||
len = strlen(buf);
|
len = strlen(buf);
|
||||||
pos = 1;
|
pos = 1;
|
||||||
return buf[0];
|
return buf[0];
|
||||||
@ -1240,44 +1240,56 @@ static char *ioline (const char *prompt) {
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* Get line oriented interactive input from the user,
|
* Get some line oriented interactive input from the ol' user,
|
||||||
* going way beyond native tty support by providing:
|
* going way, way beyond that native tty support by providing:
|
||||||
* . true line editing, not just destructive backspace
|
* . true input line editing, not just a destructive backspace
|
||||||
* . an input limit sensitive to current screen dimensions
|
* . an input limit sensitive to the current screen dimensions
|
||||||
* . ability to recall prior strings for re-input/re-editing */
|
* . an ability to recall prior strings for editing & re-input */
|
||||||
static char *ioline (const char *prompt) {
|
static char *ioline (const char *prompt) {
|
||||||
|
#define setLEN ( len = strlen(buf) - utf8_delta(buf) )
|
||||||
|
#define setPOS(X) ( pos = utf8_embody(buf, X) )
|
||||||
|
#define utfCHR(X) ( (unsigned char *)&buf[X] )
|
||||||
|
#define utfTOT(X) ( UTF8_tab[(unsigned char)buf[X]] )
|
||||||
|
#define utfCOL(X) ( utf8_cols(utfCHR(X), utfTOT(X)) )
|
||||||
|
#define movBKW { setPOS(cur - 1); while (utfTOT(pos) < 0) --pos; }
|
||||||
|
#define chkCUR { if (cur < 0) cur = 0; if (cur > len) cur = len; }
|
||||||
|
// thank goodness ol' memmove will safely allow strings to overlap
|
||||||
|
#define sqzSTR { i = utfTOT(pos); while (i < 0) i = utfTOT(--pos); \
|
||||||
|
memmove(&buf[pos], &buf[pos + i], bufMAX-(pos + i)); \
|
||||||
|
memset(&buf[bufMAX - i], '\0', i); }
|
||||||
|
#define expSTR(X) if (bufNXT < bufMAX && scrNXT < Screen_cols) { \
|
||||||
|
memmove(&buf[pos + X], &buf[pos], bufMAX - pos); }
|
||||||
#define savMAX 50
|
#define savMAX 50
|
||||||
// thank goodness memmove allows the two strings to overlap
|
#define bufNXT ( pos + 4 ) // four equals longest utf8 str
|
||||||
#define sqzSTR { memmove(&buf[pos], &buf[pos+1], bufMAX-pos); \
|
#define scrNXT ( beg + len + 2 ) // two due to multi-column char
|
||||||
buf[sizeof(buf)-1] = '\0'; }
|
|
||||||
#define expSTR if (len+1 < bufMAX && len+beg+1 < Screen_cols) { \
|
|
||||||
memmove(&buf[pos+1], &buf[pos], bufMAX-pos); buf[pos] = ' '; }
|
|
||||||
#define logCOL (pos+1)
|
|
||||||
#define phyCOL (beg+pos+1)
|
|
||||||
#define bufMAX ((int)sizeof(buf)-2) // -1 for '\0' string delimeter
|
#define bufMAX ((int)sizeof(buf)-2) // -1 for '\0' string delimeter
|
||||||
static char buf[MEDBUFSIZ+1]; // +1 for '\0' string delimeter
|
static char buf[MEDBUFSIZ+1]; // +1 for '\0' string delimeter
|
||||||
static int ovt;
|
static int ovt;
|
||||||
int beg, pos, len, key, i;
|
int beg, // the physical column where input began, buf[0]
|
||||||
|
cur, // the logical current column/insertion position
|
||||||
|
len, // the logical input length, thus the end column
|
||||||
|
pos, // the physical position in the buffer currently
|
||||||
|
key, i;
|
||||||
struct lin_s {
|
struct lin_s {
|
||||||
struct lin_s *bkw; // ptr to older saved strs
|
struct lin_s *bkw; // pointer for older saved strs
|
||||||
struct lin_s *fwd; // ptr to newer saved strs
|
struct lin_s *fwd; // pointer for newer saved strs
|
||||||
char *str; // the saved string
|
char *str; // an actual saved input string
|
||||||
};
|
};
|
||||||
static struct lin_s *anchor, *plin;
|
static struct lin_s *anchor, *plin;
|
||||||
|
|
||||||
if (!anchor) {
|
if (!anchor) {
|
||||||
anchor = alloc_c(sizeof(struct lin_s));
|
anchor = alloc_c(sizeof(struct lin_s));
|
||||||
anchor->str = alloc_s(""); // top-of-stack == empty str
|
anchor->str = alloc_s(""); // the top-of-stack (empty str)
|
||||||
}
|
}
|
||||||
plin = anchor;
|
plin = anchor;
|
||||||
pos = 0;
|
cur = len = pos = 0;
|
||||||
beg = show_pmt(prompt);
|
beg = show_pmt(prompt);
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
|
// this may not work under a gui emulator (but linux console is ok)
|
||||||
putp(ovt ? Cap_curs_huge : Cap_curs_norm);
|
putp(ovt ? Cap_curs_huge : Cap_curs_norm);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
len = strlen(buf);
|
|
||||||
key = iokey(IOKEY_NEXT);
|
key = iokey(IOKEY_NEXT);
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -1287,6 +1299,7 @@ static char *ioline (const char *prompt) {
|
|||||||
buf[0] = kbd_ESC;
|
buf[0] = kbd_ESC;
|
||||||
return buf;
|
return buf;
|
||||||
case kbd_ENTER:
|
case kbd_ENTER:
|
||||||
|
case kbd_BTAB: case kbd_PGUP: case kbd_PGDN:
|
||||||
continue;
|
continue;
|
||||||
case kbd_INS:
|
case kbd_INS:
|
||||||
ovt = !ovt;
|
ovt = !ovt;
|
||||||
@ -1295,45 +1308,63 @@ static char *ioline (const char *prompt) {
|
|||||||
case kbd_DEL:
|
case kbd_DEL:
|
||||||
sqzSTR
|
sqzSTR
|
||||||
break;
|
break;
|
||||||
case kbd_BKSP :
|
case kbd_BKSP:
|
||||||
if (0 < pos) { --pos; sqzSTR }
|
if (0 < cur) { movBKW; cur -= utfCOL(pos); setPOS(cur); sqzSTR; }
|
||||||
break;
|
break;
|
||||||
case kbd_LEFT:
|
case kbd_LEFT:
|
||||||
if (0 < pos) --pos;
|
if (0 < cur) { movBKW; cur -= utfCOL(pos); }
|
||||||
break;
|
break;
|
||||||
case kbd_RIGHT:
|
case kbd_RIGHT:
|
||||||
if (pos < len) ++pos;
|
if (cur < len) cur += utfCOL(pos);
|
||||||
break;
|
break;
|
||||||
case kbd_HOME:
|
case kbd_HOME:
|
||||||
pos = 0;
|
cur = pos = 0;
|
||||||
break;
|
break;
|
||||||
case kbd_END:
|
case kbd_END:
|
||||||
pos = len;
|
cur = len;
|
||||||
|
pos = strlen(buf);
|
||||||
break;
|
break;
|
||||||
case kbd_UP:
|
case kbd_UP:
|
||||||
if (plin->bkw) {
|
if (plin->bkw) {
|
||||||
plin = plin->bkw;
|
plin = plin->bkw;
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
pos = snprintf(buf, sizeof(buf), "%.*s", Screen_cols - beg - 1, plin->str);
|
memccpy(buf, plin->str, '\0', bufMAX);
|
||||||
|
cur = setLEN;
|
||||||
|
pos = strlen(buf);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kbd_DOWN:
|
case kbd_DOWN:
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
if (plin->fwd) plin = plin->fwd;
|
if (plin->fwd) plin = plin->fwd;
|
||||||
pos = snprintf(buf, sizeof(buf), "%.*s", Screen_cols - beg - 1, plin->str);
|
memset(buf, '\0', sizeof(buf));
|
||||||
|
memccpy(buf, plin->str, '\0', bufMAX);
|
||||||
|
cur = setLEN;
|
||||||
|
pos = strlen(buf);
|
||||||
break;
|
break;
|
||||||
default: // what we REALLY wanted (maybe)
|
default: // what we REALLY wanted (maybe)
|
||||||
if (isprint(key) && logCOL < bufMAX && phyCOL < Screen_cols) {
|
if (bufNXT < bufMAX && scrNXT < Screen_cols) {
|
||||||
if (!ovt) expSTR
|
int tot = UTF8_tab[(unsigned char)key],
|
||||||
|
sav = pos;
|
||||||
|
if (tot < 1) tot = 1;
|
||||||
|
if (!ovt) { expSTR(tot); }
|
||||||
|
else { pos = utf8_embody(buf, cur); sqzSTR; expSTR(tot); }
|
||||||
buf[pos++] = key;
|
buf[pos++] = key;
|
||||||
|
while (tot > 1) {
|
||||||
|
key = iokey(IOKEY_NEXT);
|
||||||
|
buf[pos++] = key;
|
||||||
|
--tot;
|
||||||
|
}
|
||||||
|
cur += utfCOL(sav);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
setLEN;
|
||||||
|
chkCUR;
|
||||||
|
setPOS(cur);
|
||||||
putp(fmtmk("%s%s%s", tg2(beg, Msg_row), Cap_clr_eol, buf));
|
putp(fmtmk("%s%s%s", tg2(beg, Msg_row), Cap_clr_eol, buf));
|
||||||
#ifdef OVERTYPE_SEE
|
#ifdef OVERTYPE_SEE
|
||||||
putp(fmtmk("%s%c", tg2(beg - 1, Msg_row), ovt ? '^' : ' '));
|
putp(fmtmk("%s%c", tg2(beg - 1, Msg_row), ovt ? '^' : ' '));
|
||||||
#endif
|
#endif
|
||||||
putp(tg2(beg+pos, Msg_row));
|
putp(tg2(beg + cur, Msg_row));
|
||||||
} while (key != kbd_ENTER);
|
} while (key != kbd_ENTER);
|
||||||
|
|
||||||
// weed out duplicates, including empty strings (top-of-stack)...
|
// weed out duplicates, including empty strings (top-of-stack)...
|
||||||
@ -1372,11 +1403,18 @@ static char *ioline (const char *prompt) {
|
|||||||
anchor->bkw = plin; // by sliding it in as new number 2!
|
anchor->bkw = plin; // by sliding it in as new number 2!
|
||||||
|
|
||||||
return buf; // protect our copy, return original
|
return buf; // protect our copy, return original
|
||||||
#undef savMAX
|
#undef setLEN
|
||||||
|
#undef setPOS
|
||||||
|
#undef utfCHR
|
||||||
|
#undef utfTOT
|
||||||
|
#undef utfCOL
|
||||||
|
#undef movBKW
|
||||||
|
#undef chkCUR
|
||||||
#undef sqzSTR
|
#undef sqzSTR
|
||||||
#undef expSTR
|
#undef expSTR
|
||||||
#undef logCOL
|
#undef savMAX
|
||||||
#undef phyCOL
|
#undef bufNXT
|
||||||
|
#undef scrNXT
|
||||||
#undef bufMAX
|
#undef bufMAX
|
||||||
} // end: ioline
|
} // end: ioline
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user