summaryrefslogtreecommitdiff
path: root/builtins
diff options
context:
space:
mode:
Diffstat (limited to 'builtins')
-rw-r--r--builtins/command.def4
-rw-r--r--builtins/common.h1
-rw-r--r--builtins/complete.def220
-rw-r--r--builtins/declare.def6
-rw-r--r--builtins/evalstring.c22
-rw-r--r--builtins/fc.def82
-rw-r--r--builtins/hash.def3
-rw-r--r--builtins/set.def18
-rw-r--r--builtins/setattr.def2
9 files changed, 198 insertions, 160 deletions
diff --git a/builtins/command.def b/builtins/command.def
index cea55b8e..acd46cc1 100644
--- a/builtins/command.def
+++ b/builtins/command.def
@@ -124,6 +124,10 @@ command_builtin (list)
#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0))
+#ifdef DEBUG
+ itrace("command_builtin: running execute_command for `%s'", list->word->word);
+#endif
+
/* We don't want this to be reparsed (consider command echo 'foo &'), so
just make a simple_command structure and call execute_command with it. */
command = make_bare_simple_command ();
diff --git a/builtins/common.h b/builtins/common.h
index 0aecc9ce..a4f9275d 100644
--- a/builtins/common.h
+++ b/builtins/common.h
@@ -210,6 +210,7 @@ extern int should_suppress_fork PARAMS((COMMAND *));
extern int can_optimize_connection PARAMS((COMMAND *));
extern void optimize_fork PARAMS((COMMAND *));
extern void optimize_subshell_command PARAMS((COMMAND *));
+extern void optimize_shell_function PARAMS((COMMAND *));
/* Functions from evalfile.c */
extern int maybe_execute_file PARAMS((const char *, int));
diff --git a/builtins/complete.def b/builtins/complete.def
index f33328e8..28a9ec2f 100644
--- a/builtins/complete.def
+++ b/builtins/complete.def
@@ -42,7 +42,7 @@ Options:
command) word
When completion is attempted, the actions are applied in the order the
-uppercase-letter options are listed above. If multiple options are supplied,
+uppercase-letter options are listed above. If multiple options are supplied,
the -D option takes precedence over -E, and both take precedence over -I.
Exit Status:
@@ -97,11 +97,16 @@ static void print_compopts PARAMS((const char *, COMPSPEC *, int));
static void print_all_completions PARAMS((void));
static int print_cmd_completions PARAMS((WORD_LIST *));
+static void print_compoptions PARAMS((unsigned long, int));
+static void print_compactions PARAMS((unsigned long));
+static void print_arg PARAMS((const char *, const char *, int));
+static void print_cmd_name PARAMS((const char *));
+
static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg;
static const struct _compacts {
const char * const actname;
- int actflag;
+ unsigned long actflag;
int actopt;
} compacts[] = {
{ "alias", CA_ALIAS, 'a' },
@@ -134,7 +139,7 @@ static const struct _compacts {
/* This should be a STRING_INT_ALIST */
static const struct _compopt {
const char * const optname;
- int optflag;
+ unsigned long optflag;
} compopts[] = {
{ "bashdefault", COPT_BASHDEFAULT },
{ "default", COPT_DEFAULT },
@@ -485,122 +490,95 @@ remove_cmd_completions (list)
return ret;
}
-#define SQPRINTARG(a, f) \
- do { \
- if (a) \
- { \
- x = sh_single_quote (a); \
- printf ("%s %s ", f, x); \
- free (x); \
- } \
- } while (0)
-
-#define PRINTARG(a, f) \
- do { \
- if (a) \
- printf ("%s %s ", f, a); \
- } while (0)
-
-#define PRINTOPT(a, f) \
- do { \
- if (acts & a) \
- printf ("%s ", f); \
- } while (0)
-
-#define PRINTACT(a, f) \
- do { \
- if (acts & a) \
- printf ("-A %s ", f); \
- } while (0)
-
-#define PRINTCOMPOPT(a, f) \
- do { \
- if (copts & a) \
- printf ("-o %s ", f); \
- } while (0)
-
-#define XPRINTCOMPOPT(a, f) \
- do { \
- if (copts & a) \
- printf ("-o %s ", f); \
- else \
- printf ("+o %s ", f); \
- } while (0)
+static void
+print_compoptions (copts, full)
+ unsigned long copts;
+ int full;
+{
+ const struct _compopt *co;
+
+ for (co = compopts; co->optname; co++)
+ if (copts & co->optflag)
+ printf ("-o %s ", co->optname);
+ else if (full)
+ printf ("+o %s ", co->optname);
+}
+
+static void
+print_compactions (acts)
+ unsigned long acts;
+{
+ const struct _compacts *ca;
+
+ /* simple flags first */
+ for (ca = compacts; ca->actname; ca++)
+ if (ca->actopt && (acts & ca->actflag))
+ printf ("-%c ", ca->actopt);
+
+ /* then the rest of the actions */
+ for (ca = compacts; ca->actname; ca++)
+ if (ca->actopt == 0 && (acts & ca->actflag))
+ printf ("-A %s ", ca->actname);
+}
+
+static void
+print_arg (arg, flag, quote)
+ const char *arg, *flag;
+ int quote;
+{
+ char *x;
+
+ if (arg)
+ {
+ x = quote ? sh_single_quote (arg) : (char *)arg;
+ printf ("%s %s ", flag, x);
+ if (x != arg)
+ free (x);
+ }
+}
+
+static void
+print_cmd_name (cmd)
+ const char *cmd;
+{
+ if (STREQ (cmd, DEFAULTCMD))
+ printf ("-D");
+ else if (STREQ (cmd, EMPTYCMD))
+ printf ("-E");
+ else if (STREQ (cmd, INITIALWORD))
+ printf ("-I");
+ else if (*cmd == 0) /* XXX - can this happen? */
+ printf ("''");
+ else
+ printf ("%s", cmd);
+}
static int
print_one_completion (cmd, cs)
char *cmd;
COMPSPEC *cs;
{
- unsigned long acts, copts;
- char *x;
-
printf ("complete ");
- copts = cs->options;
-
- /* First, print the -o options. */
- PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
- PRINTCOMPOPT (COPT_DEFAULT, "default");
- PRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
- PRINTCOMPOPT (COPT_FILENAMES, "filenames");
- PRINTCOMPOPT (COPT_NOQUOTE, "noquote");
- PRINTCOMPOPT (COPT_NOSORT, "nosort");
- PRINTCOMPOPT (COPT_NOSPACE, "nospace");
- PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
-
- acts = cs->actions;
-
- /* simple flags next */
- PRINTOPT (CA_ALIAS, "-a");
- PRINTOPT (CA_BUILTIN, "-b");
- PRINTOPT (CA_COMMAND, "-c");
- PRINTOPT (CA_DIRECTORY, "-d");
- PRINTOPT (CA_EXPORT, "-e");
- PRINTOPT (CA_FILE, "-f");
- PRINTOPT (CA_GROUP, "-g");
- PRINTOPT (CA_JOB, "-j");
- PRINTOPT (CA_KEYWORD, "-k");
- PRINTOPT (CA_SERVICE, "-s");
- PRINTOPT (CA_USER, "-u");
- PRINTOPT (CA_VARIABLE, "-v");
-
- /* now the rest of the actions */
- PRINTACT (CA_ARRAYVAR, "arrayvar");
- PRINTACT (CA_BINDING, "binding");
- PRINTACT (CA_DISABLED, "disabled");
- PRINTACT (CA_ENABLED, "enabled");
- PRINTACT (CA_FUNCTION, "function");
- PRINTACT (CA_HELPTOPIC, "helptopic");
- PRINTACT (CA_HOSTNAME, "hostname");
- PRINTACT (CA_RUNNING, "running");
- PRINTACT (CA_SETOPT, "setopt");
- PRINTACT (CA_SHOPT, "shopt");
- PRINTACT (CA_SIGNAL, "signal");
- PRINTACT (CA_STOPPED, "stopped");
+ print_compoptions (cs->options, 0);
+ print_compactions (cs->actions);
/* now the rest of the arguments */
/* arguments that require quoting */
- SQPRINTARG (cs->globpat, "-G");
- SQPRINTARG (cs->words, "-W");
- SQPRINTARG (cs->prefix, "-P");
- SQPRINTARG (cs->suffix, "-S");
- SQPRINTARG (cs->filterpat, "-X");
+ print_arg (cs->globpat, "-G", 1);
+ print_arg (cs->words, "-W", 1);
+ print_arg (cs->prefix, "-P", 1);
+ print_arg (cs->suffix, "-S", 1);
+ print_arg (cs->filterpat, "-X", 1);
- SQPRINTARG (cs->command, "-C");
+ print_arg (cs->command, "-C", 1);
/* simple arguments that don't require quoting */
- PRINTARG (cs->funcname, "-F");
+ print_arg (cs->funcname, "-F", 0);
- if (STREQ (cmd, DEFAULTCMD))
- printf ("-D\n");
- else if (STREQ (cmd, EMPTYCMD))
- printf ("-E\n");
- else if (STREQ (cmd, INITIALWORD))
- printf ("-I\n");
- else
- printf ("%s\n", cmd);
+ print_cmd_name (cmd);
+ printf ("\n");
return (0);
}
@@ -611,42 +589,12 @@ print_compopts (cmd, cs, full)
COMPSPEC *cs;
int full;
{
- int copts;
-
printf ("compopt ");
- copts = cs->options;
- if (full)
- {
- XPRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
- XPRINTCOMPOPT (COPT_DEFAULT, "default");
- XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
- XPRINTCOMPOPT (COPT_FILENAMES, "filenames");
- XPRINTCOMPOPT (COPT_NOQUOTE, "noquote");
- XPRINTCOMPOPT (COPT_NOSORT, "nosort");
- XPRINTCOMPOPT (COPT_NOSPACE, "nospace");
- XPRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
- }
- else
- {
- PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
- PRINTCOMPOPT (COPT_DEFAULT, "default");
- PRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
- PRINTCOMPOPT (COPT_FILENAMES, "filenames");
- PRINTCOMPOPT (COPT_NOQUOTE, "noquote");
- PRINTCOMPOPT (COPT_NOSORT, "nosort");
- PRINTCOMPOPT (COPT_NOSPACE, "nospace");
- PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
- }
+ print_compoptions (cs->options, full);
+ print_cmd_name (cmd);
- if (STREQ (cmd, DEFAULTCMD))
- printf ("-D\n");
- else if (STREQ (cmd, EMPTYCMD))
- printf ("-E\n");
- else if (STREQ (cmd, INITIALWORD))
- printf ("-I\n");
- else
- printf ("%s\n", cmd);
+ printf ("\n");
}
static int
diff --git a/builtins/declare.def b/builtins/declare.def
index 98878243..21e4516d 100644
--- a/builtins/declare.def
+++ b/builtins/declare.def
@@ -727,20 +727,20 @@ restart_new_var_name:
if (flags_on & att_assoc)
{
var = make_new_assoc_variable (name);
- if (var && offset == 0 && no_invisible_vars == 0)
+ if (var && offset == 0)
VSETATTR (var, att_invisible);
}
else if ((flags_on & att_array) || making_array_special)
{
var = make_new_array_variable (name);
- if (var && offset == 0 && no_invisible_vars == 0)
+ if (var && offset == 0)
VSETATTR (var, att_invisible);
}
else
#endif
{
var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
- if (var && offset == 0 && no_invisible_vars == 0)
+ if (var && offset == 0)
VSETATTR (var, att_invisible);
}
if (var == 0)
diff --git a/builtins/evalstring.c b/builtins/evalstring.c
index 4240277e..3a6801dd 100644
--- a/builtins/evalstring.c
+++ b/builtins/evalstring.c
@@ -145,7 +145,27 @@ optimize_subshell_command (command)
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR))
optimize_subshell_command (command->value.Connection->second);
}
-
+
+void
+optimize_shell_function (command)
+ COMMAND *command;
+{
+ COMMAND *fc;
+
+ fc = (command->type == cm_group) ? command->value.Group->command : command;
+
+ if (fc->type == cm_simple && should_suppress_fork (fc))
+ {
+ fc->flags |= CMD_NO_FORK;
+ fc->value.Simple->flags |= CMD_NO_FORK;
+ }
+ else if (fc->type == cm_connection && can_optimize_connection (fc) && should_suppress_fork (fc->value.Connection->second))
+ {
+ fc->value.Connection->second->flags |= CMD_NO_FORK;
+ fc->value.Connection->second->value.Simple->flags |= CMD_NO_FORK;
+ }
+}
+
/* How to force parse_and_execute () to clean up after itself. */
void
parse_and_execute_cleanup (old_running_trap)
diff --git a/builtins/fc.def b/builtins/fc.def
index c266ac2c..467dbcbc 100644
--- a/builtins/fc.def
+++ b/builtins/fc.def
@@ -86,6 +86,14 @@ $END
extern int errno;
#endif /* !errno */
+#define HIST_INVALID INT_MIN
+#define HIST_ERANGE INT_MIN+1
+#define HIST_NOTFOUND INT_MIN+2
+
+/* Values for the flags argument to fc_gethnum */
+#define HN_LISTING 0x01
+#define HN_FIRST 0x02
+
extern int unlink PARAMS((const char *));
extern FILE *sh_mktmpfp PARAMS((char *, int, char **));
@@ -201,7 +209,7 @@ fc_builtin (list)
break;
case 'l':
- listing = 1;
+ listing = HN_LISTING; /* for fc_gethnum */
break;
case 'r':
@@ -321,14 +329,11 @@ fc_builtin (list)
while (last_hist >= 0 && hlist[last_hist] == 0)
last_hist--;
if (last_hist < 0)
- {
- sh_erange ((char *)NULL, _("history specification"));
- return (EXECUTION_FAILURE);
- }
+ last_hist = 0; /* per POSIX */
if (list)
{
- histbeg = fc_gethnum (list->word->word, hlist, listing);
+ histbeg = fc_gethnum (list->word->word, hlist, listing|HN_FIRST);
list = list->next;
if (list)
@@ -353,12 +358,27 @@ fc_builtin (list)
histbeg = histend = last_hist;
}
- /* We print error messages for line specifications out of range. */
- if ((histbeg < 0) || (histend < 0))
+ if (histbeg == HIST_INVALID || histend == HIST_INVALID)
+ {
+ sh_erange ((char *)NULL, _("history specification"));
+ return (EXECUTION_FAILURE);
+ }
+ else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
+ else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
+ {
+ builtin_error (_("no command found"));
+ return (EXECUTION_FAILURE);
+ }
+
+ /* We don't throw an error for line specifications out of range, per POSIX */
+ if (histbeg < 0)
+ histbeg = 0;
+ if (histend < 0)
+ histend = 0;
/* "When not listing, the fc command that caused the editing shall not be
entered into the history list." */
@@ -382,12 +402,27 @@ fc_builtin (list)
histbeg = last_hist;
}
- /* We print error messages for line specifications out of range. */
- if ((histbeg < 0) || (histend < 0))
+ if (histbeg == HIST_INVALID || histend == HIST_INVALID)
+ {
+ sh_erange ((char *)NULL, _("history specification"));
+ return (EXECUTION_FAILURE);
+ }
+ else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
+ else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
+ {
+ builtin_error (_("no command found"));
+ return (EXECUTION_FAILURE);
+ }
+
+ /* We don't throw an error for line specifications out of range, per POSIX */
+ if (histbeg < 0)
+ histbeg = 0;
+ if (histend < 0)
+ histend = 0;
if (histend < histbeg)
{
@@ -507,7 +542,9 @@ fc_number (list)
/* Return an absolute index into HLIST which corresponds to COMMAND. If
COMMAND is a number, then it was specified in relative terms. If it
is a string, then it is the start of a command line present in HLIST.
- MODE is 1 if we are listing commands, 0 if we are executing them. */
+ MODE includes HN_LISTING if we are listing commands, and does not if we
+ are executing them. If MODE includes HN_FIRST we are looking for the
+ first history number specification. */
static int
fc_gethnum (command, hlist, mode)
char *command;
@@ -515,9 +552,10 @@ fc_gethnum (command, hlist, mode)
int mode;
{
int sign, n, clen, rh;
- register int i, j, last_hist, real_last;
+ register int i, j, last_hist, real_last, listing;
register char *s;
+ listing = mode & HN_LISTING;
sign = 1;
/* Count history elements. */
for (i = 0; hlist[i]; i++);
@@ -570,19 +608,33 @@ fc_gethnum (command, hlist, mode)
n = atoi (s);
n *= sign;
+ /* We want to return something that is an offset to HISTORY_BASE. */
+
/* If the value is negative or zero, then it is an offset from
the current history item. */
+ /* We don't use HN_FIRST here, so we don't return different values
+ depending on whether we're looking for the first or last in a
+ pair of range arguments, but nobody else does, either. */
if (n < 0)
{
n += i + 1;
return (n < 0 ? 0 : n);
}
else if (n == 0)
- return ((sign == -1) ? (mode ? real_last : -1) : i);
+ return ((sign == -1) ? (listing ? real_last : HIST_INVALID) : i);
else
{
+ /* If we're out of range (greater than I (last history entry) or
+ less than HISTORY_BASE, we want to return different values
+ based on whether or not we are looking for the first or last
+ value in a desired range of history entries. */
n -= history_base;
- return (i < n ? i : n);
+ if (n < 0)
+ return (mode & HN_FIRST ? 0 : i);
+ else if (n >= i)
+ return (mode & HN_FIRST ? 0 : i);
+ else
+ return n;
}
}
@@ -592,7 +644,7 @@ fc_gethnum (command, hlist, mode)
if (STREQN (command, histline (j), clen))
return (j);
}
- return (-1);
+ return (HIST_NOTFOUND);
}
/* Locate the most recent history line which begins with
diff --git a/builtins/hash.def b/builtins/hash.def
index 8eddc999..c58e91c4 100644
--- a/builtins/hash.def
+++ b/builtins/hash.def
@@ -134,7 +134,8 @@ hash_builtin (list)
if (list == 0 && expunge_hash_table == 0)
{
opt = print_hashed_commands (list_portably);
- if (opt == 0 && posixly_correct == 0)
+ if (opt == 0 && posixly_correct == 0 &&
+ (list_portably == 0 || shell_compatibility_level <= 50))
printf (_("%s: hash table empty\n"), this_command_name);
return (EXECUTION_SUCCESS);
diff --git a/builtins/set.def b/builtins/set.def
index 48927679..8ee01657 100644
--- a/builtins/set.def
+++ b/builtins/set.def
@@ -358,17 +358,29 @@ void
set_current_options (bitmap)
const char *bitmap;
{
- int i;
+ int i, v, cv, *on_or_off;
if (bitmap == 0)
return;
for (i = 0; o_options[i].name; i++)
{
+ v = bitmap[i] ? FLAG_ON : FLAG_OFF;
if (o_options[i].letter)
- change_flag (o_options[i].letter, bitmap[i] ? FLAG_ON : FLAG_OFF);
+ {
+ /* We should not get FLAG_UNKNOWN here */
+ on_or_off = find_flag (o_options[i].letter);
+ cv = *on_or_off ? FLAG_ON : FLAG_OFF;
+ if (v != cv)
+ change_flag (o_options[i].letter, v);
+ }
else
- SET_BINARY_O_OPTION_VALUE (i, bitmap[i] ? FLAG_ON : FLAG_OFF, o_options[i].name);
+ {
+ cv = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
+ cv = cv ? FLAG_ON : FLAG_OFF;
+ if (v != cv)
+ SET_BINARY_O_OPTION_VALUE (i, v, o_options[i].name);
+ }
}
/* Now reset the variables changed by posix mode */
diff --git a/builtins/setattr.def b/builtins/setattr.def
index e43f7091..a193462d 100644
--- a/builtins/setattr.def
+++ b/builtins/setattr.def
@@ -645,7 +645,7 @@ set_var_attribute (name, attribute, undo)
if (var == 0)
{
var = bind_variable (name, (char *)NULL, 0);
- if (var && no_invisible_vars == 0)
+ if (var)
VSETATTR (var, att_invisible);
}
else if (var->context != 0)