about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/Zle/complist.c23
-rw-r--r--Src/Zle/zle.h36
-rw-r--r--Src/Zle/zle_hist.c60
-rw-r--r--Src/Zle/zle_main.c10
-rw-r--r--Src/Zle/zle_misc.c93
-rw-r--r--Src/Zle/zle_move.c8
-rw-r--r--Src/Zle/zle_params.c8
-rw-r--r--Src/Zle/zle_refresh.c4
-rw-r--r--Src/Zle/zle_tricky.c13
-rw-r--r--Src/Zle/zle_utils.c74
-rw-r--r--Src/Zle/zle_vi.c27
12 files changed, 199 insertions, 164 deletions
diff --git a/ChangeLog b/ChangeLog
index 5da864b9a..256978edb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2005-02-23  Peter Stephenson  <pws@csr.com>
+
+	* 20854: Src/Zle/complist.c, Src/Zle/zle.h, Src/Zle/zle_hist.c,
+	Src/Zle/zle_main.c, Src/Zle/zle_misc.c, Src/Zle/zle_move.c,
+	Src/Zle/zle_params.c, Src/Zle/zle_refresh.c, Src/Zle/zle_tricky.c,
+	Src/Zle/zle_utils.c, Src/Zle/zle_vi.c: more Unicode stuff.
+
 2005-02-23  Clint Adams  <clint@zsh.org>
 
 	* 20847: Completion/compaudit: stop adding gratuitous
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 748b1fdf7..b0baa490f 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -1861,7 +1861,11 @@ msearchpop(int *backp)
 static Cmatch **
 msearch(Cmatch **ptr, int ins, int back, int rep, int *wrapp)
 {
+#ifdef ZLE_UNICODE_SUPPORT
+    char s[MB_CUR_MAX+1];
+#else
     char s[2];
+#endif
     Cmatch **p, *l = NULL, m;
     int x = mcol, y = mline;
     int ex, ey, wrap = 0, owrap = (msearchstate & MS_WRAPPED);
@@ -1869,12 +1873,19 @@ msearch(Cmatch **ptr, int ins, int back, int rep, int *wrapp)
     msearchpush(ptr, back);
 
     if (ins) {
-	/*
-	 * TODO: probably need to convert back to multibyte character
-	 * string?  Who knows...
-	 */
-        s[0] = lastchar;
-        s[1] = '\0';
+#ifdef ZLE_UNICODE_SUPPORT
+	if (lastchar_wide_valid)
+	{
+	    int len = wctomb(s, lastchar_wide);
+	    if (len < 0)
+		len = 0;
+	    s[len] = '\0';
+	} else
+#endif
+	{
+	    s[0] = lastchar;
+	    s[1] = '\0';
+	}
 
         msearchstr = dyncat(msearchstr, s);
     }
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 9c99f0b75..c95959776 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -44,21 +44,9 @@ typedef wint_t   ZLE_INT_T;
 #define MB_CUR_MAX 6
 #endif
 
-#define ZLENL	L'\n'
-#define ZLENUL	L'\0'
-#define ZLETAB	L'\t'
-#define ZLESPC	L' '
-
-#define DIGIT_1		L'1'
-#define DIGIT_9		L'9'
-#define LETTER_a	L'a'
-#define LETTER_z	L'z'
-#define LETTER_A	L'A'
-#define LETTER_Z	L'Z'
-#define LETTER_y	L'y'
-#define LETTER_n	L'n'
-
-#define ZLENULSTR	L""
+/* Convert character or string to wide character or string */
+#define ZWC(c)	L ## c
+
 #define ZLEEOF	WEOF
 #define ZS_memcpy wmemcpy
 #define ZS_memmove wmemmove
@@ -73,21 +61,9 @@ typedef unsigned char *ZLE_STRING_T;
 typedef int ZLE_INT_T;
 #define ZLE_CHAR_SIZE	sizeof(unsigned char)
 
-#define ZLENL	'\n'
-#define ZLENUL	'\0'
-#define ZLETAB	'\t'
-#define ZLESPC	' '
-
-#define DIGIT_1		'1'
-#define DIGIT_9		'9'
-#define LETTER_a	'a'
-#define LETTER_z	'z'
-#define LETTER_A	'A'
-#define LETTER_Z	'Z'
-#define LETTER_y	'y'
-#define LETTER_n	'n'
-
-#define ZLENULSTR	""
+/* Leave character or string as is */
+#define ZWC(c)	c
+
 #define ZLEEOF	EOF
 #define ZS_memcpy memcpy
 #define ZS_memmove memmove
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index afad7ae44..18800fd26 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -614,11 +614,11 @@ pushline(UNUSED(char **args))
 
     if (n < 0)
 	return 1;
-    zpushnode(bufstack, metafy((char *) zleline, zlell, META_DUP));
+    zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0));
     while (--n)
 	zpushnode(bufstack, ztrdup(""));
     stackcs = zlecs;
