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:
parent
80d777c8ec
commit
58babfa98f
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 **);
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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++)
|
||||
|
@ -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. */
|
||||
|
106
bin/sh/sh.1
106
bin/sh/sh.1
@ -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.
|
||||
|
@ -371,7 +371,6 @@ void
|
||||
opentrace(void)
|
||||
{
|
||||
char s[100];
|
||||
char *getenv();
|
||||
int flags;
|
||||
|
||||
if (!debug)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user