- POSIX special built-ins (builtin.defs 1.19, main.c 1.28, mkbuiltins 1.16,
    eval.c 1.51, exec.c 1.29, exec.h 1.15, options.c 1.25)
- Fix el_gets() buffer handling (input.c 1.23).
- Sort 'set' output (var.c 1.31).
- Document that '#' starts a comment (sh.1 1.118).
This commit is contained in:
stefanf 2006-06-03 15:38:08 +00:00
parent 487eb1ffd8
commit 63f3d1c92c
10 changed files with 130 additions and 62 deletions

View File

@ -36,13 +36,15 @@
#
# This file lists all the builtin commands. The first column is the name
# of a C routine. The -j flag, if present, specifies that this command
# is to be excluded from systems without job control, and the -h flag,
# if present specifies that this command is to be excluded from systems
# based on the NO_HISTORY compile-time symbol. The rest of the line
# specifies the command name or names used to run the command. The entry
# for bltincmd, which is run when the user does not specify a command, must
# come first.
# of a C routine.
# The -j flag specifies that this command is to be excluded from systems
# without job control.
# The -h flag specifies that this command is to be excluded from systems
# based on the NO_HISTORY compile-time symbol.
# The -s flag specifies that this is a POSIX 'special built-in' command.
# The rest of the line specifies the command name or names used to run the
# command. The entry for bltincmd, which is run when the user does not specify
# a command, must come first.
#
# NOTE: bltincmd must come first!
@ -50,16 +52,16 @@ bltincmd builtin
aliascmd alias
bgcmd -j bg
bindcmd bind
breakcmd break continue
breakcmd -s break -s continue
cdcmd cd chdir
commandcmd command
dotcmd .
dotcmd -s .
echocmd echo
evalcmd eval
execcmd exec
exitcmd exit
evalcmd -s eval
execcmd -s exec
exitcmd -s exit
expcmd exp let
exportcmd export readonly
exportcmd -s export -s readonly
#exprcmd expr
falsecmd false
fgcmd -j fg
@ -72,18 +74,18 @@ localcmd local
#printfcmd printf
pwdcmd pwd
readcmd read
returncmd return
setcmd set
returncmd -s return
setcmd -s set
setvarcmd setvar
shiftcmd shift
shiftcmd -s shift
testcmd test [
timescmd times
trapcmd trap
truecmd : true
timescmd -s times
trapcmd -s trap
truecmd -s : true
typecmd type
ulimitcmd ulimit
umaskcmd umask
unaliascmd unalias
unsetcmd unset
unsetcmd -s unset
waitcmd wait
wordexpcmd wordexp

View File

@ -658,8 +658,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
/* Now locate the command. */
if (argc == 0) {
/* Variable assignment(s) without command */
cmdentry.cmdtype = CMDBUILTIN;
cmdentry.u.index = BLTINCMD;
cmdentry.special = 1;
} else {
static const char PATH[] = "PATH=";
char *path = pathval();
@ -705,7 +707,8 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
argv++;
if (--argc == 0)
break;
if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
if ((cmdentry.u.index = find_builtin(*argv,
&cmdentry.special)) < 0) {
outfmt(&errout, "%s: not found\n", *argv);
exitstatus = 127;
flushout(&errout);
@ -812,7 +815,6 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
memout.bufsize = 64;
mode |= REDIR_BACKQ;
}
redirect(cmd->ncmd.redirect, mode);
savecmdname = commandname;
cmdenviron = varlist.list;
e = -1;
@ -823,6 +825,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
}
savehandler = handler;
handler = &jmploc;
redirect(cmd->ncmd.redirect, mode);
if (cmdentry.special)
listsetvar(cmdenviron);
commandname = argv[0];
argptr = argv + 1;
optptr = NULL; /* initialize nextopt */
@ -842,14 +847,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
handler = savehandler;
if (e != -1) {
if ((e != EXERROR && e != EXEXEC)
|| cmdentry.u.index == BLTINCMD
|| cmdentry.u.index == DOTCMD
|| cmdentry.u.index == EVALCMD
#ifndef NO_HISTORY
|| cmdentry.u.index == HISTCMD
#endif
|| cmdentry.u.index == EXECCMD
|| cmdentry.u.index == COMMANDCMD)
|| cmdentry.special)
exraise(e);
FORCEINTON;
}
@ -925,14 +923,12 @@ prehash(union node *n)
*/
/*
* No command given, or a bltin command with no arguments. Set the
* specified variables.
* No command given, or a bltin command with no arguments.
*/
int
bltincmd(int argc __unused, char **argv __unused)
{
listsetvar(cmdenviron);
/*
* Preserve exitstatus of a previous possible redirection
* as POSIX mandates

View File

@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$");
struct tblentry {
struct tblentry *next; /* next entry in hash chain */
union param param; /* definition of builtin function */
int special; /* flag for special builtin commands */
short cmdtype; /* index identifying command */
char rehash; /* if set, cd done since entry created */
char cmdname[ARB]; /* name of command */
@ -317,6 +318,7 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
struct stat statb;
int e;
int i;
int spec;
/* If name contains a slash, don't use the hash table */
if (strchr(name, '/') != NULL) {
@ -330,11 +332,12 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
goto success;
/* If %builtin not in path, check for builtin next */
if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
if (builtinloc < 0 && (i = find_builtin(name, &spec)) >= 0) {
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
cmdp->special = spec;
INTON;
goto success;
}
@ -356,12 +359,13 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
index++;
if (pathopt) {
if (prefix("builtin", pathopt)) {
if ((i = find_builtin(name)) < 0)
if ((i = find_builtin(name, &spec)) < 0)
goto loop;
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
cmdp->special = spec;
INTON;
goto success;
} else if (prefix("func", pathopt)) {
@ -430,6 +434,7 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
cmdp->rehash = 0;
entry->cmdtype = cmdp->cmdtype;
entry->u = cmdp->param;
entry->special = cmdp->special;
}
@ -439,13 +444,15 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
*/
int
find_builtin(char *name)
find_builtin(char *name, int *special)
{
const struct builtincmd *bp;
for (bp = builtincmd ; bp->name ; bp++) {
if (*bp->name == *name && equal(bp->name, name))
if (*bp->name == *name && equal(bp->name, name)) {
*special = bp->special;
return bp->code;
}
}
return -1;
}

View File

@ -52,6 +52,7 @@ struct cmdentry {
int index;
union node *func;
} u;
int special;
};
@ -62,7 +63,7 @@ void shellexec(char **, char **, char *, int);
char *padvance(char **, char *);
int hashcmd(int, char **);
void find_command(char *, struct cmdentry *, int, char *);
int find_builtin(char *);
int find_builtin(char *, int *);
void hashcd(void);
void changepath(const char *);
void deletefuncs(void);

View File

@ -184,14 +184,23 @@ preadfd(void)
retry:
#ifndef NO_HISTORY
if (parsefile->fd == 0 && el) {
const char *rl_cp;
static const char *rl_cp;
static int el_len;
rl_cp = el_gets(el, &nr);
if (rl_cp == NULL)
rl_cp = el_gets(el, &el_len);
if (rl_cp == NULL)
nr = 0;
else {
/* XXX - BUFSIZE should redesign so not necessary */
(void) strcpy(parsenextc, rl_cp);
nr = el_len;
if (nr > BUFSIZ - 1)
nr = BUFSIZ - 1;
memcpy(parsenextc, rl_cp, nr);
if (nr != el_len) {
el_len -= nr;
rl_cp += nr;
} else
rl_cp = NULL;
}
} else
#endif

View File

@ -314,19 +314,21 @@ int
dotcmd(int argc, char **argv)
{
struct strlist *sp;
char *fullname;
if (argc < 2)
error("missing filename");
exitstatus = 0;
for (sp = cmdenviron; sp ; sp = sp->next)
setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
if (argc >= 2) { /* That's what SVR2 does */
char *fullname = find_dot_file(argv[1]);
setinputfile(fullname, 1);
commandname = fullname;
cmdloop(0);
popfile();
}
fullname = find_dot_file(argv[1]);
setinputfile(fullname, 1);
commandname = fullname;
cmdloop(0);
popfile();
return exitstatus;
}

View File

@ -66,9 +66,14 @@ echo '};
const struct builtincmd builtincmd[] = {'
awk '{ for (i = 2 ; i <= NF ; i++) {
printf "\t{ \"%s\", %d },\n", $i, NR-1
if ($i == "-s") {
spc = 1;
} else {
printf "\t{ \"%s\", %d, %d },\n", $i, NR-1, spc
spc = 0;
}
}}' $temp
echo ' { NULL, 0 }
echo ' { NULL, 0, 0 }
};'
exec > ${objdir}/builtins.h
@ -85,6 +90,7 @@ echo '
struct builtincmd {
char *name;
int code;
int special;
};
extern int (*const builtinfunc[])(int, char **);