-    *zleline = '\0';
+    *zleline = ZWC('\0');
     zlell = zlecs = 0;
     clearlist = 1;
     return 0;
@@ -629,19 +629,23 @@ int
 pushlineoredit(char **args)
 {
     int ics, ret;
-    unsigned char *s;
+    ZLE_STRING_T s;
     char *hline = hgetline();
 
     if (zmult < 0)
 	return 1;
     if (hline && *hline) {
-	ics = ztrlen(hline);
+	ZLE_STRING_T zhline = stringaszleline((unsigned char *)hline,
+					      &ics, NULL);
+
 	sizeline(ics + zlell + 1);
-	for (s = zleline + zlell; --s >= zleline; *(s + ics) = *s);
-	for (s = zleline; *hline; hline++)
-	    *s++ = *hline == Meta ? *++hline ^ 32 : *hline;
+	/* careful of overlapping copy */
+	for (s = zleline + zlell; --s >= zleline; s[ics] = *s)
+	    ;
+	ZS_memcpy(zleline, zhline, ics);
 	zlell += ics;
 	zlecs += ics;
+	free(zhline);
     }
     ret = pushline(args);
     if (!isfirstln)
@@ -669,18 +673,19 @@ pushinput(char **args)
 int
 zgetline(UNUSED(char **args))
 {
-    char *s = (char *)getlinknode(bufstack);
+    unsigned char *s = (unsigned char *)getlinknode(bufstack);
 
     if (!s) {
 	return 1;
     } else {
 	int cc;
+	ZLE_STRING_T lineadd = stringaszleline(s, &cc, NULL);
 
-	unmetafy(s, &cc);
 	spaceinline(cc);
-	memcpy((char *)zleline + zlecs, s, cc);
+	ZS_memcpy(zleline + zlecs, lineadd, cc);
 	zlecs += cc;
 	free(s);
+	free(lineadd);
 	clearlist = 1;
     }
     return 0;
@@ -940,7 +945,11 @@ doisearch(char **args, int dir)
 	    skip_pos = 1;
 	rpt:
 	    if (!sbptr && previous_search_len) {
-		if (previous_search_len > sibuf - FIRST_SEARCH_CHAR - 2) {
+		if (previous_search_len > sibuf - FIRST_SEARCH_CHAR - 2
+#ifdef ZLE_UNICODE_SUPPORT
+		    - MB_CUR_MAX
+#endif
+		    ) {
 		    ibuf = hrealloc(ibuf, sibuf, sibuf + previous_search_len);
 		    sbuf = ibuf + FIRST_SEARCH_CHAR;
 		    sibuf += previous_search_len;
@@ -983,14 +992,28 @@ doisearch(char **args, int dir)
 		continue;
 	    }
 	    set_isrch_spot(top_spot++, hl, pos, zlecs, sbptr, dir, nomatch);
-	    if (sbptr == sibuf - FIRST_SEARCH_CHAR - 2) {
+	    if (sbptr >= sibuf - FIRST_SEARCH_CHAR - 2
+#ifdef ZLE_UNICODE_SUPPORT
+		- MB_CUR_MAX
+#endif
+		) {
 		ibuf = hrealloc(ibuf, sibuf, sibuf * 2);
 		sbuf = ibuf + FIRST_SEARCH_CHAR;
 		sibuf *= 2;
 	    }
-	    /* TODO: use lastchar_wide if available, convert back to
-	     * multibyte string.  Yuk.  */
+#ifdef ZLE_UNICODE_SUPPORT
+	    /*
+	     * We've supposedly arranged above that lastchar_wide is
+	     * always valid at this point.
+	     */
+	    {
+		int len = wctomb(sbuf + sbptr, lastchar_wide);
+		if (len > 0)
+		    sbptr += len;
+	    }
+#else
 	    sbuf[sbptr++] = lastchar;
+#endif
 	}
 	if (feep)
 	    handlefeep(zlenoargs);
@@ -1160,8 +1183,15 @@ getvisrchstr(void)
 		strcpy(newbuf, sbuf);
 		statusline = sbuf = newbuf;
 	    }
-	    /* TODO: may be wide char, convert back to multibyte string */
+#ifdef ZLE_UNICODE_SUPPORT
+	    {
+		int len = wctomb(sbuf + sptr, lastchar_wide);
+		if (len > 0)
+		    sptr += len;
+	    }
+#else
 	    sbuf[sptr++] = lastchar;
+#endif
 	} else {
 	    feep = 1;
 	}
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index e9d955ef6..091012d17 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -717,8 +717,6 @@ getbyte(int keytmout)
 
 /*
  * Get a full character rather than just a single byte.
- * (TODO: Strictly we ought to call this getbyte and the above
- * function getbyte.)
  */
 
 /**/
@@ -778,6 +776,8 @@ getrestchar(int inchar)
 
 	/* No timeout here as we really need the character. */
 	inchar = getbyte(0);
+	/* getbyte deliberately resets lastchar_wide_valid */
+	lastchar_wide_valid = 1;
 	if (inchar == EOF)
 	    return lastchar_wide = WEOF;
 	c = inchar;
@@ -833,7 +833,7 @@ zlecore(void)
 	    handleprefixes();
 	    /* for vi mode, make sure the cursor isn't somewhere illegal */
 	    if (invicmdmode() && zlecs > findbol() &&
-		(zlecs == zlell || zleline[zlecs] == ZLENL))
+		(zlecs == zlell || zleline[zlecs] == ZWC('\n')))
 		zlecs--;
 	    if (undoing)
 		handleundo();
@@ -934,7 +934,7 @@ zleread(char **lp, char **rp, int flags, int context)
     histline = curhist;
     undoing = 1;
     zleline = (unsigned char *)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE);
