refactor code to be able to track whether we have a parameter substitution
or a “proper” glob expansion; if there’s a dollar, but not a glob, refrain from appending a space later (LP: #710539)
This commit is contained in:
4
check.t
4
check.t
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.t,v 1.404 2011/01/30 02:18:25 tg Exp $
|
# $MirOS: src/bin/mksh/check.t,v 1.405 2011/02/03 15:57:49 tg Exp $
|
||||||
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
||||||
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
||||||
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
||||||
@ -25,7 +25,7 @@
|
|||||||
# http://www.research.att.com/~gsf/public/ifs.sh
|
# http://www.research.att.com/~gsf/public/ifs.sh
|
||||||
|
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
@(#)MIRBSD KSH R39 2011/01/29
|
@(#)MIRBSD KSH R39 2011/02/03
|
||||||
description:
|
description:
|
||||||
Check version of shell.
|
Check version of shell.
|
||||||
stdin:
|
stdin:
|
||||||
|
424
edit.c
424
edit.c
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.202 2011/01/21 22:43:17 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.203 2011/02/03 15:57:50 tg Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in later versions we might use libtermcap for this, but since external
|
* in later versions we might use libtermcap for this, but since external
|
||||||
@ -57,6 +57,9 @@ static X_chars edchars;
|
|||||||
#define XCF_FILE BIT(1) /* Do file completion */
|
#define XCF_FILE BIT(1) /* Do file completion */
|
||||||
#define XCF_FULLPATH BIT(2) /* command completion: store full path */
|
#define XCF_FULLPATH BIT(2) /* command completion: store full path */
|
||||||
#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
|
#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
|
||||||
|
#define XCF_IS_COMMAND BIT(3) /* return flag: is command */
|
||||||
|
#define XCF_IS_VARSUB BIT(4) /* return flag: is $FOO substitution */
|
||||||
|
#define XCF_IS_EXTGLOB BIT(5) /* return flag: is foo* expansion */
|
||||||
|
|
||||||
static char editmode;
|
static char editmode;
|
||||||
static int xx_cols; /* for Emacs mode */
|
static int xx_cols; /* for Emacs mode */
|
||||||
@ -68,8 +71,7 @@ static void x_putcf(int);
|
|||||||
static bool x_mode(bool);
|
static bool x_mode(bool);
|
||||||
static int x_do_comment(char *, int, int *);
|
static int x_do_comment(char *, int, int *);
|
||||||
static void x_print_expansions(int, char *const *, bool);
|
static void x_print_expansions(int, char *const *, bool);
|
||||||
static int x_cf_glob(int, const char *, int, int, int *, int *, char ***,
|
static int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
|
||||||
bool *);
|
|
||||||
static int x_longest_prefix(int, char *const *);
|
static int x_longest_prefix(int, char *const *);
|
||||||
static int x_basename(const char *, const char *);
|
static int x_basename(const char *, const char *);
|
||||||
static void x_free_words(int, char **);
|
static void x_free_words(int, char **);
|
||||||
@ -89,17 +91,10 @@ static int x_vi(char *, size_t);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int path_order_cmp(const void *aa, const void *bb);
|
static int path_order_cmp(const void *aa, const void *bb);
|
||||||
static char *add_glob(const char *, int)
|
|
||||||
MKSH_A_NONNULL((nonnull (1)))
|
|
||||||
MKSH_A_BOUNDED(string, 1, 2);
|
|
||||||
static void glob_table(const char *, XPtrV *, struct table *);
|
static void glob_table(const char *, XPtrV *, struct table *);
|
||||||
static void glob_path(int flags, const char *, XPtrV *, const char *);
|
static void glob_path(int flags, const char *, XPtrV *, const char *);
|
||||||
static int x_file_glob(int, const char *, int, char ***)
|
static int x_file_glob(int, char *, char ***);
|
||||||
MKSH_A_NONNULL((nonnull (2)))
|
static int x_command_glob(int, char *, char ***);
|
||||||
MKSH_A_BOUNDED(string, 2, 3);
|
|
||||||
static int x_command_glob(int, const char *, int, char ***)
|
|
||||||
MKSH_A_NONNULL((nonnull (2)))
|
|
||||||
MKSH_A_BOUNDED(string, 2, 3);
|
|
||||||
static int x_locate_word(const char *, int, int, int *, bool *);
|
static int x_locate_word(const char *, int, int, int *, bool *);
|
||||||
|
|
||||||
static int x_e_getmbc(char *);
|
static int x_e_getmbc(char *);
|
||||||
@ -111,11 +106,14 @@ static int x_e_rebuildline(const char *);
|
|||||||
void
|
void
|
||||||
x_init(void)
|
x_init(void)
|
||||||
{
|
{
|
||||||
/* set to -2 to force initial binding */
|
/*
|
||||||
|
* Set edchars to -2 to force initial binding, except
|
||||||
|
* we need default values for some deficient systems…
|
||||||
|
*/
|
||||||
edchars.erase = edchars.kill = edchars.intr = edchars.quit =
|
edchars.erase = edchars.kill = edchars.intr = edchars.quit =
|
||||||
edchars.eof = -2;
|
edchars.eof = -2;
|
||||||
/* default value for deficient systems */
|
/* ^W */
|
||||||
edchars.werase = 027; /* ^W */
|
edchars.werase = 027;
|
||||||
x_init_emacs();
|
x_init_emacs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +134,8 @@ x_read(char *buf, size_t len)
|
|||||||
i = x_vi(buf, len);
|
i = x_vi(buf, len);
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
i = -1; /* internal error */
|
/* internal error */
|
||||||
|
i = -1;
|
||||||
editmode = 0;
|
editmode = 0;
|
||||||
x_mode(false);
|
x_mode(false);
|
||||||
return (i);
|
return (i);
|
||||||
@ -179,7 +178,8 @@ x_putcf(int c)
|
|||||||
* Misc common code for vi/emacs *
|
* Misc common code for vi/emacs *
|
||||||
*********************************/
|
*********************************/
|
||||||
|
|
||||||
/* Handle the commenting/uncommenting of a line.
|
/*-
|
||||||
|
* Handle the commenting/uncommenting of a line.
|
||||||
* Returns:
|
* Returns:
|
||||||
* 1 if a carriage return is indicated (comment added)
|
* 1 if a carriage return is indicated (comment added)
|
||||||
* 0 if no return (comment removed)
|
* 0 if no return (comment removed)
|
||||||
@ -193,7 +193,8 @@ x_do_comment(char *buf, int bsize, int *lenp)
|
|||||||
int i, j, len = *lenp;
|
int i, j, len = *lenp;
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (1); /* somewhat arbitrary - it's what AT&T ksh does */
|
/* somewhat arbitrary - it's what AT&T ksh does */
|
||||||
|
return (1);
|
||||||
|
|
||||||
/* Already commented? */
|
/* Already commented? */
|
||||||
if (buf[0] == '#') {
|
if (buf[0] == '#') {
|
||||||
@ -238,7 +239,8 @@ x_print_expansions(int nwords, char * const *words, bool is_command)
|
|||||||
int prefix_len;
|
int prefix_len;
|
||||||
XPtrV l = { NULL, NULL, NULL };
|
XPtrV l = { NULL, NULL, NULL };
|
||||||
|
|
||||||
/* Check if all matches are in the same directory (in this
|
/*
|
||||||
|
* Check if all matches are in the same directory (in this
|
||||||
* case, we want to omit the directory name)
|
* case, we want to omit the directory name)
|
||||||
*/
|
*/
|
||||||
if (!is_command &&
|
if (!is_command &&
|
||||||
@ -272,7 +274,8 @@ x_print_expansions(int nwords, char * const *words, bool is_command)
|
|||||||
pr_list(use_copy ? (char **)XPptrv(l) : words);
|
pr_list(use_copy ? (char **)XPptrv(l) : words);
|
||||||
|
|
||||||
if (use_copy)
|
if (use_copy)
|
||||||
XPfree(l); /* not x_free_words() */
|
/* not x_free_words() */
|
||||||
|
XPfree(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -283,19 +286,14 @@ x_print_expansions(int nwords, char * const *words, bool is_command)
|
|||||||
* - returns number of matching strings
|
* - returns number of matching strings
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
x_file_glob(int flags MKSH_A_UNUSED, const char *str, int slen, char ***wordsp)
|
x_file_glob(int flags MKSH_A_UNUSED, char *toglob, char ***wordsp)
|
||||||
{
|
{
|
||||||
char *toglob, **words;
|
char **words;
|
||||||
int nwords, i, idx;
|
int nwords, i, idx;
|
||||||
bool escaping;
|
bool escaping;
|
||||||
XPtrV w;
|
XPtrV w;
|
||||||
struct source *s, *sold;
|
struct source *s, *sold;
|
||||||
|
|
||||||
if (slen < 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
toglob = add_glob(str, slen);
|
|
||||||
|
|
||||||
/* remove all escaping backward slashes */
|
/* remove all escaping backward slashes */
|
||||||
escaping = false;
|
escaping = false;
|
||||||
for (i = 0, idx = 0; toglob[i]; i++) {
|
for (i = 0, idx = 0; toglob[i]; i++) {
|
||||||
@ -338,8 +336,9 @@ x_file_glob(int flags MKSH_A_UNUSED, const char *str, int slen, char ***wordsp)
|
|||||||
if (nwords == 1) {
|
if (nwords == 1) {
|
||||||
struct stat statb;
|
struct stat statb;
|
||||||
|
|
||||||
/* Check if globbing failed (returned glob pattern),
|
/*
|
||||||
* but be careful (E.g. toglob == "ab*" when the file
|
* Check if globbing failed (returned glob pattern),
|
||||||
|
* but be careful (e.g. toglob == "ab*" when the file
|
||||||
* "ab*" exists is not an error).
|
* "ab*" exists is not an error).
|
||||||
* Also, check for empty result - happens if we tried
|
* Also, check for empty result - happens if we tried
|
||||||
* to glob something which evaluated to an empty
|
* to glob something which evaluated to an empty
|
||||||
@ -353,7 +352,6 @@ x_file_glob(int flags MKSH_A_UNUSED, const char *str, int slen, char ***wordsp)
|
|||||||
nwords = 0;
|
nwords = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
afree(toglob, ATEMP);
|
|
||||||
|
|
||||||
if ((*wordsp = nwords ? words : NULL) == NULL && words != NULL)
|
if ((*wordsp = nwords ? words : NULL) == NULL && words != NULL)
|
||||||
x_free_words(nwords, words);
|
x_free_words(nwords, words);
|
||||||
@ -381,21 +379,15 @@ path_order_cmp(const void *aa, const void *bb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
x_command_glob(int flags, const char *str, int slen, char ***wordsp)
|
x_command_glob(int flags, char *toglob, char ***wordsp)
|
||||||
{
|
{
|
||||||
char *toglob, *pat, *fpath;
|
char *pat, *fpath;
|
||||||
int nwords;
|
int nwords;
|
||||||
XPtrV w;
|
XPtrV w;
|
||||||
struct block *l;
|
struct block *l;
|
||||||
|
|
||||||
if (slen < 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
toglob = add_glob(str, slen);
|
|
||||||
|
|
||||||
/* Convert "foo*" (toglob) to a pattern for future use */
|
/* Convert "foo*" (toglob) to a pattern for future use */
|
||||||
pat = evalstr(toglob, DOPAT | DOTILDE);
|
pat = evalstr(toglob, DOPAT | DOTILDE);
|
||||||
afree(toglob, ATEMP);
|
|
||||||
|
|
||||||
XPinit(w, 32);
|
XPinit(w, 32);
|
||||||
|
|
||||||
@ -481,7 +473,8 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp,
|
|||||||
/* The case where pos == buflen happens to take care of itself... */
|
/* The case where pos == buflen happens to take care of itself... */
|
||||||
|
|
||||||
start = pos;
|
start = pos;
|
||||||
/* Keep going backwards to start of word (has effect of allowing
|
/*
|
||||||
|
* Keep going backwards to start of word (has effect of allowing
|
||||||
* one blank after the end of a word)
|
* one blank after the end of a word)
|
||||||
*/
|
*/
|
||||||
for (; (start > 0 && IS_WORDC(buf[start - 1])) ||
|
for (; (start > 0 && IS_WORDC(buf[start - 1])) ||
|
||||||
@ -502,7 +495,8 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp,
|
|||||||
p--;
|
p--;
|
||||||
iscmd = p < 0 || vstrchr(";|&()`", buf[p]);
|
iscmd = p < 0 || vstrchr(";|&()`", buf[p]);
|
||||||
if (iscmd) {
|
if (iscmd) {
|
||||||
/* If command has a /, path, etc. is not searched;
|
/*
|
||||||
|
* If command has a /, path, etc. is not searched;
|
||||||
* only current directory is searched which is just
|
* only current directory is searched which is just
|
||||||
* like file globbing.
|
* like file globbing.
|
||||||
*/
|
*/
|
||||||
@ -519,55 +513,34 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
x_cf_glob(int flags, const char *buf, int buflen, int pos, int *startp,
|
x_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp,
|
||||||
int *endp, char ***wordsp, bool *is_commandp)
|
int *endp, char ***wordsp)
|
||||||
{
|
{
|
||||||
int len, nwords;
|
int len, nwords = 0;
|
||||||
char **words = NULL;
|
char **words = NULL;
|
||||||
bool is_command;
|
bool is_command;
|
||||||
|
|
||||||
len = x_locate_word(buf, buflen, pos, startp, &is_command);
|
len = x_locate_word(buf, buflen, pos, startp, &is_command);
|
||||||
if (!(flags & XCF_COMMAND))
|
if (!(*flagsp & XCF_COMMAND))
|
||||||
is_command = false;
|
is_command = false;
|
||||||
/* Don't do command globing on zero length strings - it takes too
|
/*
|
||||||
|
* Don't do command globing on zero length strings - it takes too
|
||||||
* long and isn't very useful. File globs are more likely to be
|
* long and isn't very useful. File globs are more likely to be
|
||||||
* useful, so allow these.
|
* useful, so allow these.
|
||||||
*/
|
*/
|
||||||
if (len == 0 && is_command)
|
if (len == 0 && is_command)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
nwords = is_command ?
|
if (len >= 0) {
|
||||||
x_command_glob(flags, buf + *startp, len, &words) :
|
|
||||||
x_file_glob(flags, buf + *startp, len, &words);
|
|
||||||
if (nwords == 0) {
|
|
||||||
*wordsp = NULL;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
if (is_commandp)
|
|
||||||
*is_commandp = is_command;
|
|
||||||
*wordsp = words;
|
|
||||||
*endp = *startp + len;
|
|
||||||
|
|
||||||
return (nwords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given a string, copy it and possibly add a '*' to the end.
|
|
||||||
* The new string is returned.
|
|
||||||
*/
|
|
||||||
static char *
|
|
||||||
add_glob(const char *str, int slen)
|
|
||||||
{
|
|
||||||
char *toglob, *s;
|
char *toglob, *s;
|
||||||
bool saw_slash = false;
|
bool saw_slash = false, saw_dollar = false, saw_glob = false;
|
||||||
|
|
||||||
if (slen < 0)
|
/*
|
||||||
return (NULL);
|
* Given a string, copy it and possibly add a '*' to the end.
|
||||||
|
*/
|
||||||
|
|
||||||
/* for clang's static analyser, the nonnull attribute isn't enough */
|
strndupx(toglob, buf + *startp, len + /* the '*' */ 1, ATEMP);
|
||||||
mkssert(str != NULL);
|
toglob[len] = '\0';
|
||||||
|
|
||||||
strndupx(toglob, str, slen + 1, ATEMP); /* + 1 for "*" */
|
|
||||||
toglob[slen] = '\0';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the pathname contains a wildcard (an unquoted '*',
|
* If the pathname contains a wildcard (an unquoted '*',
|
||||||
@ -578,18 +551,56 @@ add_glob(const char *str, int slen)
|
|||||||
for (s = toglob; *s; s++) {
|
for (s = toglob; *s; s++) {
|
||||||
if (*s == '\\' && s[1])
|
if (*s == '\\' && s[1])
|
||||||
s++;
|
s++;
|
||||||
else if (*s == '*' || *s == '[' || *s == '?' || *s == '$' ||
|
else if (*s == '$') {
|
||||||
(s[1] == '(' /*)*/ && /* *s in '*','?' already checked */
|
/*
|
||||||
(*s == '+' || *s == '@' || *s == '!')))
|
* Do not append a space after the value
|
||||||
break;
|
* if expanding a parameter substitution
|
||||||
else if (*s == '/')
|
* as in: “cat $HOME/.ss↹” (LP: #710539)
|
||||||
|
*/
|
||||||
|
saw_dollar = true;
|
||||||
|
} else if (*s == '?' || *s == '*' || *s == '[' ||
|
||||||
|
/* ?() *() +() @() !() but two already checked */
|
||||||
|
(s[1] == '(' /*)*/ &&
|
||||||
|
(*s == '+' || *s == '@' || *s == '!'))) {
|
||||||
|
/* just expand based on the extglob */
|
||||||
|
saw_glob = true;
|
||||||
|
} else if (*s == '/')
|
||||||
saw_slash = true;
|
saw_slash = true;
|
||||||
}
|
}
|
||||||
if (!*s && (*toglob != '~' || saw_slash)) {
|
if (saw_glob) {
|
||||||
toglob[slen] = '*';
|
/*
|
||||||
toglob[slen + 1] = '\0';
|
* do not append a glob, we already have a
|
||||||
|
* glob or extglob; it works even if this is
|
||||||
|
* a parameter expansion as we have a glob
|
||||||
|
*/
|
||||||
|
*flagsp |= XCF_IS_EXTGLOB;
|
||||||
|
} else if (saw_dollar) {
|
||||||
|
/* do not append a glob, nor later a space */
|
||||||
|
*flagsp |= XCF_IS_VARSUB;
|
||||||
|
} else if (*toglob != '~' || saw_slash) {
|
||||||
|
/* append a glob, this is not just a tilde */
|
||||||
|
toglob[len] = '*';
|
||||||
|
toglob[len + 1] = '\0';
|
||||||
}
|
}
|
||||||
return (toglob);
|
|
||||||
|
/*
|
||||||
|
* Expand (glob) it now.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nwords = is_command ?
|
||||||
|
x_command_glob(*flagsp, toglob, &words) :
|
||||||
|
x_file_glob(*flagsp, toglob, &words);
|
||||||
|
afree(toglob, ATEMP);
|
||||||
|
}
|
||||||
|
if (nwords == 0) {
|
||||||
|
*wordsp = NULL;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
*flagsp |= XCF_IS_COMMAND;
|
||||||
|
*wordsp = words;
|
||||||
|
*endp = *startp + len;
|
||||||
|
|
||||||
|
return (nwords);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -622,7 +633,8 @@ x_free_words(int nwords, char **words)
|
|||||||
afree(words, ATEMP);
|
afree(words, ATEMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the offset of the basename of string s (which ends at se - need not
|
/*-
|
||||||
|
* Return the offset of the basename of string s (which ends at se - need not
|
||||||
* be null terminated). Trailing slashes are ignored. If s is just a slash,
|
* be null terminated). Trailing slashes are ignored. If s is just a slash,
|
||||||
* then the offset is 0 (actually, length - 1).
|
* then the offset is 0 (actually, length - 1).
|
||||||
* s Return
|
* s Return
|
||||||
@ -694,7 +706,8 @@ glob_path(int flags, const char *pat, XPtrV *wp, const char *lpath)
|
|||||||
p = sp + strlen(sp);
|
p = sp + strlen(sp);
|
||||||
pathlen = p - sp;
|
pathlen = p - sp;
|
||||||
if (pathlen) {
|
if (pathlen) {
|
||||||
/* Copy sp into xp, stuffing any MAGIC characters
|
/*
|
||||||
|
* Copy sp into xp, stuffing any MAGIC characters
|
||||||
* on the way
|
* on the way
|
||||||
*/
|
*/
|
||||||
const char *s = sp;
|
const char *s = sp;
|
||||||
@ -713,7 +726,8 @@ glob_path(int flags, const char *pat, XPtrV *wp, const char *lpath)
|
|||||||
memcpy(xp, pat, patlen);
|
memcpy(xp, pat, patlen);
|
||||||
|
|
||||||
oldsize = XPsize(*wp);
|
oldsize = XPsize(*wp);
|
||||||
glob_str(Xstring(xs, xp), wp, 1); /* mark dirs */
|
/* mark dirs */
|
||||||
|
glob_str(Xstring(xs, xp), wp, 1);
|
||||||
newsize = XPsize(*wp);
|
newsize = XPsize(*wp);
|
||||||
|
|
||||||
/* Check that each match is executable... */
|
/* Check that each match is executable... */
|
||||||
@ -809,7 +823,8 @@ struct x_defbindings {
|
|||||||
#define X_NTABS 3 /* normal, meta1, meta2 */
|
#define X_NTABS 3 /* normal, meta1, meta2 */
|
||||||
#define X_TABSZ 256 /* size of keydef tables etc */
|
#define X_TABSZ 256 /* size of keydef tables etc */
|
||||||
|
|
||||||
/* Arguments for do_complete()
|
/*-
|
||||||
|
* Arguments for do_complete()
|
||||||
* 0 = enumerate M-= complete as much as possible and then list
|
* 0 = enumerate M-= complete as much as possible and then list
|
||||||
* 1 = complete M-Esc
|
* 1 = complete M-Esc
|
||||||
* 2 = list M-?
|
* 2 = list M-?
|
||||||
@ -1000,7 +1015,8 @@ static struct x_defbindings const x_defbindings[] = {
|
|||||||
{ XFUNC_fold_capitalise, 1, 'C' },
|
{ XFUNC_fold_capitalise, 1, 'C' },
|
||||||
{ XFUNC_fold_capitalise, 1, 'c' },
|
{ XFUNC_fold_capitalise, 1, 'c' },
|
||||||
#endif
|
#endif
|
||||||
/* These for ansi arrow keys: arguablely shouldn't be here by
|
/*
|
||||||
|
* These for ANSI arrow keys: arguablely shouldn't be here by
|
||||||
* default, but its simpler/faster/smaller than using termcap
|
* default, but its simpler/faster/smaller than using termcap
|
||||||
* entries.
|
* entries.
|
||||||
*/
|
*/
|
||||||
@ -1156,7 +1172,8 @@ x_emacs(char *buf, size_t len)
|
|||||||
case KEOL:
|
case KEOL:
|
||||||
i = xep - xbuf;
|
i = xep - xbuf;
|
||||||
return (i);
|
return (i);
|
||||||
case KINTR: /* special case for interrupt */
|
case KINTR:
|
||||||
|
/* special case for interrupt */
|
||||||
trapsig(SIGINT);
|
trapsig(SIGINT);
|
||||||
x_mode(false);
|
x_mode(false);
|
||||||
unwind(LSHELL);
|
unwind(LSHELL);
|
||||||
@ -1267,7 +1284,8 @@ x_ins(const char *s)
|
|||||||
x_lastcp();
|
x_lastcp();
|
||||||
x_adj_ok = (xcp >= xlp);
|
x_adj_ok = (xcp >= xlp);
|
||||||
x_zots(cp);
|
x_zots(cp);
|
||||||
if (adj == x_adj_done) { /* has x_adjust() been called? */
|
/* has x_adjust() been called? */
|
||||||
|
if (adj == x_adj_done) {
|
||||||
/* no */
|
/* no */
|
||||||
cp = xlp;
|
cp = xlp;
|
||||||
while (cp > xcp)
|
while (cp > xcp)
|
||||||
@ -1356,13 +1374,15 @@ x_delete(int nc, int push)
|
|||||||
x_push(nb);
|
x_push(nb);
|
||||||
|
|
||||||
xep -= nb;
|
xep -= nb;
|
||||||
memmove(xcp, xcp + nb, xep - xcp + 1); /* Copies the NUL */
|
/* Copies the NUL */
|
||||||
x_adj_ok = 0; /* don't redraw */
|
memmove(xcp, xcp + nb, xep - xcp + 1);
|
||||||
|
/* don't redraw */
|
||||||
|
x_adj_ok = 0;
|
||||||
xlp_valid = false;
|
xlp_valid = false;
|
||||||
x_zots(xcp);
|
x_zots(xcp);
|
||||||
/*
|
/*
|
||||||
* if we are already filling the line,
|
* if we are already filling the line,
|
||||||
* there is no need to ' ','\b'.
|
* there is no need to ' ', '\b'.
|
||||||
* But if we must, make sure we do the minimum.
|
* But if we must, make sure we do the minimum.
|
||||||
*/
|
*/
|
||||||
if ((i = xx_cols - 2 - x_col) > 0 || xep - xlp == 0) {
|
if ((i = xx_cols - 2 - x_col) > 0 || xep - xlp == 0) {
|
||||||
@ -1474,10 +1494,12 @@ x_goto(char *cp)
|
|||||||
/* we are heading off screen */
|
/* we are heading off screen */
|
||||||
xcp = cp;
|
xcp = cp;
|
||||||
x_adjust();
|
x_adjust();
|
||||||
} else if (cp < xcp) { /* move back */
|
} else if (cp < xcp) {
|
||||||
|
/* move back */
|
||||||
while (cp < xcp)
|
while (cp < xcp)
|
||||||
x_bs3(&xcp);
|
x_bs3(&xcp);
|
||||||
} else if (cp > xcp) { /* move forward */
|
} else if (cp > xcp) {
|
||||||
|
/* move forward */
|
||||||
while (cp > xcp)
|
while (cp > xcp)
|
||||||
x_zotc3(&xcp);
|
x_zotc3(&xcp);
|
||||||
}
|
}
|
||||||
@ -1517,9 +1539,11 @@ x_size2(char *cp, char **dcp)
|
|||||||
if (dcp)
|
if (dcp)
|
||||||
*dcp = cp + 1;
|
*dcp = cp + 1;
|
||||||
if (c == '\t')
|
if (c == '\t')
|
||||||
return (4); /* Kludge, tabs are always four spaces. */
|
/* Kludge, tabs are always four spaces. */
|
||||||
|
return (4);
|
||||||
if (c < ' ' || c == 0x7f)
|
if (c < ' ' || c == 0x7f)
|
||||||
return (2); /* control unsigned char */
|
/* control unsigned char */
|
||||||
|
return (2);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1702,7 +1726,8 @@ x_next_com(int c MKSH_A_UNUSED)
|
|||||||
return (KSTD);
|
return (KSTD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Goto a particular history number obtained from argument.
|
/*
|
||||||
|
* Goto a particular history number obtained from argument.
|
||||||
* If no argument is given history 1 is probably not what you
|
* If no argument is given history 1 is probably not what you
|
||||||
* want so we'll simply go to the oldest one.
|
* want so we'll simply go to the oldest one.
|
||||||
*/
|
*/
|
||||||
@ -1835,7 +1860,8 @@ x_search_hist(int c)
|
|||||||
if (offset >= 0)
|
if (offset >= 0)
|
||||||
x_load_hist(histptr + 1);
|
x_load_hist(histptr + 1);
|
||||||
break;
|
break;
|
||||||
} else { /* other command */
|
} else {
|
||||||
|
/* other command */
|
||||||
x_e_ungetc(c);
|
x_e_ungetc(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1967,7 +1993,8 @@ x_cls(int c MKSH_A_UNUSED)
|
|||||||
return (x_e_rebuildline(MKSH_CLS_STRING));
|
return (x_e_rebuildline(MKSH_CLS_STRING));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redraw (part of) the line. If limit is < 0, the everything is redrawn
|
/*
|
||||||
|
* Redraw (part of) the line. If limit is < 0, the everything is redrawn
|
||||||
* on a NEW line, otherwise limit is the screen column up to which needs
|
* on a NEW line, otherwise limit is the screen column up to which needs
|
||||||
* redrawing.
|
* redrawing.
|
||||||
*/
|
*/
|
||||||
@ -2004,7 +2031,8 @@ x_redraw(int limit)
|
|||||||
limit = xx_cols;
|
limit = xx_cols;
|
||||||
if (limit >= 0) {
|
if (limit >= 0) {
|
||||||
if (xep > xlp)
|
if (xep > xlp)
|
||||||
i = 0; /* we fill the line */
|
/* we fill the line */
|
||||||
|
i = 0;
|
||||||
else {
|
else {
|
||||||
char *cpl = xbp;
|
char *cpl = xbp;
|
||||||
|
|
||||||
@ -2021,7 +2049,8 @@ x_redraw(int limit)
|
|||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
i = ' ';
|
i = ' ';
|
||||||
if (xep > xlp) { /* more off screen */
|
if (xep > xlp) {
|
||||||
|
/* more off screen */
|
||||||
if (xbp > xbuf)
|
if (xbp > xbuf)
|
||||||
i = '*';
|
i = '*';
|
||||||
else
|
else
|
||||||
@ -2045,7 +2074,8 @@ x_transpose(int c MKSH_A_UNUSED)
|
|||||||
{
|
{
|
||||||
unsigned int tmpa, tmpb;
|
unsigned int tmpa, tmpb;
|
||||||
|
|
||||||
/* What transpose is meant to do seems to be up for debate. This
|
/*-
|
||||||
|
* What transpose is meant to do seems to be up for debate. This
|
||||||
* is a general summary of the options; the text is abcd with the
|
* is a general summary of the options; the text is abcd with the
|
||||||
* upper case character or underscore indicating the cursor position:
|
* upper case character or underscore indicating the cursor position:
|
||||||
* Who Before After Before After
|
* Who Before After Before After
|
||||||
@ -2066,8 +2096,9 @@ x_transpose(int c MKSH_A_UNUSED)
|
|||||||
x_e_putc2(7);
|
x_e_putc2(7);
|
||||||
return (KSTD);
|
return (KSTD);
|
||||||
}
|
}
|
||||||
/* Gosling/Unipress emacs style: Swap two characters before the
|
/*
|
||||||
* cursor, do not change cursor position
|
* Gosling/Unipress emacs style: Swap two characters before
|
||||||
|
* the cursor, do not change cursor position
|
||||||
*/
|
*/
|
||||||
x_bs3(&xcp);
|
x_bs3(&xcp);
|
||||||
if (utf_mbtowc(&tmpa, xcp) == (size_t)-1) {
|
if (utf_mbtowc(&tmpa, xcp) == (size_t)-1) {
|
||||||
@ -2084,7 +2115,8 @@ x_transpose(int c MKSH_A_UNUSED)
|
|||||||
utf_wctomb(xcp, tmpb);
|
utf_wctomb(xcp, tmpb);
|
||||||
x_zotc3(&xcp);
|
x_zotc3(&xcp);
|
||||||
} else {
|
} else {
|
||||||
/* GNU emacs style: Swap the characters before and under the
|
/*
|
||||||
|
* GNU emacs style: Swap the characters before and under the
|
||||||
* cursor, move cursor position along one.
|
* cursor, move cursor position along one.
|
||||||
*/
|
*/
|
||||||
if (utf_mbtowc(&tmpa, xcp) == (size_t)-1) {
|
if (utf_mbtowc(&tmpa, xcp) == (size_t)-1) {
|
||||||
@ -2281,7 +2313,8 @@ x_mapin(const char *cp, Area *ap)
|
|||||||
/* XXX -- should handle \^ escape? */
|
/* XXX -- should handle \^ escape? */
|
||||||
if (*cp == '^') {
|
if (*cp == '^') {
|
||||||
cp++;
|
cp++;
|
||||||
if (*cp >= '?') /* includes '?'; ASCII */
|
if (*cp >= '?')
|
||||||
|
/* includes '?'; ASCII */
|
||||||
*op++ = CTRL(*cp);
|
*op++ = CTRL(*cp);
|
||||||
else {
|
else {
|
||||||
*op++ = '^';
|
*op++ = '^';
|
||||||
@ -2345,9 +2378,11 @@ x_print(int prefix, int key)
|
|||||||
int
|
int
|
||||||
x_bind(const char *a1, const char *a2,
|
x_bind(const char *a1, const char *a2,
|
||||||
#ifndef MKSH_SMALL
|
#ifndef MKSH_SMALL
|
||||||
bool macro, /* bind -m */
|
/* bind -m */
|
||||||
|
bool macro,
|
||||||
#endif
|
#endif
|
||||||
bool list) /* bind -l */
|
/* bind -l */
|
||||||
|
bool list)
|
||||||
{
|
{
|
||||||
unsigned char f;
|
unsigned char f;
|
||||||
int prefix, key;
|
int prefix, key;
|
||||||
@ -2605,10 +2640,10 @@ x_expand(int c MKSH_A_UNUSED)
|
|||||||
{
|
{
|
||||||
char **words;
|
char **words;
|
||||||
int start, end, nwords, i;
|
int start, end, nwords, i;
|
||||||
bool is_command;
|
|
||||||
|
|
||||||
nwords = x_cf_glob(XCF_FILE, xbuf, xep - xbuf, xcp - xbuf,
|
i = XCF_FILE;
|
||||||
&start, &end, &words, &is_command);
|
nwords = x_cf_glob(&i, xbuf, xep - xbuf, xcp - xbuf,
|
||||||
|
&start, &end, &words);
|
||||||
|
|
||||||
if (nwords == 0) {
|
if (nwords == 0) {
|
||||||
x_e_putc2(7);
|
x_e_putc2(7);
|
||||||
@ -2616,7 +2651,9 @@ x_expand(int c MKSH_A_UNUSED)
|
|||||||
}
|
}
|
||||||
x_goto(xbuf + start);
|
x_goto(xbuf + start);
|
||||||
x_delete(end - start, false);
|
x_delete(end - start, false);
|
||||||
for (i = 0; i < nwords;) {
|
|
||||||
|
i = 0;
|
||||||
|
while (i < nwords) {
|
||||||
if (x_escape(words[i], strlen(words[i]), x_do_ins) < 0 ||
|
if (x_escape(words[i], strlen(words[i]), x_do_ins) < 0 ||
|
||||||
(++i < nwords && x_ins(" ") < 0)) {
|
(++i < nwords && x_ins(" ") < 0)) {
|
||||||
x_e_putc2(7);
|
x_e_putc2(7);
|
||||||
@ -2628,24 +2665,26 @@ x_expand(int c MKSH_A_UNUSED)
|
|||||||
return (KSTD);
|
return (KSTD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* type == 0 for list, 1 for complete and 2 for complete-list */
|
|
||||||
static void
|
static void
|
||||||
do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
|
do_complete(
|
||||||
|
/* XCF_{COMMAND,FILE,COMMAND_FILE} */
|
||||||
|
int flags,
|
||||||
|
/* 0 for list, 1 for complete and 2 for complete-list */
|
||||||
Comp_type type)
|
Comp_type type)
|
||||||
{
|
{
|
||||||
char **words;
|
char **words;
|
||||||
int start, end, nlen, olen, nwords;
|
int start, end, nlen, olen, nwords;
|
||||||
bool is_command, completed = false;
|
bool completed = false;
|
||||||
|
|
||||||
nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
|
nwords = x_cf_glob(&flags, xbuf, xep - xbuf, xcp - xbuf,
|
||||||
&start, &end, &words, &is_command);
|
&start, &end, &words);
|
||||||
/* no match */
|
/* no match */
|
||||||
if (nwords == 0) {
|
if (nwords == 0) {
|
||||||
x_e_putc2(7);
|
x_e_putc2(7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == CT_LIST) {
|
if (type == CT_LIST) {
|
||||||
x_print_expansions(nwords, words, is_command);
|
x_print_expansions(nwords, words, flags & XCF_IS_COMMAND);
|
||||||
x_redraw(0);
|
x_redraw(0);
|
||||||
x_free_words(nwords, words);
|
x_free_words(nwords, words);
|
||||||
return;
|
return;
|
||||||
@ -2660,13 +2699,14 @@ do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
|
|||||||
x_adjust();
|
x_adjust();
|
||||||
completed = true;
|
completed = true;
|
||||||
}
|
}
|
||||||
/* add space if single non-dir match */
|
/* add space if single non-dir match and not parameter substitution */
|
||||||
if (nwords == 1 && words[0][nlen - 1] != '/') {
|
if (nwords == 1 && words[0][nlen - 1] != '/' &&
|
||||||
|
!(flags & XCF_IS_VARSUB)) {
|
||||||
x_ins(" ");
|
x_ins(" ");
|
||||||
completed = true;
|
completed = true;
|
||||||
}
|
}
|
||||||
if (type == CT_COMPLIST && !completed) {
|
if (type == CT_COMPLIST && !completed) {
|
||||||
x_print_expansions(nwords, words, is_command);
|
x_print_expansions(nwords, words, flags & XCF_IS_COMMAND);
|
||||||
completed = true;
|
completed = true;
|
||||||
}
|
}
|
||||||
if (completed)
|
if (completed)
|
||||||
@ -2675,7 +2715,8 @@ do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
|
|||||||
x_free_words(nwords, words);
|
x_free_words(nwords, words);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NAME:
|
/*-
|
||||||
|
* NAME:
|
||||||
* x_adjust - redraw the line adjusting starting point etc.
|
* x_adjust - redraw the line adjusting starting point etc.
|
||||||
*
|
*
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
@ -2691,7 +2732,8 @@ do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
|
|||||||
static void
|
static void
|
||||||
x_adjust(void)
|
x_adjust(void)
|
||||||
{
|
{
|
||||||
x_adj_done++; /* flag the fact that we were called. */
|
/* flag the fact that we were called. */
|
||||||
|
x_adj_done++;
|
||||||
/*
|
/*
|
||||||
* we had a problem if the prompt length > xx_cols / 2
|
* we had a problem if the prompt length > xx_cols / 2
|
||||||
*/
|
*/
|
||||||
@ -2819,7 +2861,8 @@ x_e_puts(const char *s)
|
|||||||
x_e_putc3(&s);
|
x_e_putc3(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NAME:
|
/*-
|
||||||
|
* NAME:
|
||||||
* x_set_arg - set an arg value for next function
|
* x_set_arg - set an arg value for next function
|
||||||
*
|
*
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
@ -2833,7 +2876,8 @@ x_set_arg(int c)
|
|||||||
{
|
{
|
||||||
int n = 0, first = 1;
|
int n = 0, first = 1;
|
||||||
|
|
||||||
c &= 255; /* strip command prefix */
|
/* strip command prefix */
|
||||||
|
c &= 255;
|
||||||
for (; c >= 0 && ksh_isdigit(c); c = x_e_getc(), first = 0)
|
for (; c >= 0 && ksh_isdigit(c); c = x_e_getc(), first = 0)
|
||||||
n = n * 10 + (c - '0');
|
n = n * 10 + (c - '0');
|
||||||
if (c < 0 || first) {
|
if (c < 0 || first) {
|
||||||
@ -2929,7 +2973,8 @@ x_edit_line(int c MKSH_A_UNUSED)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* NAME:
|
/*-
|
||||||
|
* NAME:
|
||||||
* x_prev_histword - recover word from prev command
|
* x_prev_histword - recover word from prev command
|
||||||
*
|
*
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
@ -3026,7 +3071,8 @@ x_fold_capitalise(int c MKSH_A_UNUSED)
|
|||||||
return (x_fold_case('C'));
|
return (x_fold_case('C'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NAME:
|
/*-
|
||||||
|
* NAME:
|
||||||
* x_fold_case - convert word to UPPER/lower/Capital case
|
* x_fold_case - convert word to UPPER/lower/Capital case
|
||||||
*
|
*
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
@ -3056,9 +3102,11 @@ x_fold_case(int c)
|
|||||||
* a different action than for the rest.
|
* a different action than for the rest.
|
||||||
*/
|
*/
|
||||||
if (cp != xep) {
|
if (cp != xep) {
|
||||||
if (c == 'L') /* lowercase */
|
if (c == 'L')
|
||||||
|
/* lowercase */
|
||||||
*cp = ksh_tolower(*cp);
|
*cp = ksh_tolower(*cp);
|
||||||
else /* uppercase, capitalise */
|
else
|
||||||
|
/* uppercase, capitalise */
|
||||||
*cp = ksh_toupper(*cp);
|
*cp = ksh_toupper(*cp);
|
||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
@ -3066,9 +3114,11 @@ x_fold_case(int c)
|
|||||||
* now for the rest of the word
|
* now for the rest of the word
|
||||||
*/
|
*/
|
||||||
while (cp != xep && !is_mfs(*cp)) {
|
while (cp != xep && !is_mfs(*cp)) {
|
||||||
if (c == 'U') /* uppercase */
|
if (c == 'U')
|
||||||
|
/* uppercase */
|
||||||
*cp = ksh_toupper(*cp);
|
*cp = ksh_toupper(*cp);
|
||||||
else /* lowercase, capitalise */
|
else
|
||||||
|
/* lowercase, capitalise */
|
||||||
*cp = ksh_tolower(*cp);
|
*cp = ksh_tolower(*cp);
|
||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
@ -3079,7 +3129,8 @@ x_fold_case(int c)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* NAME:
|
/*-
|
||||||
|
* NAME:
|
||||||
* x_lastcp - last visible char
|
* x_lastcp - last visible char
|
||||||
*
|
*
|
||||||
* SYNOPSIS:
|
* SYNOPSIS:
|
||||||
@ -3146,10 +3197,10 @@ x_mode(bool onoff)
|
|||||||
cb.c_iflag &= ~(INLCR | ICRNL);
|
cb.c_iflag &= ~(INLCR | ICRNL);
|
||||||
cb.c_lflag &= ~(ISIG | ICANON | ECHO);
|
cb.c_lflag &= ~(ISIG | ICANON | ECHO);
|
||||||
#if defined(VLNEXT) && defined(_POSIX_VDISABLE)
|
#if defined(VLNEXT) && defined(_POSIX_VDISABLE)
|
||||||
/* osf/1 processes lnext when ~icanon */
|
/* OSF/1 processes lnext when ~icanon */
|
||||||
cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
|
cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
|
||||||
#endif
|
#endif
|
||||||
/* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */
|
/* SunOS 4.1.x & OSF/1 processes discard(flush) when ~icanon */
|
||||||
#if defined(VDISCARD) && defined(_POSIX_VDISABLE)
|
#if defined(VDISCARD) && defined(_POSIX_VDISABLE)
|
||||||
cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
|
cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
|
||||||
#endif
|
#endif
|
||||||
@ -3345,7 +3396,8 @@ static int ohnum; /* history line copied (after mod) */
|
|||||||
static int hlast; /* 1 past last position in history */
|
static int hlast; /* 1 past last position in history */
|
||||||
static int state;
|
static int state;
|
||||||
|
|
||||||
/* Information for keeping track of macros that are being expanded.
|
/*
|
||||||
|
* Information for keeping track of macros that are being expanded.
|
||||||
* The format of buf is the alias contents followed by a NUL byte followed
|
* The format of buf is the alias contents followed by a NUL byte followed
|
||||||
* by the name (letter) of the alias. The end of the buffer is marked by
|
* by the name (letter) of the alias. The end of the buffer is marked by
|
||||||
* a double NUL. The name of the alias is stored so recursive macros can
|
* a double NUL. The name of the alias is stored so recursive macros can
|
||||||
@ -3809,7 +3861,8 @@ vi_insert(int ch)
|
|||||||
expanded = NONE;
|
expanded = NONE;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
/* If any chars are entered before escape, trash the saved insert
|
/*
|
||||||
|
* If any chars are entered before escape, trash the saved insert
|
||||||
* buffer (if user inserts & deletes char, ibuf gets trashed and
|
* buffer (if user inserts & deletes char, ibuf gets trashed and
|
||||||
* we don't want to use it)
|
* we don't want to use it)
|
||||||
*/
|
*/
|
||||||
@ -4332,29 +4385,37 @@ vi_cmd(int argcnt, const char *cmd)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
case '=': /* AT&T ksh */
|
/* AT&T ksh */
|
||||||
case Ctrl('e'): /* Nonstandard vi/ksh */
|
case '=':
|
||||||
|
/* Nonstandard vi/ksh */
|
||||||
|
case Ctrl('e'):
|
||||||
print_expansions(es, 1);
|
print_expansions(es, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case Ctrl('i'): /* Nonstandard vi/ksh */
|
/* Nonstandard vi/ksh */
|
||||||
|
case Ctrl('i'):
|
||||||
if (!Flag(FVITABCOMPLETE))
|
if (!Flag(FVITABCOMPLETE))
|
||||||
return (-1);
|
return (-1);
|
||||||
complete_word(1, argcnt);
|
complete_word(1, argcnt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Ctrl('['): /* some annoying AT&T kshs */
|
/* some annoying AT&T kshs */
|
||||||
|
case Ctrl('['):
|
||||||
if (!Flag(FVIESCCOMPLETE))
|
if (!Flag(FVIESCCOMPLETE))
|
||||||
return (-1);
|
return (-1);
|
||||||
case '\\': /* AT&T ksh */
|
/* AT&T ksh */
|
||||||
case Ctrl('f'): /* Nonstandard vi/ksh */
|
case '\\':
|
||||||
|
/* Nonstandard vi/ksh */
|
||||||
|
case Ctrl('f'):
|
||||||
complete_word(1, argcnt);
|
complete_word(1, argcnt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case '*': /* AT&T ksh */
|
/* AT&T ksh */
|
||||||
case Ctrl('x'): /* Nonstandard vi/ksh */
|
case '*':
|
||||||
|
/* Nonstandard vi/ksh */
|
||||||
|
case Ctrl('x'):
|
||||||
expand_word(1);
|
expand_word(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5005,7 +5066,8 @@ display(char *wb1, char *wb2, int leftside)
|
|||||||
col++;
|
col++;
|
||||||
}
|
}
|
||||||
if (es->winleft > 0 && moreright)
|
if (es->winleft > 0 && moreright)
|
||||||
/* POSIX says to use * for this but that is a globbing
|
/*
|
||||||
|
* POSIX says to use * for this but that is a globbing
|
||||||
* character and may confuse people; + is more innocuous
|
* character and may confuse people; + is more innocuous
|
||||||
*/
|
*/
|
||||||
mc = '+';
|
mc = '+';
|
||||||
@ -5054,11 +5116,8 @@ static int
|
|||||||
expand_word(int cmd)
|
expand_word(int cmd)
|
||||||
{
|
{
|
||||||
static struct edstate *buf;
|
static struct edstate *buf;
|
||||||
int rval = 0;
|
int rval = 0, nwords, start, end, i;
|
||||||
int nwords;
|
|
||||||
int start, end;
|
|
||||||
char **words;
|
char **words;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Undo previous expansion */
|
/* Undo previous expansion */
|
||||||
if (cmd == 0 && expanded == EXPAND && buf) {
|
if (cmd == 0 && expanded == EXPAND && buf) {
|
||||||
@ -5072,9 +5131,9 @@ expand_word(int cmd)
|
|||||||
buf = 0;
|
buf = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH,
|
i = XCF_COMMAND_FILE | XCF_FULLPATH;
|
||||||
es->cbuf, es->linelen, es->cursor,
|
nwords = x_cf_glob(&i, es->cbuf, es->linelen, es->cursor,
|
||||||
&start, &end, &words, NULL);
|
&start, &end, &words);
|
||||||
if (nwords == 0) {
|
if (nwords == 0) {
|
||||||
vi_error();
|
vi_error();
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -5084,7 +5143,8 @@ expand_word(int cmd)
|
|||||||
expanded = EXPAND;
|
expanded = EXPAND;
|
||||||
del_range(start, end);
|
del_range(start, end);
|
||||||
es->cursor = start;
|
es->cursor = start;
|
||||||
for (i = 0; i < nwords; ) {
|
i = 0;
|
||||||
|
while (i < nwords) {
|
||||||
if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
|
if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
|
||||||
rval = -1;
|
rval = -1;
|
||||||
break;
|
break;
|
||||||
@ -5109,10 +5169,10 @@ static int
|
|||||||
complete_word(int cmd, int count)
|
complete_word(int cmd, int count)
|
||||||
{
|
{
|
||||||
static struct edstate *buf;
|
static struct edstate *buf;
|
||||||
int rval, nwords, start, end, match_len;
|
int rval, nwords, start, end, match_len, flags;
|
||||||
char **words;
|
char **words;
|
||||||
char *match;
|
char *match;
|
||||||
bool is_command, is_unique;
|
bool is_unique;
|
||||||
|
|
||||||
/* Undo previous completion */
|
/* Undo previous completion */
|
||||||
if (cmd == 0 && expanded == COMPLETE && buf) {
|
if (cmd == 0 && expanded == COMPLETE && buf) {
|
||||||
@ -5131,12 +5191,15 @@ complete_word(int cmd, int count)
|
|||||||
buf = 0;
|
buf = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XCF_FULLPATH for count 'cause the menu printed by print_expansions()
|
/*
|
||||||
* was done this way.
|
* XCF_FULLPATH for count 'cause the menu printed by
|
||||||
|
* print_expansions() was done this way.
|
||||||
*/
|
*/
|
||||||
nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0),
|
flags = XCF_COMMAND_FILE;
|
||||||
es->cbuf, es->linelen, es->cursor,
|
if (count)
|
||||||
&start, &end, &words, &is_command);
|
flags |= XCF_FULLPATH;
|
||||||
|
nwords = x_cf_glob(&flags, es->cbuf, es->linelen, es->cursor,
|
||||||
|
&start, &end, &words);
|
||||||
if (nwords == 0) {
|
if (nwords == 0) {
|
||||||
vi_error();
|
vi_error();
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -5147,7 +5210,8 @@ complete_word(int cmd, int count)
|
|||||||
count--;
|
count--;
|
||||||
if (count >= nwords) {
|
if (count >= nwords) {
|
||||||
vi_error();
|
vi_error();
|
||||||
x_print_expansions(nwords, words, is_command);
|
x_print_expansions(nwords, words,
|
||||||
|
flags & XCF_IS_COMMAND);
|
||||||
x_free_words(nwords, words);
|
x_free_words(nwords, words);
|
||||||
redraw_line(0);
|
redraw_line(0);
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -5155,7 +5219,7 @@ complete_word(int cmd, int count)
|
|||||||
/*
|
/*
|
||||||
* Expand the count'th word to its basename
|
* Expand the count'th word to its basename
|
||||||
*/
|
*/
|
||||||
if (is_command) {
|
if (flags & XCF_IS_COMMAND) {
|
||||||
match = words[count] +
|
match = words[count] +
|
||||||
x_basename(words[count], NULL);
|
x_basename(words[count], NULL);
|
||||||
/* If more than one possible match, use full path */
|
/* If more than one possible match, use full path */
|
||||||
@ -5174,7 +5238,8 @@ complete_word(int cmd, int count)
|
|||||||
} else {
|
} else {
|
||||||
match = words[0];
|
match = words[0];
|
||||||
match_len = x_longest_prefix(nwords, words);
|
match_len = x_longest_prefix(nwords, words);
|
||||||
expanded = COMPLETE; /* next call will list completions */
|
/* next call will list completions */
|
||||||
|
expanded = COMPLETE;
|
||||||
is_unique = nwords == 1;
|
is_unique = nwords == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5182,18 +5247,25 @@ complete_word(int cmd, int count)
|
|||||||
del_range(start, end);
|
del_range(start, end);
|
||||||
es->cursor = start;
|
es->cursor = start;
|
||||||
|
|
||||||
/* escape all shell-sensitive characters and put the result into
|
/*
|
||||||
* command buffer */
|
* escape all shell-sensitive characters and put the result into
|
||||||
|
* command buffer
|
||||||
|
*/
|
||||||
rval = x_escape(match, match_len, x_vi_putbuf);
|
rval = x_escape(match, match_len, x_vi_putbuf);
|
||||||
|
|
||||||
if (rval == 0 && is_unique) {
|
if (rval == 0 && is_unique) {
|
||||||
/* If exact match, don't undo. Allows directory completions
|
/*
|
||||||
|
* If exact match, don't undo. Allows directory completions
|
||||||
* to be used (ie, complete the next portion of the path).
|
* to be used (ie, complete the next portion of the path).
|
||||||
*/
|
*/
|
||||||
expanded = NONE;
|
expanded = NONE;
|
||||||
|
|
||||||
/* If not a directory, add a space to the end... */
|
/*
|
||||||
if (match_len > 0 && match[match_len - 1] != '/')
|
* append a space if this is not a directory or the
|
||||||
|
* result of a parameter substitution
|
||||||
|
*/
|
||||||
|
if (match_len > 0 && match[match_len - 1] != '/' &&
|
||||||
|
!(flags & XCF_IS_VARSUB))
|
||||||
rval = putbuf(" ", 1, 0);
|
rval = putbuf(" ", 1, 0);
|
||||||
}
|
}
|
||||||
x_free_words(nwords, words);
|
x_free_words(nwords, words);
|
||||||
@ -5201,7 +5273,8 @@ complete_word(int cmd, int count)
|
|||||||
modified = 1;
|
modified = 1;
|
||||||
hnum = hlast;
|
hnum = hlast;
|
||||||
insert = INSERT;
|
insert = INSERT;
|
||||||
lastac = 0; /* prevent this from being redone... */
|
/* prevent this from being redone... */
|
||||||
|
lastac = 0;
|
||||||
refresh(0);
|
refresh(0);
|
||||||
|
|
||||||
return (rval);
|
return (rval);
|
||||||
@ -5210,18 +5283,17 @@ complete_word(int cmd, int count)
|
|||||||
static int
|
static int
|
||||||
print_expansions(struct edstate *est, int cmd MKSH_A_UNUSED)
|
print_expansions(struct edstate *est, int cmd MKSH_A_UNUSED)
|
||||||
{
|
{
|
||||||
int start, end, nwords;
|
int start, end, nwords, i;
|
||||||
char **words;
|
char **words;
|
||||||
bool is_command;
|
|
||||||
|
|
||||||
nwords = x_cf_glob(XCF_COMMAND_FILE | XCF_FULLPATH,
|
i = XCF_COMMAND_FILE | XCF_FULLPATH;
|
||||||
est->cbuf, est->linelen, est->cursor,
|
nwords = x_cf_glob(&i, est->cbuf, est->linelen, est->cursor,
|
||||||
&start, &end, &words, &is_command);
|
&start, &end, &words);
|
||||||
if (nwords == 0) {
|
if (nwords == 0) {
|
||||||
vi_error();
|
vi_error();
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
x_print_expansions(nwords, words, is_command);
|
x_print_expansions(nwords, words, i & XCF_IS_COMMAND);
|
||||||
x_free_words(nwords, words);
|
x_free_words(nwords, words);
|
||||||
redraw_line(0);
|
redraw_line(0);
|
||||||
return (0);
|
return (0);
|
||||||
|
4
sh.h
4
sh.h
@ -154,9 +154,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#ifdef EXTERN
|
||||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.426 2011/01/30 01:36:00 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.427 2011/02/03 15:57:52 tg Exp $");
|
||||||
#endif
|
#endif
|
||||||
#define MKSH_VERSION "R39 2011/01/29"
|
#define MKSH_VERSION "R39 2011/02/03"
|
||||||
|
|
||||||
#ifndef MKSH_INCLUDES_ONLY
|
#ifndef MKSH_INCLUDES_ONLY
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user