View File

@ -374,7 +374,7 @@ shiftcmd(int argc, char **argv)
if (argc > 1)
n = number(argv[1]);
if (n > shellparam.nparam)
error("can't shift that many");
return 1;
INTOFF;
shellparam.nparam -= n;
for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {

View File

@ -362,6 +362,13 @@ The following is a list of valid operators:
.It Li <& Ta Li >& Ta Li <<- Ta Li >|
.El
.El
.Pp
The character
.Ql #
introduces a comment if used at the beginning of a word.
The word starting with
.Ql #
and the rest of the line are ignored.
.Ss Quoting
Quoting is used to remove the special meaning of certain characters
or words to the shell, such as operators, whitespace, keywords,

View File

@ -479,6 +479,21 @@ shprocvar(void)
}
static int
var_compare(const void *a, const void *b)
{
const char *const *sa, *const *sb;
sa = a;
sb = b;
/*
* This compares two var=value strings which creates a different
* order from what you would probably expect. POSIX is somewhat
* ambiguous on what should be sorted exactly.
*/
return strcoll(*sa, *sb);
}
/*
* Command to list all variables which are set. Currently this command
@ -492,18 +507,41 @@ showvarscmd(int argc __unused, char **argv __unused)
struct var **vpp;
struct var *vp;
const char *s;
const char **vars;
int i, n;
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (vp = *vpp ; vp ; vp = vp->next) {
if (vp->flags & VUNSET)
continue;
for (s = vp->text; *s != '='; s++)
out1c(*s);
out1c('=');
out1qstr(s + 1);
out1c('\n');
/*
* POSIX requires us to sort the variables.
*/
n = 0;
for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
for (vp = *vpp; vp; vp = vp->next) {
if (!(vp->flags & VUNSET))
n++;
}
}
INTON;
vars = ckmalloc(n * sizeof(*vars));
i = 0;
for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
for (vp = *vpp; vp; vp = vp->next) {
if (!(vp->flags & VUNSET))
vars[i++] = vp->text;
}
}
qsort(vars, n, sizeof(*vars), var_compare);
for (i = 0; i < n; i++) {
for (s = vars[i]; *s != '='; s++)
out1c(*s);
out1c('=');
out1qstr(s + 1);
out1c('\n');
}
ckfree(vars);
INTOFF;
return 0;
}