-    *zleline = ZLENUL;
+    *zleline = ZWC('\0');
     virangeflag = lastcmd = done = zlecs = zlell = mark = 0;
     vichgflag = 0;
     viinsbegin = 0;
@@ -993,7 +993,7 @@ zleread(char **lp, char **rp, int flags, int context)
     if (eofsent) {
 	s = NULL;
     } else {
-	zleline[zlell++] = ZLENL;
+	zleline[zlell++] = ZWC('\n');
 	s = zlegetline(NULL, NULL);
     }
     free(zleline);
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 2c7c364a2..a017c6709 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -294,7 +294,7 @@ acceptline(UNUSED(char **args))
 int
 acceptandhold(UNUSED(char **args))
 {
-    zpushnode(bufstack, metafy((char *)zleline, zlell, META_DUP));
+    zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0));
     stackcs = zlecs;
     done = 1;
     return 0;
@@ -314,10 +314,10 @@ killline(char **args)
 	return ret;
     }
     while (n--) {
-	if (zleline[zlecs] == '\n')
+	if (zleline[zlecs] == ZWC('\n'))
 	    zlecs++, i++;
 	else
-	    while (zlecs != zlell && zleline[zlecs] != '\n')
+	    while (zlecs != zlell && zleline[zlecs] != ZWC('\n'))
 		zlecs++, i++;
     }
     backkill(i, 0);
@@ -378,8 +378,7 @@ yank(UNUSED(char **args))
     while (n--) {
 	kct = -1;
 	spaceinline(kctbuf->len);
-	memcpy((char *)(zleline + zlecs), (char *)kctbuf->buf,
-	       kctbuf->len * ZLE_CHAR_SIZE);
+	ZS_memcpy(zleline + zlecs, kctbuf->buf, kctbuf->len);
 	zlecs += kctbuf->len;
 	yanke = zlecs;
     }
@@ -433,13 +432,13 @@ yankpop(UNUSED(char **args))
 	 *    was full, we could loop round and round it, otherwise
 	 *    we just stopped when we hit the first empty buffer.
 	 */
-    } while (!buf->buf || *buf->buf == ZLENUL);
+    } while (!buf->buf || *buf->buf == ZWC('\0'));
 
     zlecs = yankb;
     foredel(yanke - yankb);
     cc = buf->len;
     spaceinline(cc);
-    memcpy((char *)(zleline + zlecs), (char *)buf->buf, cc * ZLE_CHAR_SIZE);
+    ZS_memcpy(zleline + zlecs, buf->buf, cc);
     zlecs += cc;
     yanke = zlecs;
     return 0;
