#undef JOBS
#endif
-#if JOBS
+#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
#include <termios.h>
#endif
})
#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
-#define setjmp(jmploc) _setjmp(jmploc)
-#define longjmp(jmploc, val) _longjmp(jmploc, val)
-#endif
-
/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
struct strlist {
#endif
static int dotcmd(int, char **);
static int evalcmd(int, char **);
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+static int echocmd(int, char **);
+#endif
static int execcmd(int, char **);
static int exitcmd(int, char **);
static int exportcmd(int, char **);
/* unsigned flags; */
};
-#ifdef CONFIG_ASH_CMDCMD
-# ifdef JOBS
-# ifdef CONFIG_ASH_ALIAS
-# define COMMANDCMD (builtincmd + 7)
-# define EXECCMD (builtincmd + 10)
-# else
-# define COMMANDCMD (builtincmd + 6)
-# define EXECCMD (builtincmd + 9)
-# endif
-# else /* ! JOBS */
-# ifdef CONFIG_ASH_ALIAS
-# define COMMANDCMD (builtincmd + 6)
-# define EXECCMD (builtincmd + 9)
-# else
-# define COMMANDCMD (builtincmd + 5)
-# define EXECCMD (builtincmd + 8)
-# endif
-# endif /* JOBS */
-#else /* ! CONFIG_ASH_CMDCMD */
-# ifdef JOBS
-# ifdef CONFIG_ASH_ALIAS
-# define EXECCMD (builtincmd + 9)
-# else
-# define EXECCMD (builtincmd + 8)
-# endif
-# else /* ! JOBS */
-# ifdef CONFIG_ASH_ALIAS
-# define EXECCMD (builtincmd + 8)
-# else
-# define EXECCMD (builtincmd + 7)
-# endif
-# endif /* JOBS */
-#endif /* CONFIG_ASH_CMDCMD */
+
+#define COMMANDCMD (builtincmd + 5 + \
+ ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
+#define EXECCMD (builtincmd + 7 + \
+ ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
+ ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
#define BUILTIN_NOSPEC "0"
#define BUILTIN_SPECIAL "1"
{ BUILTIN_REGULAR "command", commandcmd },
#endif
{ BUILTIN_SPEC_REG "continue", breakcmd },
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+ { BUILTIN_REGULAR "echo", echocmd },
+#endif
{ BUILTIN_SPEC_REG "eval", evalcmd },
{ BUILTIN_SPEC_REG "exec", execcmd },
{ BUILTIN_SPEC_REG "exit", exitcmd },
{
char **envp;
char ppid[32];
+ const char *p;
+ struct stat st1, st2;
initvar();
- for (envp = environ ; *envp ; envp++) {
+ for (envp = environ ; envp && *envp ; envp++) {
if (strchr(*envp, '=')) {
setvareq(*envp, VEXPORT|VTEXTFIXED);
}
snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
setvar("PPID", ppid, 0);
- setpwd(0, 0);
+
+ p = lookupvar("PWD");
+ if (p)
+ if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
+ st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ p = 0;
+ setpwd(p, 0);
}
}
#define bflag optlist[11]
#define uflag optlist[12]
#define qflag optlist[13]
+#define viflag optlist[14]
#ifdef DEBUG
-#define nolog optlist[14]
-#define debug optlist[15]
-#define NOPTS 16
-#else
-#define NOPTS 14
+#define nolog optlist[15]
+#define debug optlist[16]
+#endif
+
+#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
+#define setvimode(on) viflag = 0 /* forcibly keep the option off */
#endif
/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
-static const char *const optletters_optnames[NOPTS] = {
+static const char *const optletters_optnames[] = {
"e" "errexit",
"f" "noglob",
"I" "ignoreeof",
"b" "notify",
"u" "nounset",
"q" "quietprofile",
+ "\0" "vi",
#ifdef DEBUG
"\0" "nolog",
"\0" "debug",
#define optletters(n) optletters_optnames[(n)][0]
#define optnames(n) (&optletters_optnames[(n)][1])
+#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
static char optlist[NOPTS];
dest = bltinlookup(homestr);
else if (dest[0] == '-' && dest[1] == '\0') {
dest = bltinlookup("OLDPWD");
- if ( !dest ) goto out;
flags |= CD_PRINT;
- goto step7;
}
if (!dest)
dest = nullstr;
static void
exvwarning(const char *msg, va_list ap)
{
- FILE *errs;
- const char *name;
- const char *fmt;
+ FILE *errs;
- errs = stderr;
- name = arg0;
- fmt = "%s: ";
- if (commandname) {
- name = commandname;
- fmt = "%s: %d: ";
- }
- fprintf(errs, fmt, name, startlinno);
- vfprintf(errs, msg, ap);
- outcslow('\n', errs);
+ errs = stderr;
+ fprintf(errs, "%s: ", arg0);
+ if (commandname) {
+ const char *fmt = (!iflag || parsefile->fd) ?
+ "%s: %d: " : "%s: ";
+ fprintf(errs, fmt, commandname, startlinno);
+ }
+ vfprintf(errs, msg, ap);
+ outcslow('\n', errs);
}
/*
return *q == '=';
}
+#ifdef CONFIG_ASH_EXPAND_PRMT
+static const char *expandstr(const char *ps);
+#else
+#define expandstr(s) s
+#endif
+
/*
* Execute a simple command.
*/
struct strlist **spp;
spp = arglist.lastp;
- if (pseudovarflag && isassignment(argp->narg.text))
+ if (pseudovarflag && isassignment(argp->narg.text))
expandarg(argp, &arglist, EXP_VARTILDE);
else
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
const char *p = " %s";
p++;
- dprintf(preverrout_fd, p, ps4val());
+ dprintf(preverrout_fd, p, expandstr(ps4val()));
sp = varlist.list;
for(n = 0; n < 2; n++) {
ifsfirst.next = NULL;
ifslastp = NULL;
argstr(arg->narg.text, flag);
+ p = _STPUTC('\0', expdest);
+ expdest = p - 1;
if (arglist == NULL) {
return; /* here document expanded */
}
- STPUTC('\0', expdest);
- p = grabstackstr(expdest);
+ p = grabstackstr(p);
exparg.lastp = &exparg.list;
/*
* TODO - EXP_REDIR
size_t partlen;
partlen = strlen(p);
-
len += partlen;
- if (len > partlen && sep) {
+
+ if (!(subtype == VSPLUS || subtype == VSLENGTH))
+ memtodest(p, partlen, syntax, quotes);
+
+ if (*ap && sep) {
char *q;
len++;
STPUTC(sep, q);
expdest = q;
}
-
- if (!(subtype == VSPLUS || subtype == VSLENGTH))
- memtodest(p, partlen, syntax, quotes);
}
return len;
case '0':
if (**argv == '%') {
jp = getjob(*argv, 0);
pid = -jp->ps[0].pid;
- } else
- pid = number(*argv);
+ } else {
+ pid = **argv == '-' ?
+ -number(*argv + 1) : number(*argv);
+ }
if (kill(pid, signo) != 0) {
- sh_warnx("%m\n");
+ sh_warnx("(%d) - %m", pid);
i = 1;
}
} while (*++argv);
char *nextc;
int subtype = 0;
int quoted = 0;
- static const char *const vstype[16] = {
- nullstr, "}", "-", "+", "?", "=",
- "%", "%%", "#", "##", nullstr
+ static const char vstype[VSTYPE + 1][4] = {
+ "", "}", "-", "+", "?", "=",
+ "%", "%%", "#", "##"
};
-
nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
p = s;
while ((c = *p++) != 0) {
goto dostr;
break;
case CTLENDVAR:
+ str = "\"}" + !(quoted & 1);
quoted >>= 1;
subtype = 0;
- if (quoted & 1) {
- str = "\"}";
- goto dostr;
- }
- c = '}';
- break;
+ goto dostr;
case CTLBACKQ:
str = "$(...)";
goto dostr;
case '=':
if (subtype == 0)
break;
+ if ((subtype & VSTYPE) != VSNORMAL)
+ quoted <<= 1;
str = vstype[subtype & VSTYPE];
if (subtype & VSNUL)
c = ':';
else
- c = *str++;
- if (c != '}')
- quoted <<= 1;
+ goto checkstr;
break;
case '\'':
case '\\':
break;
}
USTPUTC(c, nextc);
+checkstr:
if (!str)
continue;
dostr:
for (sp = cmdenviron; sp; sp = sp->next)
setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
- if (argc >= 2) { /* That's what SVR2 does */
+ if (argc >= 2) { /* That's what SVR2 does */
char *fullname;
struct stackmark smark;
/* NOTREACHED */
}
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+static int
+echocmd(int argc, char **argv)
+{
+ return bb_echo(argc, argv);
+}
+#endif
/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
/*
#endif
setinteractive(iflag);
setjobctl(mflag);
+ setvimode(viflag);
}
static inline void
while (here) {
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
here->eofmark, here->striptabs);
}
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
}
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
for (;;) {
if (needprompt) {
setprompt(2);
- needprompt = 0;
}
switch (pc = pgetc()) {
case '`':
* should be added here.
*/
+#ifdef CONFIG_ASH_EXPAND_PRMT
+static const char *
+expandstr(const char *ps)
+{
+ union node n;
+
+ /* XXX Fix (char *) cast. */
+ setinputstring((char *)ps);
+ readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
+ popfile();
+
+ n.narg.type = NARG;
+ n.narg.next = NULL;
+ n.narg.text = wordtext;
+ n.narg.backquote = backquotelist;
+
+ expandarg(&n, NULL, 0);
+ return stackblock();
+}
+#endif
+
static void setprompt(int whichprompt)
{
const char *prompt;
+#ifdef CONFIG_ASH_EXPAND_PRMT
+ struct stackmark smark;
+#endif
+
+ needprompt = 0;
switch (whichprompt) {
case 1:
default: /* 0 */
prompt = nullstr;
}
- putprompt(prompt);
+#ifdef CONFIG_ASH_EXPAND_PRMT
+ setstackmark(&smark);
+ stalloc(stackblocksize());
+#endif
+ putprompt(expandstr(prompt));
+#ifdef CONFIG_ASH_EXPAND_PRMT
+ popstackmark(&smark);
+#endif
}
INTOFF;
p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
*p++ = '\0';
- if (vallen) {
+ if (val) {
p[-1] = '=';
p = mempcpy(p, val, vallen);
}
char *prompt;
const char *ifs;
char *p;
-#if defined(CONFIG_ASH_TIMEOUT)
- fd_set set;
- int timeout;
- struct timeval timeout_struct;
- struct termios tty, old_tty;
-#endif
int startword;
int status;
int i;
+#if defined(CONFIG_ASH_READ_NCHARS)
+ int nch_flag = 0;
+ int nchars = 0;
+ int silent = 0;
+ struct termios tty, old_tty;
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+ fd_set set;
+ struct timeval ts;
+
+ ts.tv_sec = ts.tv_usec = 0;
+#endif
rflag = 0;
prompt = NULL;
-#if defined(CONFIG_ASH_TIMEOUT)
- timeout = 0;
-
+#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
+ while ((i = nextopt("p:rt:n:s")) != '\0')
+#elif defined(CONFIG_ASH_READ_NCHARS)
+ while ((i = nextopt("p:rn:s")) != '\0')
+#elif defined(CONFIG_ASH_READ_TIMEOUT)
while ((i = nextopt("p:rt:")) != '\0')
#else
while ((i = nextopt("p:r")) != '\0')
#endif
{
- if (i == 'p')
+ switch(i) {
+ case 'p':
prompt = optionarg;
- else if (i == 'r')
- rflag = 1;
-#if defined(CONFIG_ASH_TIMEOUT)
- else
- timeout = atoi(optionarg);
+ break;
+#if defined(CONFIG_ASH_READ_NCHARS)
+ case 'n':
+ nchars = strtol(optionarg, &p, 10);
+ if (*p)
+ error("invalid count");
+ nch_flag = (nchars > 0);
+ break;
+ case 's':
+ silent = 1;
+ break;
#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+ case 't':
+ ts.tv_sec = strtol(optionarg, &p, 10);
+ ts.tv_usec = 0;
+ if (*p == '.') {
+ char *p2;
+ if (*++p) {
+ int scale;
+ ts.tv_usec = strtol(p, &p2, 10);
+ if (*p2)
+ error("invalid timeout");
+ scale = p2 - p;
+ /* normalize to usec */
+ if (scale > 6)
+ error("invalid timeout");
+ while (scale++ < 6)
+ ts.tv_usec *= 10;
+ }
+ } else if (*p) {
+ error("invalid timeout");
+ }
+ if ( ! ts.tv_sec && ! ts.tv_usec)
+ error("invalid timeout");
+ break;
+#endif
+ case 'r':
+ rflag = 1;
+ break;
+ default:
+ break;
+ }
}
if (prompt && isatty(0)) {
out2str(prompt);
error("arg count");
if ((ifs = bltinlookup("IFS")) == NULL)
ifs = defifs;
-#if defined(CONFIG_ASH_TIMEOUT)
- c = 0;
-#endif
- status = 0;
- startword = 1;
- backslash = 0;
-
- STARTSTACKSTR(p);
-#if defined(CONFIG_ASH_TIMEOUT)
- if (timeout > 0) {
+#if defined(CONFIG_ASH_READ_NCHARS)
+ if (nch_flag || silent) {
tcgetattr(0, &tty);
old_tty = tty;
+ if (nch_flag) {
+ tty.c_lflag &= ~ICANON;
+ tty.c_cc[VMIN] = nchars;
+ }
+ if (silent) {
+ tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
- /* cfmakeraw(...) disables too much; we just do this instead. */
- tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+ }
tcsetattr(0, TCSANOW, &tty);
-
+ }
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+ if (ts.tv_sec || ts.tv_usec) {
FD_ZERO (&set);
FD_SET (0, &set);
- timeout_struct.tv_sec = timeout;
- timeout_struct.tv_usec = 0;
-
- if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
- {
- read(0, &c, 1);
- if(c == '\n' || c == 4) /* Handle newlines and EOF */
- i = 0; /* Don't read further... */
- else
- STPUTC(c, p); /* Keep reading... */
+ i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
+ if (!i) {
+#if defined(CONFIG_ASH_READ_NCHARS)
+ if (nch_flag)
+ tcsetattr(0, TCSANOW, &old_tty);
+#endif
+ return 1;
}
- tcsetattr(0, TCSANOW, &old_tty);
-
- /* Echo the character so the user knows it was read...
- Yes, this can be done by setting the ECHO flag, but that
- echoes ^D and other control characters at this state */
- if(c != 0)
- write(1, &c, 1);
-
- } else
- i = 1;
-
- for (;i == 1;)
+ }
+#endif
+ status = 0;
+ startword = 1;
+ backslash = 0;
+ STARTSTACKSTR(p);
+#if defined(CONFIG_ASH_READ_NCHARS)
+ while (!nch_flag || nchars--)
#else
for (;;)
#endif
STPUTC(c, p);
}
}
+#if defined(CONFIG_ASH_READ_NCHARS)
+ if (nch_flag || silent)
+ tcsetattr(0, TCSANOW, &old_tty);
+#endif
+
STACKSTRNUL(p);
/* Remove trailing blanks */
while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
goto err;
}
/* save to shell variable */
- snprintf(buf, sizeof(buf), "%lld", (long long) rez);
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+ snprintf(buf, sizeof(buf), "%lld", rez);
+#else
+ snprintf(buf, sizeof(buf), "%ld", rez);
+#endif
setvar(numptr_m1->var, buf, 0);
/* after saving, make previous value for v++ or v-- */
if(op == TOK_POST_INC)
continue;
} else if (is_digit(arithval)) {
numstackptr->var = NULL;
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
numstackptr->val = strtoll(expr, (char **) &expr, 0);
+#else
+ numstackptr->val = strtol(expr, (char **) &expr, 0);
+#endif
goto num;
}
for(p = op_tokens; ; p++) {