static const char homestr[] ALIGN1 = "HOME";
static const char snlfmt[] ALIGN1 = "%s\n";
-static const char illnum[] ALIGN1 = "Illegal number: %s";
+static const char msg_illnum[] ALIGN1 = "Illegal number: %s";
/*
* We enclose jmp_buf in a structure so that we can declare pointers to
struct jmploc *exception_handler;
-// disabled by vda: cannot understand how it was supposed to work -
-// cannot fix bugs. That's why you have to explain your non-trivial designs!
-// /* do we generate EXSIG events */
-// int exsig; /* counter */
- volatile int suppressint; /* counter */
-// TODO: rename
-// pendingsig -> pending_sig
-// intpending -> pending_int
- volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
+ volatile int suppress_int; /* counter */
+ volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
/* last pending signal */
- volatile /*sig_atomic_t*/ smallint pendingsig;
+ volatile /*sig_atomic_t*/ smallint pending_sig;
smallint exception_type; /* kind of exception (0..5) */
/* exceptions */
#define EXINT 0 /* SIGINT received */
#define arg0 (G_misc.arg0 )
#define exception_handler (G_misc.exception_handler)
#define exception_type (G_misc.exception_type )
-#define suppressint (G_misc.suppressint )
-#define intpending (G_misc.intpending )
-//#define exsig (G_misc.exsig )
-#define pendingsig (G_misc.pendingsig )
+#define suppress_int (G_misc.suppress_int )
+#define pending_int (G_misc.pending_int )
+#define pending_sig (G_misc.pending_sig )
#define isloginsh (G_misc.isloginsh )
#define nullstr (G_misc.nullstr )
#define optlist (G_misc.optlist )
# define close(fd) do { \
int dfd = (fd); \
if (close(dfd) < 0) \
- bb_error_msg("bug on %d: closing %d(%x)", \
+ bb_error_msg("bug on %d: closing %d(0x%x)", \
__LINE__, dfd, dfd); \
} while (0)
#else
/* ============ Utility functions */
#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
-/* C99 say: "char" declaration may be signed or unsigned by default */
+/* C99 says: "char" declaration may be signed or unsigned by default */
#define signed_char2int(sc) ((int)(signed char)(sc))
static int isdigit_str9(const char *str)
* more fun than worrying about efficiency and portability. :-))
*/
#define INT_OFF do { \
- suppressint++; \
+ suppress_int++; \
xbarrier(); \
} while (0)
{
int ex_type;
- intpending = 0;
+ pending_int = 0;
/* Signal is not automatically unmasked after it is raised,
* do it ourself - unmask all signals */
sigprocmask_allsigs(SIG_UNBLOCK);
- /* pendingsig = 0; - now done in onsig() */
+ /* pending_sig = 0; - now done in onsig() */
ex_type = EXSIG;
if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
int_on(void)
{
xbarrier();
- if (--suppressint == 0 && intpending) {
+ if (--suppress_int == 0 && pending_int) {
raise_interrupt();
}
}
force_int_on(void)
{
xbarrier();
- suppressint = 0;
- if (intpending)
+ suppress_int = 0;
+ if (pending_int)
raise_interrupt();
}
#define FORCE_INT_ON force_int_on()
-#define SAVE_INT(v) ((v) = suppressint)
+#define SAVE_INT(v) ((v) = suppress_int)
#define RESTORE_INT(v) do { \
xbarrier(); \
- suppressint = (v); \
- if (suppressint == 0 && intpending) \
+ suppress_int = (v); \
+ if (suppress_int == 0 && pending_int) \
raise_interrupt(); \
} while (0)
/* ============ Parser structures */
/* control characters in argument strings */
-#define CTLESC '\201' /* escape next character */
-#define CTLVAR '\202' /* variable defn */
-#define CTLENDVAR '\203'
-#define CTLBACKQ '\204'
+#define CTLESC ((unsigned char)'\201') /* escape next character */
+#define CTLVAR ((unsigned char)'\202') /* variable defn */
+#define CTLENDVAR ((unsigned char)'\203')
+#define CTLBACKQ ((unsigned char)'\204')
#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
/* CTLBACKQ | CTLQUOTE == '\205' */
-#define CTLARI '\206' /* arithmetic expression */
-#define CTLENDARI '\207'
-#define CTLQUOTEMARK '\210'
+#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
+#define CTLENDARI ((unsigned char)'\207')
+#define CTLQUOTEMARK ((unsigned char)'\210')
/* variable substitution byte (follows CTLVAR) */
#define VSTYPE 0x0f /* type of variable substitution */
struct nnot nnot;
};
+/*
+ * NODE_EOF is returned by parsecmd when it encounters an end of file.
+ * It must be distinct from NULL.
+ */
+#define NODE_EOF ((union node *) -1L)
+
struct nodelist {
struct nodelist *next;
union node *n;
if (DEBUG_PID)
fprintf(tracefile, "[%u] ", (int) getpid());
if (DEBUG_SIG)
- fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
+ fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
va_start(va, fmt);
vfprintf(tracefile, fmt, va);
va_end(va);
if (DEBUG_PID)
fprintf(tracefile, "[%u] ", (int) getpid());
if (DEBUG_SIG)
- fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
+ fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
vfprintf(tracefile, fmt, va);
}
}
}
-static void FAST_FUNC
+static void
shcmd(union node *cmd, FILE *fp)
{
union node *np;
return;
indent(ind, pfx, fp);
+
+ if (n == NODE_EOF) {
+ fputs("<EOF>", fp);
+ return;
+ }
+
switch (n->type) {
case NSEMI:
s = "; ";
break;
case NPIPE:
for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
- shcmd(lp->n, fp);
+ shtree(lp->n, 0, NULL, fp);
if (lp->next)
fputs(" | ", fp);
}
showtree(union node *n)
{
trace_puts("showtree called\n");
- shtree(n, 1, NULL, stdout);
+ shtree(n, 1, NULL, stderr);
}
#endif /* DEBUG */
number(const char *s)
{
if (!is_number(s))
- ash_msg_and_raise_error(illnum, s);
+ ash_msg_and_raise_error(msg_illnum, s);
return atoi(s);
}
/* Need to be before varinit_data[] */
#if ENABLE_LOCALE_SUPPORT
-static void
+static void FAST_FUNC
change_lc_all(const char *value)
{
if (value && *value != '\0')
setlocale(LC_ALL, value);
}
-static void
+static void FAST_FUNC
change_lc_ctype(const char *value)
{
if (value && *value != '\0')
/* ============ Path search helper
*
* The variable path (passed by reference) should be set to the start
- * of the path before the first call; padvance will update
- * this value as it proceeds. Successive calls to padvance will return
+ * of the path before the first call; path_advance will update
+ * this value as it proceeds. Successive calls to path_advance will return
* the possible path expansions in sequence. If an option (indicated by
* a percent sign) appears in the path entry then the global variable
* pathopt will be set to point to it; otherwise pathopt will be set to
* NULL.
*/
-static const char *pathopt; /* set by padvance */
+static const char *pathopt; /* set by path_advance */
static char *
-padvance(const char **path, const char *name)
+path_advance(const char **path, const char *name)
{
const char *p;
char *q;
#define CD_PHYSICAL 1
#define CD_PRINT 2
-static int docd(const char *, int);
-
static int
cdopt(void)
{
int i, j;
j = 'L';
- while ((i = nextopt("LP"))) {
+ while ((i = nextopt("LP")) != '\0') {
if (i != j) {
flags ^= CD_PHYSICAL;
j = i;
}
do {
c = *path;
- p = padvance(&path, dest);
+ p = path_advance(&path, dest);
if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
if (c && c != ':')
flags |= CD_PRINT;
#define FORK_NOJOB 2
/* mode flags for showjob(s) */
-#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
-#define SHOW_PID 0x04 /* include process pid */
-#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
+#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
+#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
+#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
/*
* A job structure contains information about a job. A job is either a
* latter case, pidlist will be non-NULL, and will point to a -1 terminated
* array of pids.
*/
-
struct procstat {
pid_t pid; /* process id */
int status; /* last process status from wait() */
{
gotsig[signo - 1] = 1;
- if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
- if (!suppressint) {
- pendingsig = 0;
+ if (signo == SIGINT && !trap[SIGINT]) {
+ if (!suppress_int) {
+ pending_sig = 0;
raise_interrupt(); /* does not return */
}
- intpending = 1;
+ pending_int = 1;
} else {
- pendingsig = signo;
+ pending_sig = signo;
}
}
{
struct job *jp;
struct job *found;
- const char *err_msg = "No such job: %s";
+ const char *err_msg = "%s: no such job";
unsigned num;
int c;
const char *p;
}
if (is_number(p)) {
-// TODO: number() instead? It does error checking...
num = atoi(p);
if (num < njobs) {
jp = jobtab + num - 1;
p++;
}
- found = 0;
- while (1) {
- if (!jp)
- goto err;
+ found = NULL;
+ while (jp) {
if (match(jp->ps[0].cmd, p)) {
if (found)
goto err;
}
jp = jp->prev_job;
}
+ if (!found)
+ goto err;
+ jp = found;
gotit:
#if JOBS
blocking_wait_with_raise_on_sig(struct job *job)
{
pid_t pid = dowait(DOWAIT_BLOCK, job);
- if (pid <= 0 && pendingsig)
+ if (pid <= 0 && pending_sig)
raise_exception(EXSIG);
return pid;
}
ps = jp->ps;
- if (mode & SHOW_PGID) {
+ if (mode & SHOW_ONLY_PGID) { /* jobs -p */
/* just output process (group) id of pipeline */
fprintf(out, "%d\n", ps->pid);
return;
indent_col = col;
if (jp == curjob)
- s[col - 2] = '+';
+ s[col - 3] = '+';
else if (curjob && jp == curjob->prev_job)
- s[col - 2] = '-';
+ s[col - 3] = '-';
- if (mode & SHOW_PID)
+ if (mode & SHOW_PIDS)
col += fmtstr(s + col, 16, "%d ", ps->pid);
psend = ps + jp->nprocs;
status = jp->stopstatus;
col += sprint_status(s + col, status, 0);
}
+ /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
+ /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
+ * or prints several "PID | <cmdN>" lines,
+ * depending on SHOW_PIDS bit.
+ * We do not print status of individual processes
+ * between PID and <cmdN>. bash does it, but not very well:
+ * first line shows overall job status, not process status,
+ * making it impossible to know 1st process status.
+ */
goto start;
-
- do {
+ while (1) {
/* for each process */
- col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
+ s[0] = '\0';
+ col = 33;
+ if (mode & SHOW_PIDS)
+ col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->pid) - 1;
start:
- fprintf(out, "%s%*c%s",
- s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
- );
- if (!(mode & SHOW_PID)) {
- showpipe(jp, out);
+ fprintf(out, "%s%*c", s, 33 - col >= 0 ? 33 - col : 0, ' ');
+ if (ps != jp->ps)
+ fprintf(out, "| ");
+ fprintf(out, "%s", ps->cmd);
+ if (++ps == psend)
break;
- }
- if (++ps == psend) {
- outcslow('\n', out);
- break;
- }
- } while (1);
+ }
+ outcslow('\n', out);
jp->changed = 0;
{
struct job *jp;
- TRACE(("showjobs(%x) called\n", mode));
+ TRACE(("showjobs(0x%x) called\n", mode));
/* Handle all finished jobs */
while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
int mode, m;
mode = 0;
- while ((m = nextopt("lp"))) {
+ while ((m = nextopt("lp")) != '\0') {
if (m == 'l')
- mode = SHOW_PID;
+ mode |= SHOW_PIDS;
else
- mode = SHOW_PGID;
+ mode |= SHOW_ONLY_PGID;
}
argv = argptr;
if (*argv) {
do
- showjob(stdout, getjob(*argv,0), mode);
+ showjob(stdout, getjob(*argv, 0), mode);
while (*++argv);
} else
showjobs(stdout, mode);
}
retval += 128;
}
- TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
+ TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
jobno(job), job->nprocs, status, retval));
return retval;
}
int retval;
struct job *jp;
-// exsig++;
-// xbarrier();
- if (pendingsig)
+ if (pending_sig)
raise_exception(EXSIG);
nextopt(nullstr);
if (!str)
continue;
dostr:
- while ((c = *str++)) {
+ while ((c = *str++) != '\0') {
USTPUTC(c, nextc);
}
}
cmdputs("if ");
cmdtxt(n->nif.test);
cmdputs("; then ");
- n = n->nif.ifpart;
if (n->nif.elsepart) {
- cmdtxt(n);
+ cmdtxt(n->nif.ifpart);
cmdputs("; else ");
n = n->nif.elsepart;
+ } else {
+ n = n->nif.ifpart;
}
p = "; fi";
goto dotail;
static void closescript(void);
/* Called after fork(), in child */
+#if !JOBS
+# define forkchild(jp, n, mode) forkchild(jp, mode)
+#endif
static void
-forkchild(struct job *jp, /*union node *n,*/ int mode)
+forkchild(struct job *jp, union node *n, int mode)
{
int oldlvl;
* Take care of the second rule: */
setsignal(SIGQUIT);
}
+#if JOBS
+ if (n && n->type == NCMD && strcmp(n->ncmd.args->narg.text, "jobs") == 0) {
+ TRACE(("Job hack\n"));
+ freejob(curjob);
+ return;
+ }
+#endif
for (jp = curjob; jp; jp = jp->prev_job)
freejob(jp);
jobless = 0;
ash_msg_and_raise_error("can't fork");
}
if (pid == 0)
- forkchild(jp, /*n,*/ mode);
+ forkchild(jp, n, mode);
else
forkparent(jp, n, mode, pid);
return pid;
* Remove any CTLESC characters from a string.
*/
static char *
-_rmescapes(char *str, int flag)
+rmescapes(char *str, int flag)
{
static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
}
return r;
}
-#define rmescapes(p) _rmescapes((p), 0)
-
#define pmatch(a, b) !fnmatch((a), (b), 0)
/*
if (quoted) {
flag |= RMESCAPE_QUOTED;
}
- return _rmescapes((char *)pattern, flag);
+ return rmescapes((char *)pattern, flag);
}
/*
{
char *q = expdest;
- q = makestrspace(len * 2, q);
+ q = makestrspace(quotes ? len * 2 : len, q);
while (len--) {
int c = signed_char2int(*p++);
if (!c)
continue;
- if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
- USTPUTC(CTLESC, q);
+ if (quotes) {
+ int n = SIT(c, syntax);
+ if (n == CCTL || n == CBACK)
+ USTPUTC(CTLESC, q);
+ }
USTPUTC(c, q);
}
/* These forward decls are needed to use "eval" code for backticks handling: */
static uint8_t back_exitstatus; /* exit status of backquoted command */
#define EV_EXIT 01 /* exit after evaluating tree */
-static void FAST_FUNC evaltree(union node *, int);
+static void evaltree(union node *, int);
static void FAST_FUNC
evalbackcmd(union node *n, struct backcmd *result)
expdest = p;
if (quotes)
- rmescapes(p + 2);
+ rmescapes(p + 2, 0);
len = cvtnum(ash_arith(p + 2));
};
const char *reject = spclchars;
int c;
- int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
+ int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
int breakall = flag & EXP_WORD;
int inquotes;
size_t length;
#if ENABLE_ASH_BASH_COMPAT
case VSSUBSTR:
loc = str = stackblock() + strloc;
-// TODO: number() instead? It does error checking...
- pos = atoi(loc);
+ /* Read POS in ${var:POS:LEN} */
+ pos = atoi(loc); /* number(loc) errors out on "1:4" */
len = str - startp - 1;
/* *loc != '\0', guaranteed by parser */
if (quotes) {
char *ptr;
- /* We must adjust the length by the number of escapes we find. */
+ /* Adjust the length by the number of escapes */
for (ptr = startp; ptr < (str - 1); ptr++) {
if (*ptr == CTLESC) {
len--;
orig_len = len;
if (*loc++ == ':') {
-// TODO: number() instead? It does error checking...
- len = atoi(loc);
+ /* ${var::LEN} */
+ len = number(loc);
} else {
+ /* Skip POS in ${var:POS:LEN} */
len = orig_len;
- while (*loc && *loc != ':')
+ while (*loc && *loc != ':') {
+ /* TODO?
+ * bash complains on: var=qwe; echo ${var:1a:123}
+ if (!isdigit(*loc))
+ ash_msg_and_raise_error(msg_illnum, str);
+ */
loc++;
- if (*loc++ == ':')
-// TODO: number() instead? It does error checking...
- len = atoi(loc);
+ }
+ if (*loc++ == ':') {
+ len = number(loc);
+ }
}
if (pos >= orig_len) {
pos = 0;
rmesc = startp;
rmescend = (char *)stackblock() + strloc;
if (quotes) {
- rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
+ rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
if (rmesc != startp) {
rmescend = expdest;
startp = (char *)stackblock() + startloc;
ap = shellparam.p;
if (!ap)
return -1;
- while ((p = *ap++)) {
+ while ((p = *ap++) != NULL) {
size_t partlen;
partlen = strlen(p);
case '7':
case '8':
case '9':
-// TODO: number() instead? It does error checking...
- num = atoi(name);
+ num = atoi(name); /* number(name) fails on ${var#str} etc */
if (num < 0 || num > shellparam.nparam)
return -1;
p = num ? shellparam.p[num - 1] : arg0;
p++;
if (*p == '.')
matchdot++;
- while (!intpending && (dp = readdir(dirp)) != NULL) {
+ while (!pending_int && (dp = readdir(dirp)) != NULL) {
if (dp->d_name[0] == '.' && !matchdot)
continue;
if (pmatch(start, dp->d_name)) {
*/
nometa:
*exparg.lastp = str;
- rmescapes(str->text);
+ rmescapes(str->text, 0);
exparg.lastp = &str->next;
} else {
*exparg.lastp = NULL;
expandmeta(exparg.list /*, flag*/);
} else {
if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
- rmescapes(p);
+ rmescapes(p, 0);
sp = stzalloc(sizeof(*sp));
sp->text = p;
*exparg.lastp = sp;
e = errno;
} else {
e = ENOENT;
- while ((cmdname = padvance(&path, argv[0])) != NULL) {
+ while ((cmdname = path_advance(&path, argv[0])) != NULL) {
if (--idx < 0 && pathopt == NULL) {
tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
if (errno != ENOENT && errno != ENOTDIR)
break;
}
exitstatus = exerrno;
- TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
- argv[0], e, suppressint));
+ TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
+ argv[0], e, suppress_int));
ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
/* NOTREACHED */
}
idx = cmdp->param.index;
path = pathval();
do {
- name = padvance(&path, cmdp->cmdname);
+ name = path_advance(&path, cmdp->cmdname);
stunalloc(name);
} while (--idx >= 0);
out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
p = command;
} else {
do {
- p = padvance(&path, command);
+ p = path_advance(&path, command);
stunalloc(p);
} while (--j >= 0);
}
uint8_t savestatus;
savestatus = exitstatus;
- pendingsig = 0;
+ pending_sig = 0;
xbarrier();
TRACE(("dotrap entered\n"));
}
/* forward declarations - evaluation is fairly recursive business... */
-static void FAST_FUNC evalloop(union node *, int);
-static void FAST_FUNC evalfor(union node *, int);
-static void FAST_FUNC evalcase(union node *, int);
-static void FAST_FUNC evalsubshell(union node *, int);
+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 *);
-static void FAST_FUNC evalpipe(union node *, int);
-static void FAST_FUNC evalcommand(union node *, int);
+static void evalpipe(union node *, int);
+static void evalcommand(union node *, int);
static int evalbltin(const struct builtincmd *, int, char **);
static void prehash(union node *);
* Evaluate a parse tree. The value is left in the global variable
* exitstatus.
*/
-static void FAST_FUNC
+static void
evaltree(union node *n, int flags)
{
struct jmploc *volatile savehandler = exception_handler;
struct jmploc jmploc;
int checkexit = 0;
- void (*evalfn)(union node *, int) FAST_FUNC;
+ void (*evalfn)(union node *, int);
int status;
int int_level;
out1:
if (checkexit & exitstatus)
evalskip |= SKIPEVAL;
- else if (pendingsig && dotrap())
+ else if (pending_sig && dotrap())
goto exexit;
if (flags & EV_EXIT) {
#endif
void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
-static void FAST_FUNC
+static void
evalloop(union node *n, int flags)
{
int status;
exitstatus = status;
}
-static void FAST_FUNC
+static void
evalfor(union node *n, int flags)
{
struct arglist arglist;
popstackmark(&smark);
}
-static void FAST_FUNC
+static void
evalcase(union node *n, int flags)
{
union node *cp;
/*
* Kick off a subshell to evaluate a tree.
*/
-static void FAST_FUNC
+static void
evalsubshell(union node *n, int flags)
{
struct job *jp;
* of the shell, which make the last process in a pipeline the parent
* of all the rest.)
*/
-static void FAST_FUNC
+static void
evalpipe(union node *n, int flags)
{
struct job *jp;
while ((lvp = localvars) != NULL) {
localvars = lvp->next;
vp = lvp->vp;
- TRACE(("poplocalvar %s", vp ? vp->text : "-"));
+ TRACE(("poplocalvar %s\n", vp ? vp->text : "-"));
if (vp == NULL) { /* $- saved */
memcpy(optlist, lvp->text, sizeof(optlist));
free((char*)lvp->text);
#define BUILTIN_REG_ASSG "6"
#define BUILTIN_SPEC_REG_ASSG "7"
-/* We do not handle [[ expr ]] bashism bash-compatibly,
- * we make it a synonym of [ expr ].
- * Basically, word splitting and pathname expansion should NOT be performed
- * Examples:
- * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
- * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
- * Additional operators:
- * || and && should work as -o and -a
- * =~ regexp match
- * Apart from the above, [[ expr ]] should work as [ expr ]
- */
-
/* Stubs for calling non-FAST_FUNC's */
+#if ENABLE_ASH_BUILTIN_ECHO
static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
+#endif
+#if ENABLE_ASH_BUILTIN_PRINTF
static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
+#endif
+#if ENABLE_ASH_BUILTIN_TEST
static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
+#endif
/* Keep these in proper order since it is searched via bsearch() */
static const struct builtincmd builtintab[] = {
* as POSIX mandates */
return back_exitstatus;
}
-static void FAST_FUNC
+static void
evalcommand(union node *cmd, int flags)
{
static const struct builtincmd null_bltin = {
if (i == EXINT)
exit_status = 128 + SIGINT;
if (i == EXSIG)
- exit_status = 128 + pendingsig;
+ exit_status = 128 + pending_sig;
exitstatus = exit_status;
if (i == EXINT || spclbltin > 0) {
raise:
exitstatus |= ferror(stdout);
clearerr(stdout);
commandname = savecmdname;
-// exsig = 0;
exception_handler = savehandler;
return i;
int n = argv[1] ? number(argv[1]) : 1;
if (n <= 0)
- ash_msg_and_raise_error(illnum, argv[1]);
+ ash_msg_and_raise_error(msg_illnum, argv[1]);
if (n > loopnest)
n = loopnest;
if (n > 0) {
* 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
* or we are reading from a string so we can't refill the buffer,
* return EOF.
- * 3) If the is more stuff in this buffer, use it else call read to fill it.
+ * 3) If there is more stuff in this buffer, use it else call read to fill it.
* 4) Process input up to the next newline, deleting nul characters.
*/
//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
setstackmark(&smark);
mpath = mpathset() ? mpathval() : mailval();
for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
- p = padvance(&mpath, nullstr);
+ p = path_advance(&mpath, nullstr);
if (p == NULL)
break;
if (*p == '\0')
static struct nodelist *backquotelist;
static union node *redirnode;
static struct heredoc *heredoc;
-/*
- * NEOF is returned by parsecmd when it encounters an end of file. It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
- */
-#define NEOF ((union node *)&tokpushback)
/*
* Called when an unexpected token is read during the parse. The argument
TRACE(("Here document %d\n", n->type));
if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
raise_error_syntax("illegal eof marker for << redirection");
- rmescapes(wordtext);
+ rmescapes(wordtext, 0);
here->eofmark = wordtext;
here->next = NULL;
if (heredoclist == NULL)
}
/*
- * Read and parse a command. Returns NEOF on end of file. (NULL is a
- * valid parse tree indicating a blank line.)
+ * Read and parse a command. Returns NODE_EOF on end of file.
+ * (NULL is a valid parse tree indicating a blank line.)
*/
static union node *
parsecmd(int interact)
needprompt = 0;
t = readtoken();
if (t == TEOF)
- return NEOF;
+ return NODE_EOF;
if (t == TNL)
return NULL;
tokpushback = 1;
setstackmark(&smark);
skip = 0;
- while ((n = parsecmd(0)) != NEOF) {
+ while ((n = parsecmd(0)) != NODE_EOF) {
evaltree(n, 0);
popstackmark(&smark);
skip = evalskip;
}
n = parsecmd(inter);
#if DEBUG
- showtree(n);
+ if (DEBUG > 2 && debug && (n != NODE_EOF))
+ showtree(n);
#endif
- if (n == NEOF) {
+ if (n == NODE_EOF) {
if (!top || numeof >= 50)
break;
if (!stoppedjobs()) {
goto try_cur_dir;
}
- while ((fullname = padvance(&path, name)) != NULL) {
+ while ((fullname = path_advance(&path, name)) != NULL) {
try_cur_dir:
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
/*
*/
return fullname;
}
- stunalloc(fullname);
+ if (fullname != name)
+ stunalloc(fullname);
}
/* not found in the PATH */
e = ENOENT;
idx = -1;
loop:
- while ((fullname = padvance(&path, name)) != NULL) {
+ while ((fullname = path_advance(&path, name)) != NULL) {
stunalloc(fullname);
/* NB: code below will still use fullname
* despite it being "unallocated" */
unsigned col;
unsigned i;
- out1fmt("\n"
+ out1fmt(
"Built-in commands:\n"
"------------------\n");
for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
mask = 0;
do {
if (*ap >= '8' || *ap < '0')
- ash_msg_and_raise_error(illnum, argv[1]);
+ ash_msg_and_raise_error(msg_illnum, argv[1]);
mask = (mask << 3) + (*ap - '0');
} while (*++ap != '\0');
umask(mask);