@@ -458,32 +457,35 @@ int
 whatcursorposition(UNUSED(char **args))
 {
     char msg[100];
-    char *s = msg;
-    int bol = findbol();
-    int c = STOUC(zleline[zlecs]);
+    char *s = msg, *mbstr;
+    int bol = findbol(), len;
+    ZLE_CHAR_T c = zleline[zlecs];
 
     if (zlecs == zlell)
 	strucpy(&s, "EOF");
     else {
 	strucpy(&s, "Char: ");
 	switch (c) {
-	case ' ':
+	case ZWC(' '):
 	    strucpy(&s, "SPC");
 	    break;
-	case '\t':
+	case ZWC('\t'):
 	    strucpy(&s, "TAB");
 	    break;
-	case '\n':
+	case ZWC('\n'):
 	    strucpy(&s, "LFD");
 	    break;
 	default:
-	    if (imeta(c)) {
-		*s++ = Meta;
-		*s++ = c ^ 32;
-	    } else
-		*s++ = c;
+	    /*
+	     * convert a single character, remembering it may
+	     * turn into a multibyte string or be metafied.
+	     */
+	    mbstr = zlelineasstring(zleline+zlecs, 1, 0, &len, NULL, 1);
+	    strcpy(s, mbstr);
+	    s += len;
 	}
-	sprintf(s, " (0%o, %d, 0x%x)", c, c, c);
+	sprintf(s, " (0%o, %u, 0x%x)", (unsigned int)c,
+		(unsigned int)c, (unsigned int)c);
 	s += strlen(s);
     }
     sprintf(s, "  point %d of %d(%d%%)  column %d", zlecs+1, zlell+1,
@@ -629,7 +631,7 @@ copyprevword(UNUSED(char **args))
 	t0++;
     len = zlecs - t0;
     spaceinline(len);
-    memcpy((char *)&zleline[zlecs], (char *)&zleline[t0], len);
+    ZS_memcpy(zleline + zlecs, zleline + t0, len);
     zlecs += len;
     return 0;
 }
@@ -641,21 +643,24 @@ copyprevshellword(UNUSED(char **args))
     LinkList l;
     LinkNode n;
     int i;
-    char *p = NULL;
+    unsigned char *p = NULL;
 
     if ((l = bufferwords(NULL, NULL, &i)))
         for (n = firstnode(l); n; incnode(n))
             if (!i--) {
-                p = getdata(n);
+                p = (unsigned char *)getdata(n);
                 break;
             }
 
     if (p) {
-	int len = strlen(p);
+	int len;
+	ZLE_STRING_T lineadd = stringaszleline(p, &len, NULL);
 
 	spaceinline(len);
-	memcpy(zleline + zlecs, p, len);
+	ZS_memcpy(zleline + zlecs, lineadd, len);
 	zlecs += len;
+
+	free(lineadd);
     }
     return 0;
 }
@@ -672,7 +677,7 @@ sendbreak(UNUSED(char **args))
 int
 quoteregion(UNUSED(char **args))
 {
-    char *str;
+    ZLE_STRING_T str;
     size_t len;
 
     if (mark > zlell)
@@ -682,12 +687,12 @@ quoteregion(UNUSED(char **args))
 	mark = zlecs;
 	zlecs = tmp;
     }
-    str = (char *)hcalloc(len = mark - zlecs);
-    memcpy(str, (char *)&zleline[zlecs], len);
+    str = (ZLE_STRING_T)hcalloc((len = mark - zlecs) * ZLE_CHAR_SIZE);
+    ZS_memcpy(str, zleline + zlecs, len);
     foredel(len);
     str = makequote(str, &len);
     spaceinline(len);
-    memcpy((char *)&zleline[zlecs], str, len);
+    ZS_memcpy(zleline + zlecs, str, len);
     mark = zlecs;
     zlecs += len;
     return 0;
@@ -697,39 +702,39 @@ quoteregion(UNUSED(char **args))
 int
 quoteline(UNUSED(char **args))
 {
-    char *str;
+    ZLE_STRING_T str;
     size_t len = zlell;
 
-    str = makequote((char *)zleline, &len);
+    str = makequote(zleline, &len);
     sizeline(len);
-    memcpy(zleline, str, len);
+    ZS_memcpy(zleline, str, len);
     zlecs = zlell = len;
     return 0;
 }
 
 /**/
