Sync with HEAD's code:

- Support for command -v and -V.
- Fixes for the errexit option.
- A fix for a crash caused by SIGINT.
- POSIX compliant set +o ouput.
- A fix for unalias' exit code.
- Man page updates.
- Code cleanups, WARNS 3.
This commit is contained in:
stefanf 2005-11-06 20:39:48 +00:00
parent 80d777c8ec
commit 58babfa98f
25 changed files with 258 additions and 117 deletions

View File

@ -22,7 +22,7 @@ LFLAGS= -8 # 8-bit lex scanner for arithmetic
CFLAGS+=-DSHELL -I. -I${.CURDIR}
# for debug:
# CFLAGS+= -g -DDEBUG=2
WARNS?= 0
WARNS?= 3
WFORMAT=0
.PATH: ${.CURDIR}/bltin \

View File

@ -144,7 +144,7 @@ unalias(char *name)
}
#ifdef mkinit
MKINIT void rmaliases();
MKINIT void rmaliases(void);
SHELLPROC {
rmaliases();
@ -242,7 +242,7 @@ unaliascmd(int argc __unused, char **argv __unused)
}
}
for (i = 0; *argptr; argptr++)
i = unalias(*argptr);
i |= unalias(*argptr);
return (i);
}

View File

@ -30,6 +30,8 @@
* $FreeBSD$
*/
extern char *arith_buf, *arith_startbuf;
int arith(char *);
int arith_assign(char *, arith_t);
void arith_lex_reset(void);
int expcmd(int, char **);

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <stdio.h>
#include "arith.h"
#include "shell.h"
#include "var.h"
%}
@ -261,12 +262,11 @@ expr:
#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
char *arith_buf, *arith_startbuf;
extern void arith_lex_reset();
int yylex(void);
int yyparse(void);
int
static int
arith_assign(char *name, arith_t value)
{
char *str;
@ -294,7 +294,7 @@ arith(char *s)
return result;
}
void
static void
yyerror(char *s)
{

View File

@ -42,13 +42,15 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include "arith.h"
#include "shell.h"
#include "y.tab.h"
#include "error.h"
#include "memalloc.h"
#include "var.h"
extern char *arith_buf, *arith_startbuf;
int yylex(void);
#undef YY_INPUT
#define YY_INPUT(buf,result,max) \
result = (*buf = *arith_buf++) ? 1 : YY_NULL;

View File

@ -82,5 +82,7 @@
pointer stalloc(int);
void error(const char *, ...) __printf0like(1, 2);
int echocmd(int, char **);
int testcmd(int, char **);
extern char *commandname;

View File

@ -90,8 +90,8 @@ int exitstatus; /* exit status of last command */
int oexitstatus; /* saved exit status */
STATIC void evalloop(union node *);
STATIC void evalfor(union node *);
STATIC void evalloop(union node *, int);
STATIC void evalfor(union node *, int);
STATIC void evalcase(union node *, int);
STATIC void evalsubshell(union node *, int);
STATIC void expredir(union node *);
@ -182,6 +182,9 @@ evalstring(char *s)
void
evaltree(union node *n, int flags)
{
int do_etest;
do_etest = 0;
if (n == NULL) {
TRACE(("evaltree(NULL) called\n"));
exitstatus = 0;
@ -190,10 +193,10 @@ evaltree(union node *n, int flags)
#ifndef NO_HISTORY
displayhist = 1; /* show history substitutions done with fc */
#endif
TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
switch (n->type) {
case NSEMI:
evaltree(n->nbinary.ch1, 0);
evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
if (evalskip)
goto out;
evaltree(n->nbinary.ch2, flags);
@ -219,6 +222,7 @@ evaltree(union node *n, int flags)
break;
case NSUBSHELL:
evalsubshell(n, flags);
do_etest = !(flags & EV_TESTED);
break;
case NBACKGND:
evalsubshell(n, flags);
@ -237,10 +241,10 @@ evaltree(union node *n, int flags)
}
case NWHILE:
case NUNTIL:
evalloop(n);
evalloop(n, flags & ~EV_EXIT);
break;
case NFOR:
evalfor(n);
evalfor(n, flags & ~EV_EXIT);
break;
case NCASE:
evalcase(n, flags);
@ -256,9 +260,11 @@ evaltree(union node *n, int flags)
case NPIPE:
evalpipe(n);
do_etest = !(flags & EV_TESTED);
break;
case NCMD:
evalcommand(n, flags, (struct backcmd *)NULL);
do_etest = !(flags & EV_TESTED);
break;
default:
out1fmt("Node type = %d\n", n->type);
@ -268,15 +274,13 @@ evaltree(union node *n, int flags)
out:
if (pendingsigs)
dotrap();
if ((flags & EV_EXIT) || (eflag && exitstatus
&& !(flags & EV_TESTED) && (n->type == NCMD ||
n->type == NSUBSHELL)))
if ((flags & EV_EXIT) || (eflag && exitstatus != 0 && do_etest))
exitshell(exitstatus);
}
STATIC void
evalloop(union node *n)
evalloop(union node *n, int flags)
{
int status;
@ -300,7 +304,7 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
if (exitstatus == 0)
break;
}
evaltree(n->nbinary.ch2, 0);
evaltree(n->nbinary.ch2, flags);
status = exitstatus;
if (evalskip)
goto skipping;
@ -312,7 +316,7 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
STATIC void
evalfor(union node *n)
evalfor(union node *n, int flags)
{
struct arglist arglist;
union node *argp;
@ -333,7 +337,7 @@ evalfor(union node *n)
loopnest++;
for (sp = arglist.list ; sp ; sp = sp->next) {
setvar(n->nfor.var, sp->text, 0);
evaltree(n->nfor.body, 0);
evaltree(n->nfor.body, flags);
if (evalskip) {
if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
@ -457,7 +461,7 @@ evalpipe(union node *n)
int prevfd;
int pip[2];
TRACE(("evalpipe(0x%lx) called\n", (long)n));
TRACE(("evalpipe(%p) called\n", (void *)n));
pipelen = 0;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
pipelen++;
@ -596,7 +600,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
#endif
/* First expand the arguments. */
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
setstackmark(&smark);
arglist.lastp = &arglist.list;
varlist.lastp = &varlist.list;
@ -972,6 +976,7 @@ commandcmd(int argc, char **argv)
struct strlist *sp;
char *path;
int ch;
int cmd = -1;
for (sp = cmdenviron; sp ; sp = sp->next)
setvareq(sp->text, VEXPORT|VSTACK);
@ -979,11 +984,17 @@ commandcmd(int argc, char **argv)
optind = optreset = 1;
opterr = 0;
while ((ch = getopt(argc, argv, "p")) != -1) {
while ((ch = getopt(argc, argv, "pvV")) != -1) {
switch (ch) {
case 'p':
path = stdpath;
break;
case 'v':
cmd = TYPECMD_SMALLV;
break;
case 'V':
cmd = TYPECMD_BIGV;
break;
case '?':
default:
error("unknown option: -%c", optopt);
@ -992,6 +1003,11 @@ commandcmd(int argc, char **argv)
argc -= optind;
argv += optind;
if (cmd != -1) {
if (argc != 1)
error("wrong number of arguments");
return typecmd_impl(2, argv - 1, cmd);
}
if (argc != 0) {
old = handler;
handler = &loc;

View File

@ -555,7 +555,7 @@ clearcmdentry(int firstchange)
*/
#ifdef mkinit
MKINIT void deletefuncs();
MKINIT void deletefuncs(void);
SHELLPROC {
deletefuncs();
@ -705,11 +705,12 @@ unsetfunc(char *name)
}
/*
* Locate and print what a word is...
* Shared code for the following builtin commands:
* type, command -v, command -V
*/
int
typecmd(int argc, char **argv)
typecmd_impl(int argc, char **argv, int cmd)
{
struct cmdentry entry;
struct tblentry *cmdp;
@ -720,20 +721,28 @@ typecmd(int argc, char **argv)
extern char *const parsekwd[];
for (i = 1; i < argc; i++) {
out1str(argv[i]);
if (cmd != TYPECMD_SMALLV)
out1str(argv[i]);
/* First look at the keywords */
for (pp = (char **)parsekwd; *pp; pp++)
if (**pp == *argv[i] && equal(*pp, argv[i]))
break;
if (*pp) {
out1str(" is a shell keyword\n");
if (cmd == TYPECMD_SMALLV)
out1fmt("%s\n", argv[i]);
else
out1str(" is a shell keyword\n");
continue;
}
/* Then look at the aliases */
if ((ap = lookupalias(argv[i], 1)) != NULL) {
out1fmt(" is an alias for %s\n", ap->val);
if (cmd == TYPECMD_SMALLV)
out1fmt("alias %s='%s'\n", argv[i], ap->val);
else
out1fmt(" is an alias for %s\n", ap->val);
continue;
}
@ -756,29 +765,55 @@ typecmd(int argc, char **argv)
name = padvance(&path, argv[i]);
stunalloc(name);
} while (--j >= 0);
out1fmt(" is%s %s\n",
cmdp ? " a tracked alias for" : "", name);
if (cmd == TYPECMD_SMALLV)
out1fmt("%s\n", name);
else
out1fmt(" is%s %s\n",
(cmdp && cmd == TYPECMD_TYPE) ?
" a tracked alias for" : "",
name);
} else {
if (access(argv[i], X_OK) == 0)
out1fmt(" is %s\n", argv[i]);
if (access(argv[i], X_OK) == 0) {
if (cmd == TYPECMD_SMALLV)
out1fmt("%s\n", argv[i]);
else
out1fmt(" is %s\n", argv[i]);
}
else
out1fmt(": %s\n", strerror(errno));
}
break;
}
case CMDFUNCTION:
out1str(" is a shell function\n");
if (cmd == TYPECMD_SMALLV)
out1fmt("%s\n", argv[i]);
else
out1str(" is a shell function\n");
break;
case CMDBUILTIN:
out1str(" is a shell builtin\n");
if (cmd == TYPECMD_SMALLV)
out1fmt("%s\n", argv[i]);
else
out1str(" is a shell builtin\n");
break;
default:
out1str(": not found\n");
if (cmd != TYPECMD_SMALLV)
out1str(": not found\n");
error |= 127;
break;
}
}
return error;
}
/*
* Locate and print what a word is...
*/
int
typecmd(int argc, char **argv)
{
return typecmd_impl(argc, argv, TYPECMD_TYPE);
}

View File

@ -39,6 +39,12 @@
#define CMDBUILTIN 1 /* command is a shell builtin */
#define CMDFUNCTION 2 /* command is a shell function */
/* values for typecmd_impl's third parameter */
enum {
TYPECMD_SMALLV, /* command -v */
TYPECMD_BIGV, /* command -V */
TYPECMD_TYPE /* type */
};
struct cmdentry {
int cmdtype;
@ -63,5 +69,6 @@ void deletefuncs(void);
void addcmdentry(char *, struct cmdentry *);
void defun(char *, union node *);
int unsetfunc(char *);
int typecmd_impl(int, char **, int);
int typecmd(int, char **);
void clearcmdentry(int);

View File

@ -893,7 +893,7 @@ numvar:
}
/* FALLTHROUGH */
case '*':
if (ifsset() != 0)
if (ifsset())
sep = ifsval()[0];
else
sep = ' ';
@ -1022,8 +1022,7 @@ ifsbreakup(char *string, struct arglist *arglist)
p++;
}
} while ((ifsp = ifsp->next) != NULL);
if (*start || (!ifsspc && start > string &&
(nulonly || 1))) {
if (*start || (!ifsspc && start > string)) {
sp = (struct strlist *)stalloc(sizeof *sp);
sp->text = start;
*arglist->lastp = sp;
@ -1211,7 +1210,6 @@ expmeta(char *enddir, char *name)
scopy(dp->d_name, enddir);
addfname(expdir);
} else {
char *q;
for (p = enddir, q = dp->d_name;
(*p++ = *q++) != '\0';)
continue;

View File

@ -156,7 +156,7 @@ sethistsize(hs)
if (hs == NULL || *hs == '\0' ||
(histsize = atoi(hs)) < 0)
histsize = 100;
history(hist, &he, H_EVENT, histsize);
history(hist, &he, H_SETSIZE, histsize);
}
}

View File

@ -647,7 +647,7 @@ makejob(union node *node __unused, int nprocs)
jp->ps = &jp->ps0;
}
INTON;
TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
TRACE(("makejob(%p, %d) returns %%%d\n", (void *)node, nprocs,
jp - jobtab + 1));
return jp;
}
@ -733,7 +733,7 @@ forkshell(struct job *jp, union node *n, int mode)
pid_t pid;
pid_t pgrp;
TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
TRACE(("forkshell(%%%d, %p, %d) called\n", jp - jobtab, (void *)n,
mode));
INTOFF;
flushall();

View File

@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include "shell.h"
#include "exec.h" /* defines padvance() */
#include "mail.h"
#include "var.h"
#include "output.h"
#include "memalloc.h"

View File

@ -57,7 +57,10 @@ ckmalloc(int nbytes)
{
pointer p;
if ((p = malloc(nbytes)) == NULL)
INTOFF;
p = malloc(nbytes);
INTON;
if (p == NULL)
error("Out of space");
return p;
}
@ -70,11 +73,22 @@ ckmalloc(int nbytes)
pointer
ckrealloc(pointer p, int nbytes)
{
if ((p = realloc(p, nbytes)) == NULL)
INTOFF;
p = realloc(p, nbytes);
INTON;
if (p == NULL)
error("Out of space");
return p;
}
void
ckfree(pointer p)
{
INTOFF;
free(p);
INTON;
}
/*
* Make a copy of a string in safe storage.

View File

@ -48,6 +48,7 @@ extern int herefd;
pointer ckmalloc(int);
pointer ckrealloc(pointer, int);
void ckfree(pointer);
char *savestr(char *);
pointer stalloc(int);
void stunalloc(pointer);
@ -72,5 +73,3 @@ void ungrabstackstr(char *, char *);
#define STTOPC(p) p[-1]
#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
#define ckfree(p) free((pointer)(p))

View File

@ -64,6 +64,10 @@ __FBSDID("$FreeBSD$");
#undef eflag
int readcmd(int, char **);
int umaskcmd(int, char **);
int ulimitcmd(int, char **);
/*
* The read builtin. The -r option causes backslashes to be treated like
* ordinary characters.
@ -188,13 +192,7 @@ readcmd(int argc __unused, char **argv __unused)
continue;
}
startword = 0;
if (backslash && c == '\\') {
if (read(STDIN_FILENO, &c, 1) != 1) {
status = 1;
break;
}
STPUTC(c, p);
} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
if (ap[1] != NULL && strchr(ifs, c) != NULL) {
STACKSTRNUL(p);
setvar(*ap, stackblock(), 0);
ap++;
@ -270,18 +268,20 @@ umaskcmd(int argc __unused, char **argv)
mask = 0;
do {
if (*ap >= '8' || *ap < '0')
error("Illegal number: %s", argv[1]);
error("Illegal number: %s", *argptr);
mask = (mask << 3) + (*ap - '0');
} while (*++ap != '\0');
umask(mask);
} else {
void *set;
INTOFF;
if ((set = setmode (ap)) == 0)
error("Illegal number: %s", ap);
mask = getmode (set, ~mask & 0777);
umask(~mask & 0777);
free(set);
INTON;
}
}
return 0;

View File

@ -58,9 +58,9 @@ cat <<\!
!
awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
print $0}' builtins.def | sed 's/-[hj]//' > $temp
awk '{ printf "int %s();\n", $1}' $temp
awk '{ printf "int %s(int, char **);\n", $1}' $temp
echo '
int (*const builtinfunc[])() = {'
int (*const builtinfunc[])(int, char **) = {'
awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
echo '};
@ -87,6 +87,6 @@ struct builtincmd {
int code;
};
extern int (*const builtinfunc[])();
extern int (*const builtinfunc[])(int, char **);
extern const struct builtincmd builtincmd[];'
rm -f $temp

View File

@ -133,10 +133,10 @@ char shellproc[] = "\
struct event event[] = {
{"INIT", "init", init},
{"RESET", "reset", reset},
{"SHELLPROC", "initshellproc", shellproc},
{NULL, NULL}
{ "INIT", "init", init, { NULL, 0, NULL, NULL } },
{ "RESET", "reset", reset, { NULL, 0, NULL, NULL } },
{ "SHELLPROC", "initshellproc", shellproc, { NULL, 0, NULL, NULL } },
{ NULL, NULL, NULL, { NULL, 0, NULL, NULL } }
};
@ -172,6 +172,7 @@ main(int argc __unused, char *argv[])
header_files[0] = "\"shell.h\"";
header_files[1] = "\"mystring.h\"";
header_files[2] = "\"init.h\"";
for (ap = argv + 1 ; *ap ; ap++)
readfile(*ap);
output();
@ -391,7 +392,7 @@ output(void)
for (ep = event ; ep->name ; ep++) {
fputs("\n\n\n", fp);
fputs(ep->comment, fp);
fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine);
writetext(&ep->code, fp);
fprintf(fp, "}\n");
}

View File

@ -343,9 +343,10 @@ print(char *name)
static char *macro[] = {
"#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
"#define is_alpha(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && isalpha((unsigned char) (c)))",
"#define is_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalpha((unsigned char) (c))))",
"#define is_in_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalnum((unsigned char) (c))))",
"#define is_eof(c)\t((c) == PEOF)",
"#define is_alpha(c)\t(((c) < CTLESC || (c) > CTLQUOTEMARK) && isalpha((unsigned char) (c)))",
"#define is_name(c)\t(((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalpha((unsigned char) (c))))",
"#define is_in_name(c)\t(((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalnum((unsigned char) (c))))",
"#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
NULL
};

View File

@ -247,7 +247,7 @@ end_options2:
STATIC void
minus_o(char *name, int val)
{
int doneset, i;
int i;
if (name == NULL) {
if (val) {
@ -258,16 +258,13 @@ minus_o(char *name, int val)
optlist[i].val ? "on" : "off");
} else {
/* Output suitable for re-input to shell. */
for (doneset = i = 0; i < NOPTS; i++)
if (optlist[i].val) {
if (!doneset) {
out1str("set");
doneset = 1;
}
out1fmt(" -o %s", optlist[i].name);
}
if (doneset)
out1c('\n');
for (i = 0; i < NOPTS; i++) {
if (i % 6 == 0)
out1str(i == 0 ? "set" : "\nset");
out1fmt(" %co %s", optlist[i].val ? '-' : '+',
optlist[i].name);
}
out1c('\n');
}
} else {
for (i = 0; i < NOPTS; i++)

View File

@ -39,6 +39,7 @@ static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
__FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <unistd.h>
#include "shell.h"
#include "parser.h"
@ -97,12 +98,6 @@ STATIC int startlinno; /* line # where last token started */
/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
static int noaliases = 0;
#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
#ifdef GDB_HACK
static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
static const char types[] = "}-+?=";
#endif
STATIC union node *list(int);
STATIC union node *andor(void);
@ -383,13 +378,12 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
if (lasttoken != TNL && lasttoken != TSEMI)
synexpect(-1);
} else {
#ifndef GDB_HACK
static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
'@', '=', '\0'};
#endif
static char argvars[5] = {
CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
};
n2 = (union node *)stalloc(sizeof (struct narg));
n2->type = NARG;
n2->narg.text = (char *)argvars;
n2->narg.text = argvars;
n2->narg.backquote = NULL;
n2->narg.next = NULL;
n1->nfor.args = n2;
@ -1185,13 +1179,12 @@ parsesub: {
int typeloc;
int flags;
char *p;
#ifndef GDB_HACK
static const char types[] = "}-+?=";
#endif
int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
c = pgetc();
if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) &&
!is_special(c)) {
USTPUTC('$', out);
pungetc();
} else if (c == '(') { /* $(command) or $((arith)) */
@ -1218,11 +1211,11 @@ parsesub: {
else
subtype = 0;
}
if (is_name(c)) {
if (!is_eof(c) && is_name(c)) {
do {
STPUTC(c, out);
c = pgetc();
} while (is_in_name(c));
} while (!is_eof(c) && is_in_name(c));
} else if (is_digit(c)) {
if (bracketed_name) {
do {
@ -1599,7 +1592,7 @@ getprompt(void *unused __unused)
*/
case 'h':
case 'H':
ps[i] == '\0';
ps[i] = '\0';
gethostname(&ps[i], PROMPTLEN - i);
/* Skip to end of hostname. */
trim = (*fmt == 'h') ? '.' : '\0';
@ -1615,7 +1608,7 @@ getprompt(void *unused __unused)
*/
case 'W':
case 'w':
ps[i] == '\0';
ps[i] = '\0';
getcwd(&ps[i], PROMPTLEN - i);
if (*fmt == 'W') {
/* Final path component only. */

View File

@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
.Dd July 3, 2004
.Dd October 29, 2005
.Dt SH 1
.Os
.Sh NAME
@ -208,13 +208,18 @@ option if it has been set).
.It Fl e Li errexit
Exit immediately if any untested command fails in non-interactive mode.
The exit status of a command is considered to be
explicitly tested if the command is used to control
an if, elif, while, or until; or if the command is the left
explicitly tested if the command is part of the list used to control
an if, elif, while, or until; if the command is the left
hand operand of an
.Dq Li &&
or
.Dq Li ||
operator; or if the command is a pipeline preceded by the
.Ic !\&
operator.
If a shell function is executed and its exit status is explicitly
tested, all commands of the function are considered to be tested as
well.
.It Fl f Li noglob
Disable pathname expansion.
.It Fl I Li ignoreeof
@ -355,8 +360,9 @@ The following is a list of valid operators:
.El
.Ss Quoting
Quoting is used to remove the special meaning of certain characters
or words to the shell, such as operators, whitespace, or
keywords.
or words to the shell, such as operators, whitespace, keywords,
or alias names.
.Pp
There are three types of quoting: matched single quotes,
matched double quotes, and backslash.
.Bl -tag -width indent
@ -422,6 +428,16 @@ to create functions with arguments.
They can also be
used to create lexically obscure code.
This use is discouraged.
.Pp
An alias name may be escaped in a command line, so that it is not
replaced by its alias value, by using quoting characters within or
adjacent to the alias name.
This is most often done by prefixing
an alias name with a backslash to execute a function, built-in, or
normal program with the same name.
See the
.Sx Quoting
subsection.
.Ss Commands
The shell interprets the words it reads according to a
language, the specification of which is outside the scope
@ -776,10 +792,15 @@ repeat until the exit status of the first list is zero.
The syntax of the
.Ic for
command is:
.Dl Ic for Ar variable Ic in Ar word ...
.Dl Ic for Ar variable Op Ic in Ar word ...
.Dl Ic do Ar list
.Dl Ic done
.Pp
If
.Ic in
and the following words are omitted,
.Ic in Li $@
is used instead.
The words are expanded, and then the list is executed
repeatedly with the variable set to each word in turn.
The
@ -1352,8 +1373,7 @@ for the file.
If it is not found in the
.Ev PATH ,
it is sought in the current working directory.
.It Ic alias Op Ar name ...
.It Ic alias Op Ar name Ns = Ns Ar string ...
.It Ic alias Oo Ar name Ns Oo = Ns Ar string Oc ... Oc
If
.Ar name Ns = Ns Ar string
is specified, the shell defines the alias
@ -1372,6 +1392,9 @@ built-in command prints the names and values of all defined aliases
.Ic unalias ) .
Alias values are written with appropriate quoting so that they are
suitable for re-input to the shell.
Also see the
.Sx Aliases
subsection.
.It Ic bg Op Ar job ...
Continue the specified jobs
(or the current job if no jobs are given)
@ -1439,7 +1462,8 @@ A synonym for the
.Ic cd
built-in command.
.It Ic command Oo Fl p Oc Op Ar utility Op Ar argument ...
Execute the specified
.It Ic command Oo Fl v | V Oc Op Ar utility
The first form of invocation executes the specified
.Ar utility
as a simple command (see the
.Sx Simple Commands
@ -1451,6 +1475,42 @@ option is specified, the command search is performed using a
default value of
.Ev PATH
that is guaranteed to find all of the standard utilities.
.Pp
If the
.Fl v
option is specified,
.Ar utility
is not executed but a description of its interpretation by the shell is
printed.
For ordinary commands the output is the path name; for shell built-in
commands, shell functions and keywords only the name is written.
Aliases are printed as
.Dq Ic alias Ar name Ns = Ns Ar value .
.Pp
The
.Fl V
option is identical to
.Fl v
except for the output.
It prints
.Dq Ar utility Ic is Ar description
where
.Ar description
is either
.Bl -item -offset indent
.It
the path name to
.Ar utility ,
.It
.Ic a shell builtin ,
.It
.Ic a shell function ,
.It
.Ic a shell keyword
or
.It
.Ic an alias for Ar value .
.El
.It Ic echo Oo Fl e | n Oc Op Ar string
Print
.Ar string
@ -1534,7 +1594,8 @@ If
is given
it is used as the exit status of the shell;
otherwise the exit status of the preceding command is used.
.It Ic export Oo Fl p Oc Op Ar name ...
.It Ic export Ar name ...
.It Ic export Op Fl p
The specified names are exported so that they will
appear in the environment of subsequent commands.
The only way to un-export a variable is to
@ -1719,6 +1780,10 @@ option is specified, the PID of each job is also printed.
If the
.Fl s
option is specified, only the PIDs of the jobs are printed, one per line.
.It Ic local Oo Ar variable ... Oc Op Ar -
See the
.Sx Functions
subsection.
.It Ic pwd Op Fl L | P
Print the path of the current directory.
The built-in command may
@ -1784,7 +1849,7 @@ option is specified and the
elapses before any input is supplied,
the
.Ic read
command will return without assigning any values.
command will return an exit status of 1 without assigning any values.
The
.Ar timeout
value may optionally be followed by one of
@ -1820,6 +1885,10 @@ If the
option is specified, the read-only variables are printed as
.Dq Ic readonly Ar name Ns = Ns Ar value
lines, suitable for re-input to the shell.
.It Ic return Op Ar exitstatus
See the
.Sx Functions
subsection.
.It Ic set Oo Fl /+abCEefIimnpTuVvx Oc Oo Fl /+o Ar longname Oc Oo
.Fl c Ar string Oc Op Fl - Ar arg ...
The
@ -1978,16 +2047,19 @@ The maximal number of simultaneous processes for this user ID.
.It Fl v Ar virtualmem
The maximal virtual size of a process, in kilobytes.
.El
.It Ic umask Op Ar mask
.It Ic umask Oo Fl S Oc Op Ar mask
Set the file creation mask (see
.Xr umask 2 )
to the octal value specified by
to the octal or symbolic (see
.Xr chmod 1 )
value specified by
.Ar mask .
If the argument is omitted, the current mask value is printed.
.It Ic unalias Oo Fl a Oc Op Ar name
If
.Ar name
is specified, the shell removes that alias.
If the
.Fl S
option is specified, the output is symbolic, otherwise the output is octal.
.It Ic unalias Oo Fl a Oc Op Ar name ...
The specified alias names are removed.
If
.Fl a
is specified, all aliases are removed.

View File

@ -371,7 +371,6 @@ void
opentrace(void)
{
char s[100];
char *getenv();
int flags;
if (!debug)

View File

@ -382,7 +382,7 @@ onsig(int signo)
*/
if (Tflag &&
trap[signo] != NULL &&
! trap[signo][0] == '\0' &&
! (trap[signo][0] == '\0') &&
! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
breakwaitcmd = 1;

View File

@ -445,7 +445,7 @@ environment(void)
*/
#ifdef mkinit
MKINIT void shprocvar();
MKINIT void shprocvar(void);
SHELLPROC {
shprocvar();
@ -541,9 +541,11 @@ exportcmd(int argc, char **argv)
argc -= optind;
argv += optind;
if (values && argc != 0)
error("-p requires no arguments");
listsetvar(cmdenviron);
if (argc != 0) {
while ((name = *argptr++) != NULL) {
while ((name = *argv++) != NULL) {
if ((p = strchr(name, '=')) != NULL) {
p++;
} else {