MFC:
- 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:
parent
487eb1ffd8
commit
63f3d1c92c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 **);
|
||||
|
@ -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++) {
|
||||
|
@ -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,
|
||||
|
56
bin/sh/var.c
56
bin/sh/var.c
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user