-static char *
-makequote(char *str, size_t *len)
+static ZLE_STRING_T
+makequote(ZLE_STRING_T str, size_t *len)
 {
     int qtct = 0;
-    char *l, *ol;
-    char *end = str + *len;
+    ZLE_STRING_T l, ol;
+    ZLE_STRING_T end = str + *len;
 
     for (l = str; l < end; l++)
-	if (*l == '\'')
+	if (*l == ZWC('\''))
 	    qtct++;
     *len += 2 + qtct*3;
-    l = ol = (char *)zhalloc(*len);
-    *l++ = '\'';
+    l = ol = (char *)zhalloc(*len * ZLE_CHAR_SIZE);
+    *l++ = ZWC('\'');
     for (; str < end; str++)
-	if (*str == '\'') {
-	    *l++ = '\'';
-	    *l++ = '\\';
-	    *l++ = '\'';
-	    *l++ = '\'';
+	if (*str == ZWC('\'')) {
+	    *l++ = ZWC('\'');
+	    *l++ = ZWC('\\');
+	    *l++ = ZWC('\'');
+	    *l++ = ZWC('\'');
 	} else
 	    *l++ = *str;
-    *l++ = '\'';
+    *l++ = ZWC('\'');
     return ol;
 }
 
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index b939df06b..a60b4dfd0 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -469,9 +469,9 @@ visetmark(UNUSED(char **args))
     ZLE_INT_T ch;
 
     ch = getfullchar(0);
-    if (ch < LETTER_a || ch > LETTER_z)
+    if (ch < ZWC('a') || ch > ZWC('z'))
 	return 1;
-    ch -= LETTER_a;
+    ch -= ZWC('a');
     vimarkcs[ch] = zlecs;
     vimarkline[ch] = histline;
     return 0;
@@ -487,9 +487,9 @@ vigotomark(UNUSED(char **args))
     if (ch == LASTFULLCHAR)
 	ch = 26;
     else {
-	if (ch < LETTER_a || ch > LETTER_z)
+	if (ch < ZWC('a') || ch > ZWC('z'))
 	    return 1;
-	ch -= LETTER_a;
+	ch -= ZWC('a');
     }
     if (!vimarkline[ch])
 	return 1;
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index f347e61cf..f9ac4f284 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -237,10 +237,10 @@ set_lbuffer(UNUSED(Param pm), char *x)
     ZLE_STRING_T y;
     int len;
 
-    if (x && *x != ZLENUL)
+    if (x && *x != ZWC('\0'))
 	y = stringaszleline((unsigned char *)x, &len, NULL);
     else
-	y = ZLENULSTR, len = 0;
+	y = ZWC(""), len = 0;
     sizeline(zlell - zlecs + len);
     ZS_memmove(zleline + len, zleline + zlecs, zlell - zlecs);
     ZS_memcpy(zleline, y, len);
@@ -267,10 +267,10 @@ set_rbuffer(UNUSED(Param pm), char *x)
     char *y;
     int len;
 
-    if (x && *x != ZLENUL)
+    if (x && *x != ZWC('\0'))
 	y = stringaszleline((unsigned char *)x, &len, NULL);
     else
-	y = ZLENULSTR, len = 0;
+	y = ZWC(""), len = 0;
     sizeline(zlell = zlecs + len);
     ZS_memcpy(zleline + zlecs, y, len);
     zsfree(x);
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 6c63774da..66efef77f 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -459,10 +459,10 @@ zrefresh(void)
 	if (t == scs)			/* if cursor is here, remember it */
 	    nvcs = s - (unsigned char *)(nbuf[nvln = ln]);
 
-	if (*t == ZLENL){		/* newline */
+	if (*t == ZWC('\n')){		/* newline */
 	    nbuf[ln][winw + 1] = '\0';	/* text not wrapped */
 	    nextline
-	} else if (*t == ZLETAB) {		/* tab */
+	} else if (*t == ZWC('\t')) {		/* tab */
 	    t0 = (char *)s - nbuf[ln];
 	    if ((t0 | 7) + 1 >= winw) {
 		nbuf[ln][winw + 1] = '\n';	/* text wrapped */
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 620f615a2..7d4fbd641 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -163,8 +163,8 @@ usetab(void)
 
     if (keybuf[0] != '\t' || keybuf[1])
 	return 0;
-    for (; s >= zleline && *s != ZLENL; s--)
-	if (*s != ZLETAB && *s != ZLESPC)
+    for (; s >= zleline && *s != ZWC('\n'); s--)
+	if (*s != ZWC('\t') && *s != ZWC(' '))
 	    return 0;
     if (compfunc) {
 	wouldinstab = 1;
@@ -582,6 +582,15 @@ docomplete(int lst)
 	active = 0;
 	return 0;
     }
+
+    /*
+     * TODO: metafy_line() currently tries to metafy in place.
+     * For ZLE_UNICODE_SUPPORT we need to metafy into a separate
+     * string, replacing all use of zleline, zlecs and zlell here
+     * with those values, then restoring at the end.
+     *
+     * The alternative is probably too horrendous to contemplate.
+     */
     metafy_line();
 
     ocs = zlecs;
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 8d38c4752..a6daac289 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -94,11 +94,17 @@ zleaddtoline(ZLE_CHAR_T chr)
 /*
  * Input a line in internal zle format, possibly using wide characters,
  * possibly not, together with its length and the cursor position.
- * Output an ordinary string, using multibyte characters instead of wide
- * characters where appropriate and with the contents metafied.
+ * The length must be accurate and includes all characters (no NULL
+ * termination is expected).  The input cursor position is only
+ * significant if outcs is non-NULL.
+ *
+ * Output an ordinary NULL-terminated string, using multibyte characters
+ * instead of wide characters where appropriate and with the contents
+ * metafied.
  *
  * If outll is non-NULL, assign the new length.  If outcs is non-NULL,
- * assign the new character position.
+ * assign the new character position.  This is the conventional string
+ * length, without the NULL byte.
  *
  * If useheap is 1, memory is returned from the heap, else is allocated
  * for later freeing.
@@ -200,12 +206,10 @@ stringaszleline(unsigned char *instr, int *outll, int *outsz)
 
 #ifdef ZLE_UNICODE_SUPPORT
     if (ll) {
-	/* reset shift state by converting null. */
-	/* char cnull = '\0'; */
 	char *inptr = (char *)instr;
 	wchar_t *outptr = outstr;
 
-	/* mbrtowc(outstr, &cnull, 1, &ps); */
+	/* Reset shift state to input complete string */
 	memset(&ps, '\0', sizeof(ps));
 
 	while (ll) {
@@ -268,7 +272,7 @@ spaceinline(int ct)
     for (i = zlell; --i >= zlecs;)
 	zleline[i + ct] = zleline[i];
     zlell += ct;
-    zleline[zlell] = ZLENUL;
+    zleline[zlell] = ZWC('\0');
 
     if (mark > zlecs)
 	mark += ct;
@@ -287,7 +291,7 @@ shiftchars(int to, int cnt)
 	zleline[to] = zleline[to + cnt];
 	to++;
     }
-    zleline[zlell = to] = ZLENUL;
+    zleline[zlell = to] = ZWC('\0');
 }
 
 /**/
@@ -323,7 +327,7 @@ cut(int i, int ct, int dir)
 	if (!(zmod.flags & MOD_VIAPP) || !b->buf) {
 	    free(b->buf);
 	    b->buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
-	    memcpy((char *)b->buf, (char *)(zleline + i), ct * ZLE_CHAR_SIZE);
+	    ZS_memcpy(b->buf, zleline + i, ct);
 	    b->len = ct;
 	    b->flags = vilinerange ? CUTBUFFER_LINE : 0;
 	} else {
@@ -336,9 +340,8 @@ cut(int i, int ct, int dir)
 			(ct + len + !!(b->flags & CUTBUFFER_LINE))
 			* ZLE_CHAR_SIZE);
 	    if (b->flags & CUTBUFFER_LINE)
-		b->buf[len++] = ZLENL;
-	    memcpy((char *)(b->buf + len), (char *)(zleline + i),
-		   ct * ZLE_CHAR_SIZE);
+		b->buf[len++] = ZWC('\n');
+	    ZS_memcpy(b->buf + len, zleline + i, ct);
 	    b->len = len + ct;
 	}
 	return;
@@ -349,14 +352,13 @@ cut(int i, int ct, int dir)
 	for(n=34; n>26; n--)
 	    vibuf[n] = vibuf[n-1];
 	vibuf[26].buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
-	memcpy((char *)vibuf[26].buf, (char *)(zleline + i),
-	       ct * ZLE_CHAR_SIZE);
+	ZS_memcpy(vibuf[26].buf, zleline + i, ct);
 	vibuf[26].len = ct;
 	vibuf[26].flags = vilinerange ? CUTBUFFER_LINE : 0;
     }
     if (!cutbuf.buf) {
 	cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE);
-	cutbuf.buf[0] = ZLENUL;
+	cutbuf.buf[0] = ZWC('\0');
 	cutbuf.len = cutbuf.flags = 0;
     } else if (!(lastcmd & ZLE_KILL)) {
 	Cutbuffer kptr;
@@ -370,23 +372,21 @@ cut(int i, int ct, int dir)
 	    free(kptr->buf);
 	*kptr = cutbuf;
 	cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE);
