summaryrefslogtreecommitdiff
path: root/Src/Zle/zle_tricky.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/zle_tricky.c')
-rw-r--r--Src/Zle/zle_tricky.c419
1 files changed, 245 insertions, 174 deletions
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index f59823f0b..ba149cfe8 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -33,19 +33,40 @@
/*
* The main part of ZLE maintains the line being edited as binary data,
* but here, where we interface with the lexer and other bits of zsh, we
- * need the line metafied. The technique used is quite simple: on entry
- * to the expansion/completion system, we metafy the line in place,
- * adjusting zlell and zlecs to match. All completion and expansion is
- * done on the metafied line. Immediately before returning, the line is
- * unmetafied again, changing zlell and zlecs back. (zlell and zlecs
- * might have changed during completion, so they can't be merely saved
- * and restored.) The various indexes into the line that are used in
- * this file only are not translated: they remain indexes into the
- * metafied line.
+ * need the line metafied and, if necessary, converted from wide
+ * characters into multibyte strings. On entry to the
+ * expansion/completion system, we metafy the line from zleline into
+ * zlemetaline, with zlell and zlecs adjusted into zlemetall zlemetacs
+ * to match. zlemetall and zlemetacs refer to raw character positions,
+ * in other words a metafied character contributes 2 to each. All
+ * completion and expansion is done on the metafied line. Immediately
+ * before returning, the line is unmetafied again, so that zleline,
+ * zlell and zlecs are once again valid. (zlell and zlecs might have
+ * changed during completion, so they can't be merely saved and
+ * restored.) The various indexes into the line that are used in this
+ * file only are not translated: they remain indexes into the metafied
+ * line.
+ *
+ * zlemetaline is always NULL when not in use and non-NULL when in use.
+ * This can be used to test if the line is metafied. It would be
+ * possible to use zlecs and zlell directly, updated as appropriate when
+ * metafying and unmetafying, instead of zlemetacs and zlemetall,
+ * however the current system seems clearer.
*/
#define inststr(X) inststrlen((X),1,-1)
+/*
+ * The state of the line being edited between metafy_line()
+ * unmetafy_line().
+ *
+ * zlemetacs and zlemetall are defined in lex.c.
+ */
+/**/
+mod_export unsigned char *zlemetaline;
+/**/
+mod_export int metalinesz;
+
/* The line before completion was tried. */
/**/
@@ -153,7 +174,10 @@ mod_export int comprecursive;
/**/
int hascompwidgets;
-/* Find out if we have to insert a tab (instead of trying to complete). */
+/*
+ * Find out if we have to insert a tab (instead of trying to complete).
+ * The line is not metafied here.
+ */
/**/
static int
@@ -250,6 +274,7 @@ deletecharorlist(char **args)
useglob = isset(GLOBCOMPLETE);
wouldinstab = 0;
+ /* Line not yet metafied */
if (zlecs != zlell) {
fixsuffix();
invalidatelist();
@@ -583,32 +608,24 @@ docomplete(int lst)
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;
- origline = dupstring((char *) zleline);
- origcs = zlecs;
- origll = zlell;
+ ocs = zlemetacs;
+ origline = dupstring((char *) zlemetaline);
+ origcs = zlemetacs;
+ origll = zlemetall;
if (!isfirstln && chline != NULL) {
/* If we are completing in a multi-line buffer (which was not *
* taken from the history), we have to prepend the stuff saved *
* in chline to the contents of line. */
- ol = dupstring((char *)zleline);
+ ol = dupstring((char *)zlemetaline);
/* Make sure that chline is zero-terminated. */
*hptr = '\0';
- zlecs = 0;
+ zlemetacs = 0;
inststr(chline);
- chl = zlecs;
- zlecs += ocs;
+ chl = zlemetacs;
+ zlemetacs += ocs;
} else
ol = NULL;
inwhat = IN_NOTHING;
@@ -622,35 +639,35 @@ docomplete(int lst)
* NOTE: get_comp_string() calls pushheap(), but not popheap(). */
noerrs = 1;
s = get_comp_string();
- DPUTS(wb < 0 || zlecs < wb || zlecs > we,
- "BUG: 0 <= wb <= zlecs <= we is not true!");
+ DPUTS(wb < 0 || zlemetacs < wb || zlemetacs > we,
+ "BUG: 0 <= wb <= zlemetacs <= we is not true!");
noerrs = ne;
/* For vi mode, reset the start-of-insertion pointer to the beginning *
* of the word being completed, if it is currently later. Vi itself *
* would never change the pointer in the middle of an insertion, but *
* then vi doesn't have completion. More to the point, this is only *
* an emulation. */
- if (viinsbegin > ztrsub((char *) zleline + wb, (char *) zleline))
- viinsbegin = ztrsub((char *) zleline + wb, (char *) zleline);
+ if (viinsbegin > ztrsub((char *) zlemetaline + wb, (char *) zlemetaline))
+ viinsbegin = ztrsub((char *) zlemetaline + wb, (char *) zlemetaline);
/* If we added chline to the line buffer, reset the original contents. */
if (ol) {
- zlecs -= chl;
+ zlemetacs -= chl;
wb -= chl;
we -= chl;
if (wb < 0) {
- strcpy((char *) zleline, ol);
- zlell = strlen((char *) zleline);
- zlecs = ocs;
+ strcpy((char *) zlemetaline, ol);
+ zlemetall = strlen((char *) zlemetaline);
+ zlemetacs = ocs;
popheap();
unmetafy_line();
zsfree(s);
active = 0;
return 1;
}
- ocs = zlecs;
- zlecs = 0;
+ ocs = zlemetacs;
+ zlemetacs = 0;
foredel(chl);
- zlecs = ocs;
+ zlemetacs = ocs;
}
freeheap();
/* Save the lexer state, in case the completion code uses the lexer *
@@ -694,7 +711,7 @@ docomplete(int lst)
if (*q == String && q[1] != Inpar && q[1] != Inbrack) {
if (*++q == Inbrace) {
if (! skipparens(Inbrace, Outbrace, &q) &&
- q == s + zlecs - wb)
+ q == s + zlemetacs - wb)
lst = COMP_EXPAND;
} else {
char *t, sav, sav2;
@@ -725,7 +742,7 @@ docomplete(int lst)
q++;
sav = *q;
*q = '\0';
- if (zlecs - wb == q - s &&
+ if (zlemetacs - wb == q - s &&
(idigit(sav2) || checkparams(t)))
lst = COMP_EXPAND;
*q = sav;
@@ -735,7 +752,7 @@ docomplete(int lst)
lst = COMP_COMPLETE;
} else
break;
- } while (q < s + zlecs - wb);
+ } while (q < s + zlemetacs - wb);
if (lst == COMP_EXPAND_COMPLETE) {
/* If it is still not clear if we should use expansion or *
* completion and there is a `$' or a backtick in the word, *
@@ -760,7 +777,7 @@ docomplete(int lst)
for (q = w; *q; q++)
if (INULL(*q))
*q = Nularg;
- zlecs = wb;
+ zlemetacs = wb;
foredel(we - wb);
untokenize(x = ox = dupstring(w));
@@ -775,8 +792,8 @@ docomplete(int lst)
/* Do expansion. */
char *ol = (olst == COMP_EXPAND ||
olst == COMP_EXPAND_COMPLETE) ?
- dupstring((char *)zleline) : (char *)zleline;
- int ocs = zlecs, ne = noerrs;
+ dupstring((char *)zlemetaline) : (char *)zlemetaline;
+ int ocs = zlemetacs, ne = noerrs;
noerrs = 1;
ret = doexpansion(origword, lst, olst, lincmd);
@@ -786,8 +803,8 @@ docomplete(int lst)
/* If expandorcomplete was invoked and the expansion didn't *
* change the command line, do completion. */
if (olst == COMP_EXPAND_COMPLETE &&
- !strcmp(ol, (char *)zleline)) {
- zlecs = ocs;
+ !strcmp(ol, (char *)zlemetaline)) {
+ zlemetacs = ocs;
errflag = 0;
if (!compfunc) {
@@ -808,15 +825,15 @@ docomplete(int lst)
} else {
if (ret)
clearlist = 1;
- if (!strcmp(ol, (char *)zleline)) {
+ if (!strcmp(ol, (char *)zlemetaline)) {
/* We may have removed some quotes. For completion, other
* parts of the code re-install them, but for expansion
* we have to do it here. */
- zlecs = 0;
- foredel(zlell);
+ zlemetacs = 0;
+ foredel(zlemetall);
spaceinline(origll);
- memcpy(zleline, origline, origll);
- zlecs = origcs;
+ memcpy(zlemetaline, origline, origll);
+ zlemetacs = origcs;
}
}
} else
@@ -828,11 +845,11 @@ docomplete(int lst)
/* Reset the lexer state, pop the heap. */
lexrestore();
popheap();
- unmetafy_line();
dat[0] = lst;
dat[1] = ret;
runhookdef(AFTERCOMPLETEHOOK, (void *) dat);
+ unmetafy_line();
active = 0;
return dat[1];
@@ -865,23 +882,26 @@ addx(char **ptmp)
{
int addspace = 0;
- if (!zleline[zlecs] || zleline[zlecs] == '\n' ||
- (iblank(zleline[zlecs]) && (!zlecs || zleline[zlecs-1] != '\\')) ||
- zleline[zlecs] == ')' || zleline[zlecs] == '`' ||
- zleline[zlecs] == '}' ||
- zleline[zlecs] == ';' || zleline[zlecs] == '|' ||
- zleline[zlecs] == '&' ||
- zleline[zlecs] == '>' || zleline[zlecs] == '<' ||
- (instring && (zleline[zlecs] == '"' || zleline[zlecs] == '\'')) ||
- (addspace = (comppref && !iblank(zleline[zlecs])))) {
- *ptmp = (char *)zleline;
- zleline = (ZLE_STRING_T)zhalloc(strlen((char *)zleline) + 3 +
- addspace);
- memcpy(zleline, *ptmp, zlecs);
- zleline[zlecs] = 'x';
+ if (!zlemetaline[zlemetacs] || zlemetaline[zlemetacs] == '\n' ||
+ (iblank(zlemetaline[zlemetacs]) &&
+ (!zlemetacs || zlemetaline[zlemetacs-1] != '\\')) ||
+ zlemetaline[zlemetacs] == ')' || zlemetaline[zlemetacs] == '`' ||
+ zlemetaline[zlemetacs] == '}' ||
+ zlemetaline[zlemetacs] == ';' || zlemetaline[zlemetacs] == '|' ||
+ zlemetaline[zlemetacs] == '&' ||
+ zlemetaline[zlemetacs] == '>' || zlemetaline[zlemetacs] == '<' ||
+ (instring && (zlemetaline[zlemetacs] == '"' ||
+ zlemetaline[zlemetacs] == '\'')) ||
+ (addspace = (comppref && !iblank(zlemetaline[zlemetacs])))) {
+ *ptmp = (char *)zlemetaline;
+ zlemetaline = (unsigned char *)zhalloc(strlen((char *)zlemetaline)
+ + 3 + addspace);
+ memcpy(zlemetaline, *ptmp, zlemetacs);
+ zlemetaline[zlemetacs] = 'x';
if (addspace)
- zleline[zlecs+1] = ' ';
- strcpy((char *)zleline + zlecs + 1 + addspace, (*ptmp) + zlecs);
+ zlemetaline[zlemetacs+1] = ' ';
+ strcpy((char *)zlemetaline + zlemetacs + 1 + addspace,
+ (*ptmp) + zlemetacs);
addedx = 1 + addspace;
} else {
addedx = 0;
@@ -902,35 +922,47 @@ dupstrspace(const char *str)
return t;
}
-/* These functions metafy and unmetafy the ZLE buffer, as described at the *
- * top of this file. Note that zlell and zlecs are translated. They *must* be *
- * called in matching pairs, around all the expansion/completion code. *
- * Currently, there are four pairs: in history expansion, in the main *
- * completion function, and one in each of the middle-of-menu-completion *
- * functions (there's one for each direction). */
+/*
+ * These functions metafy and unmetafy the ZLE buffer, as described at
+ * the top of this file. They *must* be called in matching pairs,
+ * around all the expansion/completion code.
+ *
+ * The variables zleline, zlell and zlecs are metafied into
+ * zlemetaline, zlemetall and zlemetacs. Only the latter variables
+ * should be referred to from above zle (i.e. in the main shell),
+ * or when using the completion API (if that's not too strong a
+ * way of referring to it).
+ */
/**/
mod_export void
metafy_line(void)
{
- int len = zlell;
- char *s;
+ UNMETACHECK();
+
+ zlemetaline = zlelineasstring(zleline, zlell, zlecs,
+ &zlemetall, &zlemetacs, 0);
+ metalinesz = zlemetall;
- for (s = (char *) zleline; s < (char *) zleline + zlell;)
- if (imeta(*s++))
- len++;
- sizeline(len);
- (void) metafy((char *) zleline, zlell, META_NOALLOC);
- zlell = len;
- zlecs = metalen((char *) zleline, zlecs);
+ /*
+ * We will always allocate a new zleline based on zlemetaline.
+ */
+ free(zleline);
+ zleline = NULL;
}
/**/
mod_export void
unmetafy_line(void)
{
- zlecs = ztrsub((char *) zleline + zlecs, (char *) zleline);
- (void) unmetafy((char *) zleline, &zlell);
+ METACHECK();
+
+ /* paranoia */
+ zlemetaline[zlemetall] = '\0';
+ zleline = stringaszleline(zlemetaline, zlemetacs, &zlell, &linesz, &zlecs);
+
+ free(zlemetaline);
+ zlemetaline = NULL;
}
/* Free a brinfo list. */
@@ -1004,6 +1036,8 @@ get_comp_string(void)
int ona = noaliases, qsub;
char *s = NULL, *linptr, *tmp, *p, *tt = NULL, rdop[20];
+ METACHECK();
+
freebrinfo(brbeg);
freebrinfo(brend);
brbeg = lastbrbeg = brend = lastbrend = NULL;
@@ -1025,7 +1059,8 @@ get_comp_string(void)
* "...", `...`, or ((...)). Nowadays this is only used to find *
* out if we are inside `...`. */
- for (i = j = k = 0, p = (char *)zleline; p < (char *)zleline + zlecs; p++)
+ for (i = j = k = 0, p = (char *)zlemetaline;
+ p < (char *)zlemetaline + zlemetacs; p++)
if (*p == '`' && !(k & 1))
i++;
else if (*p == '\"' && !(k & 1) && !(i & 1))
@@ -1037,7 +1072,7 @@ get_comp_string(void)
inbackt = (i & 1);
instring = 0;
addx(&tmp);
- linptr = (char *)zleline;
+ linptr = (char *)zlemetaline;
pushheap();
start:
@@ -1146,14 +1181,14 @@ get_comp_string(void)
tt = tokstr ? dupstring(tokstr) : NULL;
if (isset(RCQUOTES) && *tt == Snull) {
- char *p, *e = tt + zlecs - wb;
+ char *p, *e = tt + zlemetacs - wb;
for (p = tt; *p && p < e; p++)
if (*p == '\'')
qsub++;
}
/* If we added a `x', remove it. */
if (addedx && tt)
- chuck(tt + zlecs - wb - qsub);
+ chuck(tt + zlemetacs - wb - qsub);
tt0 = tok;
/* Store the number of this word. */
clwpos = i;
@@ -1201,8 +1236,8 @@ get_comp_string(void)
/* If this is the word the cursor is in and we added a `x', *
* remove it. */
if (clwpos == i++ && addedx)
- chuck(&clwords[i - 1][((zlecs - wb - qsub) >= sl) ?
- (sl - 1) : (zlecs - wb - qsub)]);
+ chuck(&clwords[i - 1][((zlemetacs - wb - qsub) >= sl) ?
+ (sl - 1) : (zlemetacs - wb - qsub)]);
} while (tok != LEXERR && tok != ENDINPUT &&
(tok != SEPER || (zleparse && !tt0)));
/* Calculate the number of words stored in the clwords array. */
@@ -1224,13 +1259,14 @@ get_comp_string(void)
/* We are in command or process substitution if we are not in
* a $((...)). */
if (parend >= 0 && !tmp)
- zleline = (unsigned char *) dupstring(tmp = (char *)zleline);
- linptr = (char *) zleline + zlell + addedx - parbegin + 1;
- if ((linptr - (char *) zleline) < 3 || *linptr != '(' ||
+ zlemetaline = (unsigned char *)
+ dupstring(tmp = (char *)zlemetaline);
+ linptr = (char *) zlemetaline + zlemetall + addedx - parbegin + 1;
+ if ((linptr - (char *) zlemetaline) < 3 || *linptr != '(' ||
linptr[-1] != '(' || linptr[-2] != '$') {
if (parend >= 0) {
- zlell -= parend;
- zleline[zlell + addedx] = '\0';
+ zlemetall -= parend;
+ zlemetaline[zlemetall + addedx] = '\0';
}
lexrestore();
tt = NULL;
@@ -1243,7 +1279,7 @@ get_comp_string(void)
else if (!t0 || t0 == ENDINPUT) {
/* There was no word (empty line). */
s = ztrdup("");
- we = wb = zlecs;
+ we = wb = zlemetacs;
clwpos = clwnum;
t0 = STRING;
} else if (t0 == STRING) {
@@ -1264,7 +1300,7 @@ get_comp_string(void)
*s = sav;
if (*s == '+')
s++;
- if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + zlecs - wb) {
+ if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + zlemetacs - wb) {
s = NULL;
inwhat = IN_MATH;
if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
@@ -1273,7 +1309,7 @@ get_comp_string(void)
else
insubscr = 1;
} else if (*s == '=') {
- if (zlecs > wb + (s - tt)) {
+ if (zlemetacs > wb + (s - tt)) {
s++;
wb += s - tt;
s = ztrdup(s);
@@ -1294,17 +1330,17 @@ get_comp_string(void)
}
lincmd = 1;
}
- if (we > zlell)
- we = zlell;
- tt = (char *)zleline;
+ if (we > zlemetall)
+ we = zlemetall;
+ tt = (char *)zlemetaline;
if (tmp) {
- zleline = (unsigned char *)tmp;
- zlell = strlen((char *)zleline);
+ zlemetaline = (unsigned char *)tmp;
+ zlemetall = strlen((char *)zlemetaline);
}
if (t0 != STRING && inwhat != IN_MATH) {
if (tmp) {
tmp = NULL;
- linptr = (char *)zleline;
+ linptr = (char *)zlemetaline;
lexrestore();
addedx = 0;
goto start;
@@ -1325,7 +1361,7 @@ get_comp_string(void)
int i = 0;
char *nnb = (iident(*s) ? s : s + 1), *nb = NULL, *ne = NULL;
- for (tt = s; ++tt < s + zlecs - wb;)
+ for (tt = s; ++tt < s + zlemetacs - wb;)
if (*tt == Inbrack) {
i++;
nb = nnb;
@@ -1354,23 +1390,23 @@ get_comp_string(void)
int lev;
char *p;
- for (wb = zlecs - 1, lev = 0; wb > 0; wb--)
- if (zleline[wb] == ']' || zleline[wb] == ')')
+ for (wb = zlemetacs - 1, lev = 0; wb > 0; wb--)
+ if (zlemetaline[wb] == ']' || zlemetaline[wb] == ')')
lev++;
- else if (zleline[wb] == '[') {
+ else if (zlemetaline[wb] == '[') {
if (!lev--)
break;
- } else if (zleline[wb] == '(') {
- if (!lev && zleline[wb - 1] == '(')
+ } else if (zlemetaline[wb] == '(') {
+ if (!lev && zlemetaline[wb - 1] == '(')
break;
if (lev)
lev--;
}
- p = (char *) zleline + wb;
+ p = (char *) zlemetaline + wb;
wb++;
if (wb && (*p == '[' || *p == '(') &&
!skipparens(*p, (*p == '[' ? ']' : ')'), &p)) {
- we = (p - (char *) zleline) - 1;
+ we = (p - (char *) zlemetaline) - 1;
if (insubscr == 2)
insubscr = 3;
}
@@ -1378,25 +1414,26 @@ get_comp_string(void)
/* In mathematical expression, we complete parameter names *
* (even if they don't have a `$' in front of them). So we *
* have to find that name. */
- for (we = zlecs; iident(zleline[we]); we++);
- for (wb = zlecs; --wb >= 0 && iident(zleline[wb]););
+ for (we = zlemetacs; iident(zlemetaline[we]); we++);
+ for (wb = zlemetacs; --wb >= 0 && iident(zlemetaline[wb]););
wb++;
}
zsfree(s);
s = zalloc(we - wb + 1);
- strncpy(s, (char *) zleline + wb, we - wb);
+ strncpy(s, (char *) zlemetaline + wb, we - wb);
s[we - wb] = '\0';
- if (wb > 2 && zleline[wb - 1] == '[' && iident(zleline[wb - 2])) {
+ if (wb > 2 && zlemetaline[wb - 1] == '[' &&
+ iident(zlemetaline[wb - 2])) {
int i = wb - 3;
- unsigned char sav = zleline[wb - 1];
+ unsigned char sav = zlemetaline[wb - 1];
- while (i >= 0 && iident(zleline[i]))
+ while (i >= 0 && iident(zlemetaline[i]))
i--;
- zleline[wb - 1] = '\0';
+ zlemetaline[wb - 1] = '\0';
zsfree(varname);
- varname = ztrdup((char *) zleline + i + 1);
- zleline[wb - 1] = sav;
+ varname = ztrdup((char *) zlemetaline + i + 1);
+ zlemetaline[wb - 1] = sav;
if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
(keypm->flags & PM_HASHED)) {
if (insubscr != 3)
@@ -1407,7 +1444,7 @@ get_comp_string(void)
parse_subst_string(s);
}
/* This variable will hold the current word in quoted form. */
- offs = zlecs - wb;
+ offs = zlemetacs - wb;
if ((p = parambeg(s))) {
for (p = s; *p; p++)
if (*p == Dnull)
@@ -1451,34 +1488,34 @@ get_comp_string(void)
/* While building the quoted form, we also clean up the command line. */
for (p = s, i = wb, j = 0; *p; p++, i++)
if (INULL(*p)) {
- if (i < zlecs)
+ if (i < zlemetacs)
offs--;
if (*p == Snull && isset(RCQUOTES))
j = 1-j;
if (p[1] || *p != Bnull) {
if (*p == Bnull) {
- if (zlecs == i + 1)
- zlecs++, offs++;
+ if (zlemetacs == i + 1)
+ zlemetacs++, offs++;
} else {
- ocs = zlecs;
- zlecs = i;
+ ocs = zlemetacs;
+ zlemetacs = i;
foredel(1);
- if ((zlecs = ocs) > i--)
- zlecs--;
+ if ((zlemetacs = ocs) > i--)
+ zlemetacs--;
we--;
}
} else {
- ocs = zlecs;
- zlecs = we;
+ ocs = zlemetacs;
+ zlemetacs = we;
backdel(1);
if (ocs == we)
- zlecs = we - 1;
+ zlemetacs = we - 1;
else
- zlecs = ocs;
+ zlemetacs = ocs;
we--;
}
chuck(p--);
- } else if (j && *p == '\'' && i < zlecs)
+ } else if (j && *p == '\'' && i < zlemetacs)
offs--;
zsfree(origword);
@@ -1746,9 +1783,24 @@ inststrlen(char *str, int move, int len)
if (len == -1)
len = strlen(str);
spaceinline(len);
- strncpy((char *)(zleline + zlecs), str, len);
- if (move)
- zlecs += len;
+ if (zlemetaline != NULL)
+ {
+ strncpy((char *)(zlemetaline + zlemetacs), str, len);
+ if (move)
+ zlemetacs += len;
+ }
+ else
+ {
+ unsigned char *instr;
+ ZLE_STRING_T zlestr;
+ int zlelen;
+
+ instr = (unsigned char *)ztrduppfx((char *)str, len);
+ zlestr = stringaszleline(instr, 0, &zlelen, NULL, NULL);
+ ZS_strncpy(zleline + zlecs, zlestr, zlelen);
+ free(zlestr);
+ zsfree((char *)instr);
+ }
return len;
}
@@ -1801,17 +1853,17 @@ doexpansion(char *s, int lst, int olst, int explincmd)
if (lst == COMP_LIST_EXPAND) {
/* Only the list of expansions was requested. Restore the
* command line. */
- zlecs = 0;
- foredel(zlell);
+ zlemetacs = 0;
+ foredel(zlemetall);
spaceinline(origll);
- memcpy(zleline, origline, origll);
- zlecs = origcs;
+ memcpy(zlemetaline, origline, origll);
+ zlemetacs = origcs;
ret = listlist(vl);
showinglist = 0;
goto end;
}
/* Remove the current word and put the expansions there. */
- zlecs = wb;
+ zlemetacs = wb;
foredel(we - wb);
while ((ss = (char *)ugetnode(vl))) {
ret = 0;
@@ -1820,11 +1872,11 @@ doexpansion(char *s, int lst, int olst, int explincmd)
inststr(ss);
#if 0
if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) ||
- (zlecs && zleline[zlecs-1] != '/')) {
+ (zlemetacs && zlemetaline[zlemetacs-1] != '/')) {
#endif
if (nonempty(vl) || !first) {
spaceinline(1);
- zleline[zlecs++] = ' ';
+ zlemetaline[zlemetacs++] = ' ';
}
first = 0;
}
@@ -2250,14 +2302,16 @@ doexpandhist(void)
unsigned char *ol;
int oll, ocs, ne = noerrs, err, ona = noaliases;
+ UNMETACHECK();
+
pushheap();
metafy_line();
- oll = zlell;
- ocs = zlecs;
- ol = (unsigned char *)dupstring((char *)zleline);
+ oll = zlemetall;
+ ocs = zlemetacs;
+ ol = (unsigned char *)dupstring((char *)zlemetaline);
expanding = 1;
- excs = zlecs;
- zlell = zlecs = 0;
+ excs = zlemetacs;
+ zlemetall = zlemetacs = 0;
lexsave();
/* We push ol as it will remain unchanged */
inpush((char *) ol, 0, NULL);
@@ -2283,8 +2337,8 @@ doexpandhist(void)
expanding = 0;
if (!err) {
- zlecs = excs;
- if (strcmp((char *)zleline, (char *)ol)) {
+ zlemetacs = excs;
+ if (strcmp((char *)zlemetaline, (char *)ol)) {
unmetafy_line();
/* For vi mode -- reset the beginning-of-insertion pointer *
* to the beginning of the line. This seems a little silly, *
@@ -2296,9 +2350,9 @@ doexpandhist(void)
}
}
- strcpy((char *)zleline, (char *)ol);
- zlell = oll;
- zlecs = ocs;
+ strcpy((char *)zlemetaline, (char *)ol);
+ zlemetall = oll;
+ zlemetacs = ocs;
unmetafy_line();
popheap();
@@ -2325,26 +2379,35 @@ fixmagicspace(void)
int
magicspace(char **args)
{
- char *bangq;
+ ZLE_STRING_T bangq;
+ ZLE_CHAR_T zlebangchar[1];
int ret;
fixmagicspace();
- for (bangq = (char *)zleline; (bangq = strchr(bangq, bangchar));
- bangq += 2)
- if (bangq[1] == '"' && (bangq == (char *)zleline || bangq[-1] != '\\'))
- break;
+
#ifdef ZLE_UNICODE_SUPPORT
/*
- * TODO: expansion and completion with Unicode are currently
- * fundamentally broken. Most of the code for this hasn't been
- * commented out, but crashing the shell just because you entered
- * a space seems to be worth guarding against.
+ * TODO: bangchar should really be a multibyte string representing
+ * a single character, since there's no fundamental reason why
+ * it shouldn't be a Unicode character. In practice this is
+ * very minor, however.
*/
- ret = selfinsert(args);
+ if (mbtowc(zlebangchar, (char *)&bangchar, 1) < 0)
+ return selfinsert(args);
#else
+ zlebangchar[0] = bangchar;
+#endif
+ for (bangq = zleline; bangq < zleline + zlell; bangq++)
+ {
+ if (*bangq != zlebangchar[0])
+ continue;
+ if (bangq[1] == ZWC('"') &&
+ (bangq == zleline || bangq[-1] == ZWC('\\')))
+ break;
+ }
+
if (!(ret = selfinsert(args)) &&
- (!bangq || bangq + 2 > (char *)zleline + zlecs))
+ (!bangq || bangq + 2 > zleline + zlecs))
doexpandhist();
-#endif
return ret;
}
@@ -2369,8 +2432,7 @@ getcurcmd(void)
zleparse = 2;
lexsave();
metafy_line();
- inpush(dupstrspace((char *) zleline), 0, NULL);
- unmetafy_line();
+ inpush(dupstrspace((char *) zlemetaline), 0, NULL);
strinbeg(1);
pushheap();
do {
@@ -2381,8 +2443,8 @@ getcurcmd(void)
if (tok == STRING && curlincmd) {
zsfree(s);
s = ztrdup(tokstr);
- cmdwb = zlell - wordbeg;
- cmdwe = zlell + 1 - inbufct;
+ cmdwb = zlemetall - wordbeg;
+ cmdwe = zlemetall + 1 - inbufct;
}
}
while (tok != ENDINPUT && tok != LEXERR && zleparse);
@@ -2390,6 +2452,7 @@ getcurcmd(void)
strinend();
inpop();
errflag = zleparse = 0;
+ unmetafy_line();
lexrestore();
return s;
@@ -2426,8 +2489,13 @@ processcmd(UNUSED(char **args))
int
expandcmdpath(UNUSED(char **args))
{
- int oldcs = zlecs, na = noaliases;
+ /*
+ * zleline is not metafied for most of this function
+ * (that happens within getcurcmd()).
+ */
+ int oldcs = zlecs, na = noaliases, strll;
char *s, *str;
+ ZLE_STRING_T zlestr;
noaliases = 1;
s = getcurcmd();
@@ -2440,8 +2508,11 @@ expandcmdpath(UNUSED(char **args))
return 1;
zlecs = cmdwb;
foredel(cmdwe - cmdwb);
- spaceinline(strlen(str));
- strncpy((char *)zleline + zlecs, str, strlen(str));
+ zlestr = stringaszleline((unsigned char *)str, 0,
+ &strll, NULL, NULL);
+ spaceinline(strll);
+ ZS_strncpy(zleline + zlecs, zlestr, strll);
+ free(zlestr);
zlecs = oldcs;
if (zlecs >= cmdwe - 1)
zlecs += cmdwe - cmdwb + strlen(str);
@@ -2461,7 +2532,7 @@ expandorcompleteprefix(char **args)
comppref = 1;
ret = expandorcomplete(args);
- if (zlecs && zleline[zlecs - 1] == ' ')
+ if (zlecs && zleline[zlecs - 1] == ZWC(' '))
makesuffixstr(NULL, "\\-", 0);
comppref = 0;
return ret;