-	cutbuf.buf[0] = ZLENUL;
+	cutbuf.buf[0] = ZWC('\0');
 	cutbuf.len = cutbuf.flags = 0;
     }
     if (dir) {
 	ZLE_STRING_T s = (ZLE_STRING_T)zalloc((cutbuf.len + ct)*ZLE_CHAR_SIZE);
 
-	memcpy(s, (char *) (zleline + i), ct * ZLE_CHAR_SIZE);
-	memcpy((char *)(s + ct), (char *)cutbuf.buf,
-	       cutbuf.len * ZLE_CHAR_SIZE);
+	ZS_memcpy(s, zleline + i, ct);
+	ZS_memcpy(s + ct, cutbuf.buf, cutbuf.len);
 	free(cutbuf.buf);
 	cutbuf.buf = s;
 	cutbuf.len += ct;
     } else {
 	cutbuf.buf = realloc((char *)cutbuf.buf,
 			     (cutbuf.len + ct) * ZLE_CHAR_SIZE);
-	memcpy((char *)(cutbuf.buf + cutbuf.len), (char *) (zleline + i),
-	       ct * ZLE_CHAR_SIZE);
+	ZS_memcpy(cutbuf.buf + cutbuf.len, zleline + i, ct);
 	cutbuf.len += ct;
     }
     if(vilinerange)
@@ -442,7 +442,7 @@ findbol(void)
 {
     int x = zlecs;
 
-    while (x > 0 && zleline[x - 1] != ZLENL)
+    while (x > 0 && zleline[x - 1] != ZWC('\n'))
 	x--;
     return x;
 }
@@ -453,7 +453,7 @@ findeol(void)
 {
     int x = zlecs;
 
-    while (x != zlell && zleline[x] != ZLENL)
+    while (x != zlell && zleline[x] != ZWC('\n'))
 	x++;
     return x;
 }
@@ -528,15 +528,15 @@ getzlequery(int yesno)
     /* get a character from the tty and interpret it */
     c = getfullchar(0);
     if (yesno) {
-	if (c == ZLETAB)
-	    c = LETTER_y;
-	else if (icntrl(c) || c == EOF)
-	    c = LETTER_n;
+	if (c == ZWC('\t'))
+	    c = ZWC('y');
+	else if (icntrl(c) || c == ZLEEOF) /* TODO iswcntrl */
+	    c = ZWC('n');
 	else
-	    c = tulower(c);
+	    c = tulower(c);	/* TODO tulower doesn't handle wint_t */
     }
     /* echo response and return */
-    if (c != ZLENL)
+    if (c != ZWC('\n'))
 	putc(c, shout);		/* TODO: convert to multibyte */
     return c;
 }
@@ -667,7 +667,7 @@ initundo(void)
     curchange->del = curchange->ins = NULL;
     curchange->dell = curchange->insl = 0;
     lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE);
-    memcpy(lastline, zleline, (lastll = zlell) * ZLE_CHAR_SIZE);
+    ZS_memcpy(lastline, zleline, (lastll = zlell));
     lastcs = zlecs;
 }
 
@@ -751,8 +751,7 @@ mkundoent(void)
     } else {
 	ch->dell = lastll - pre - suf;
 	ch->del = (ZLE_STRING_T)zalloc(ch->dell * ZLE_CHAR_SIZE);
-	memcpy((char *)ch->del, (char *)(lastline + pre),
-	       ch->dell * ZLE_CHAR_SIZE);
+	ZS_memcpy(ch->del, lastline + pre, ch->dell);
     }
     if(suf + pre == zlell) {
 	ch->ins = NULL;
@@ -760,8 +759,7 @@ mkundoent(void)
     } else {
 	ch->insl = zlell - pre - suf;
 	ch->ins = (ZLE_STRING_T)zalloc(ch->insl * ZLE_CHAR_SIZE);
-	memcpy((char *)ch->ins, (char *)(zleline + pre),
-	       ch->insl * ZLE_CHAR_SIZE);
+	ZS_memcpy(ch->ins, zleline + pre, ch->insl);
     }
     if(nextchanges) {
 	ch->flags = CH_PREV;
@@ -784,7 +782,7 @@ setlastline(void)
 {
     if(lastlinesz != linesz)
 	lastline = realloc(lastline, (lastlinesz = linesz) * ZLE_CHAR_SIZE);
-    memcpy(lastline, zleline, (lastll = zlell) * ZLE_CHAR_SIZE);
+    ZS_memcpy(lastline, zleline, (lastll = zlell));
     lastcs = zlecs;
 }
 
@@ -821,8 +819,7 @@ unapplychange(struct change *ch)
 	foredel(ch->insl);
     if(ch->del) {
 	spaceinline(ch->dell);
-	memcpy((char *)(zleline + zlecs), (char *)ch->del,
-	       ch->dell * ZLE_CHAR_SIZE);
+	ZS_memcpy(zleline + zlecs, ch->del, ch->dell);
 	zlecs += ch->dell;
     }
     zlecs = ch->old_cs;
@@ -862,8 +859,7 @@ applychange(struct change *ch)
 	foredel(ch->dell);
     if(ch->ins) {
 	spaceinline(ch->insl);
-	memcpy((char *)(zleline + zlecs), (char *)ch->ins,
-	       ch->insl * ZLE_CHAR_SIZE);
+	ZS_memcpy(zleline + zlecs, ch->ins, ch->insl);
 	zlecs += ch->insl;
     }
     zlecs = ch->new_cs;
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index b45ccf10a..e4a36b219 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -200,7 +200,7 @@ getvirange(int wf)
      * the line, or selected a different history line.             */
     if (histline != hist1 || zlell != lastll || memcmp(zleline, lastline, zlell)) {
 	histline = hist1;
-	memcpy(zleline, lastline, zlell = lastll);
+	ZS_memcpy(zleline, lastline, zlell = lastll);
 	zlecs = pos;
 	return -1;
     }
@@ -733,13 +733,13 @@ viputbefore(UNUSED(char **args))
     if(buf->flags & CUTBUFFER_LINE) {
 	zlecs = findbol();
 	spaceinline(buf->len + 1);
-	memcpy((char *)zleline + zlecs, buf->buf, buf->len);
-	zleline[zlecs + buf->len] = '\n';
+	ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
+	zleline[zlecs + buf->len] = ZWC('\n');
 	vifirstnonblank(zlenoargs);
     } else {
 	while (n--) {
 	    spaceinline(buf->len);
-	    memcpy((char *)zleline + zlecs, buf->buf, buf->len);
+	    ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
 	    zlecs += buf->len;
 	}
 	if (zlecs)
@@ -765,15 +765,15 @@ viputafter(UNUSED(char **args))
     if(buf->flags & CUTBUFFER_LINE) {
 	zlecs = findeol();
 	spaceinline(buf->len + 1);
-	zleline[zlecs++] = '\n';
-	memcpy((char *)zleline + zlecs, buf->buf, buf->len);
+	zleline[zlecs++] = ZWC('\n');
+	ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
 	vifirstnonblank(zlenoargs);
     } else {
 	if (zlecs != findeol())
 	    zlecs++;
 	while (n--) {
 	    spaceinline(buf->len);
-	    memcpy((char *)zleline + zlecs, buf->buf, buf->len);
+	    ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
 	    zlecs += buf->len;
 	}
 	if (zlecs)
@@ -798,7 +798,7 @@ vijoin(UNUSED(char **args))
 	zlecs--;
     else {
 	spaceinline(1);
-	zleline[zlecs] = ' ';
+	zleline[zlecs] = ZWC(' ');
     }
     return 0;
 }
@@ -854,15 +854,16 @@ visetbuffer(UNUSED(char **args))
     ZLE_INT_T ch;
 
     if ((zmod.flags & MOD_VIBUF) ||
-	(((ch = getfullchar(0)) < DIGIT_1 || ch > DIGIT_9) &&
-	 (ch < LETTER_a || ch > LETTER_z) &&
-	 (ch < LETTER_A || ch > LETTER_Z)))
+	(((ch = getfullchar(0)) < ZWC('1') || ch > ZWC('9')) &&
+	 (ch < ZWC('a') || ch > ZWC('z')) &&
+	 (ch < ZWC('A') || ch > ZWC('Z'))))
 	return 1;
-    if (ch >= LETTER_A && ch <= LETTER_Z)	/* needed in cut() */
+    if (ch >= ZWC('A') && ch <= ZWC('Z'))	/* needed in cut() */
 	zmod.flags |= MOD_VIAPP;
     else
 	zmod.flags &= ~MOD_VIAPP;
-    zmod.vibuf = tulower(ch) + (idigit(ch) ? - DIGIT_1 + 26 : -LETTER_a);
+    /* TODO tulower, idigit doen't handle wint_t */
+    zmod.vibuf = tulower(ch) + (idigit(ch) ? - ZWC('1') + 26 : -ZWC('a'));
     zmod.flags |= MOD_VIBUF;
     prefixflag = 1;
     return 0;