-/* $OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $ */
-/* $OpenBSD: c_sh.c,v 1.45 2014/08/27 08:26:04 jmc Exp $ */
+/* $OpenBSD: c_ksh.c,v 1.37 2015/09/10 22:48:58 nicm Exp $ */
+/* $OpenBSD: c_sh.c,v 1.46 2015/07/20 20:46:24 guenther Exp $ */
/* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */
/* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2010, 2011, 2012, 2013, 2014
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
#endif
#endif
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.258 2014/09/03 19:55:51 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.305 2016/08/01 21:38:02 tg Exp $");
#if HAVE_KILLPG
/*
static int c_suspend(const char **);
#endif
+static int do_whence(const char **, int, bool, bool);
+
/* getn() that prints error */
static int
bi_getn(const char *as, int *ai)
int rv;
if (!(rv = getn(as, ai)))
- bi_errorf("%s: %s", as, "bad number");
+ bi_errorf(Tf_sD_s, as, "bad number");
return (rv);
}
* A leading * means a POSIX special builtin.
*/
const struct builtin mkshbuiltins[] = {
- {"*=.", c_dot},
+ {Tsgdot, c_dot},
{"*=:", c_true},
- {"[", c_test},
+ {Tbracket, c_test},
/* no =: AT&T manual wrong */
{Talias, c_alias},
{"*=break", c_brkcont},
{Tgbuiltin, c_builtin},
- {"cat", c_cat},
- {"cd", c_cd},
+ {Tbcat, c_cat},
+ {Tcd, c_cd},
/* dash compatibility hack */
{"chdir", c_cd},
- {"command", c_command},
+ {Tcommand, c_command},
{"*=continue", c_brkcont},
{"echo", c_print},
{"*=eval", c_eval},
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
{Tsgexport, c_typeset},
- {"false", c_false},
+ {Tfalse, c_false},
{"fc", c_fc},
- {"getopts", c_getopts},
+ {Tgetopts, c_getopts},
{"=global", c_typeset},
- {"jobs", c_jobs},
+ {Tjobs, c_jobs},
{"kill", c_kill},
{"let", c_let},
{"let]", c_let},
{"print", c_print},
{"pwd", c_pwd},
- {"read", c_read},
+ {Tread, c_read},
{Tsgreadonly, c_typeset},
- {"realpath", c_realpath},
- {"rename", c_rename},
+ {"!realpath", c_realpath},
+ {"~rename", c_rename},
{"*=return", c_exitreturn},
{Tsgset, c_set},
{"*=shift", c_shift},
+ {"=source", c_dot},
#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
- {"suspend", c_suspend},
+ {Tsuspend, c_suspend},
#endif
{"test", c_test},
{"*=times", c_times},
{"*=trap", c_trap},
- {"true", c_true},
- {T_typeset, c_typeset},
+ {Ttrue, c_true},
+ {Tgtypeset, c_typeset},
{"ulimit", c_ulimit},
{"umask", c_umask},
{Tunalias, c_unalias},
- {Tsgunset, c_unset},
+ {"*=unset", c_unset},
{"=wait", c_wait},
{"whence", c_whence},
#ifndef MKSH_UNEMPLOYED
- {"bg", c_fgbg},
- {"fg", c_fgbg},
+ {Tbg, c_fgbg},
+ {Tfg, c_fgbg},
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
{"bind", c_bind},
{"mknod", c_mknod},
#endif
#ifdef MKSH_PRINTF_BUILTIN
- {"printf", c_printf},
+ {"~printf", c_printf},
#endif
#if HAVE_SELECT
{"sleep", c_sleep},
/* alias to "true" for historical reasons */
{"domainname", c_true},
#endif
+#ifdef __OS2__
+ {Textproc, c_true},
+#endif
{NULL, (int (*)(const char **))NULL}
};
static Test_op ptest_isa(Test_env *, Test_meta);
static const char *ptest_getopnd(Test_env *, Test_op, bool);
static void ptest_error(Test_env *, int, const char *);
-static char *kill_fmt_entry(char *, size_t, unsigned int, const void *);
+static void kill_fmt_entry(char *, size_t, unsigned int, const void *);
static void p_time(struct shf *, bool, long, int, int,
const char *, const char *);
wp += builtin_opt.optind;
if (wp[0]) {
- bi_errorf("too many arguments");
+ bi_errorf(Ttoo_many_args);
return (1);
}
p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) :
if (p && access(p, R_OK) < 0)
p = NULL;
if (!p && !(p = allocd = ksh_get_wd())) {
- bi_errorf("%s: %s", "can't determine current directory",
+ bi_errorf(Tf_sD_s, "can't determine current directory",
cstrerror(errno));
return (1);
}
- shprintf("%s\n", p);
+ shprintf(Tf_sN, p);
afree(allocd, ATEMP);
return (0);
}
int
c_print(const char **wp)
{
-#define PO_NL BIT(0) /* print newline */
-#define PO_EXPAND BIT(1) /* expand backslash sequences */
-#define PO_PMINUSMINUS BIT(2) /* print a -- argument */
-#define PO_HIST BIT(3) /* print to history instead of stdout */
-#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
int fd = 1, c;
- int flags = PO_EXPAND | PO_NL;
- const char *s, *emsg;
+ const char *s;
XString xs;
char *xp;
+ /* print newline; expand backslash sequences */
+ bool po_nl = true, po_exp = true;
+ /* print to history instead of file descriptor / stdout */
+ bool po_hist = false;
+ /* print characters */
+ bool po_char = false;
+ char ts[4];
if (wp[0][0] == 'e') {
- /* echo builtin */
- wp++;
+ /* "echo" builtin */
+ ++wp;
#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
if (Flag(FSH)) {
/*
* one that supports -e but does not enable it by
* default
*/
- flags = PO_NL;
+ po_exp = false;
}
#endif
if (Flag(FPOSIX) ||
Flag(FAS_BUILTIN)) {
/* Debian Policy 10.4 compliant "echo" builtin */
if (*wp && !strcmp(*wp, "-n")) {
- /* we recognise "-n" only as the first arg */
- flags = 0;
- wp++;
- } else
- /* otherwise, we print everything as-is */
- flags = PO_NL;
+ /* recognise "-n" only as the first arg */
+ po_nl = false;
+ ++wp;
+ }
+ /* print everything as-is */
+ po_exp = false;
} else {
- int nflags = flags;
+ bool new_exp = po_exp, new_nl = po_nl;
/**
* a compromise between sysV and BSD echo commands:
* quences are enabled by default.
*/
- while ((s = *wp) && *s == '-' && s[1]) {
- while (*++s)
- if (*s == 'n')
- nflags &= ~PO_NL;
- else if (*s == 'e')
- nflags |= PO_EXPAND;
- else if (*s == 'E')
- nflags &= ~PO_EXPAND;
- else
- /*
- * bad option: don't use
- * nflags, print argument
- */
- break;
-
- if (*s)
- break;
- wp++;
- flags = nflags;
+ print_tradparse_arg:
+ if ((s = *wp) && *s++ == '-' && *s) {
+ print_tradparse_ch:
+ switch ((c = *s++)) {
+ case 'E':
+ new_exp = false;
+ goto print_tradparse_ch;
+ case 'e':
+ new_exp = true;
+ goto print_tradparse_ch;
+ case 'n':
+ new_nl = false;
+ goto print_tradparse_ch;
+ case '\0':
+ po_exp = new_exp;
+ po_nl = new_nl;
+ ++wp;
+ goto print_tradparse_arg;
+ }
}
}
} else {
- int optc;
- const char *opts = "Rnprsu,";
-
- while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
- switch (optc) {
- case 'R':
- /* fake BSD echo command */
- flags |= PO_PMINUSMINUS;
- flags &= ~PO_EXPAND;
- opts = "ne";
+ /* "print" builtin */
+ const char *opts = "AnpRrsu,";
+ const char *emsg;
+ /* print a "--" argument */
+ bool po_pminusminus = false;
+
+ while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
+ switch (c) {
+ case 'A':
+ po_char = true;
break;
case 'e':
- flags |= PO_EXPAND;
+ po_exp = true;
break;
case 'n':
- flags &= ~PO_NL;
+ po_nl = false;
break;
case 'p':
if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
- bi_errorf("%s: %s", "-p", emsg);
+ bi_errorf(Tf_coproc, emsg);
return (1);
}
break;
+ case 'R':
+ /* fake BSD echo command */
+ po_pminusminus = true;
+ po_exp = false;
+ opts = "en";
+ break;
case 'r':
- flags &= ~PO_EXPAND;
+ po_exp = false;
break;
case 's':
- flags |= PO_HIST;
+ po_hist = true;
break;
case 'u':
if (!*(s = builtin_opt.optarg))
fd = 0;
else if ((fd = check_fd(s, W_OK, &emsg)) < 0) {
- bi_errorf("%s: %s: %s", "-u", s, emsg);
+ bi_errorf("-u%s: %s", s, emsg);
return (1);
}
break;
}
if (!(builtin_opt.info & GI_MINUSMINUS)) {
- /* treat a lone - like -- */
+ /* treat a lone "-" like "--" */
if (wp[builtin_opt.optind] &&
ksh_isdash(wp[builtin_opt.optind]))
builtin_opt.optind++;
- } else if (flags & PO_PMINUSMINUS)
- builtin_opt.optind--;
+ } else if (po_pminusminus)
+ builtin_opt.optind--;
wp += builtin_opt.optind;
}
Xinit(xs, xp, 128, ATEMP);
- while (*wp != NULL) {
+ if (*wp != NULL && po_char) {
+ mksh_ari_t wc;
+
+ do {
+ if (!evaluate(*wp, &wc, KSH_RETURN_ERROR, true))
+ return (1);
+ Xcheck(xs, xp);
+ if (UTFMODE) {
+ ts[utf_wctomb(ts, wc)] = 0;
+ c = 0;
+ do {
+ Xput(xs, xp, ts[c]);
+ } while (ts[++c]);
+ } else
+ Xput(xs, xp, wc & 0xFF);
+ } while (*++wp);
+ } else if (*wp != NULL) {
+ print_read_arg:
s = *wp;
while ((c = *s++) != '\0') {
Xcheck(xs, xp);
- if ((flags & PO_EXPAND) && c == '\\') {
+ if (po_exp && c == '\\') {
s_ptr = s;
c = unbksl(false, s_get, s_put);
s = s_ptr;
/* rejected by generic function */
switch ((c = *s++)) {
case 'c':
- flags &= ~PO_NL;
+ po_nl = false;
/* AT&T brain damage */
continue;
case '\0':
- s--;
+ --s;
c = '\\';
break;
default:
}
} else if ((unsigned int)c > 0xFF) {
/* generic function returned Unicode */
- char ts[4];
-
ts[utf_wctomb(ts, c - 0x100)] = 0;
- for (c = 0; ts[c]; ++c)
+ c = 0;
+ do {
Xput(xs, xp, ts[c]);
+ } while (ts[++c]);
continue;
}
}
Xput(xs, xp, c);
}
- if (*++wp != NULL)
+ if (*++wp != NULL) {
Xput(xs, xp, ' ');
+ goto print_read_arg;
+ }
}
- if (flags & PO_NL)
+ if (po_nl)
Xput(xs, xp, '\n');
- if (flags & PO_HIST) {
+ c = 0;
+ if (po_hist) {
Xput(xs, xp, '\0');
- histsave(&source->line, Xstring(xs, xp), true, false);
+ histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
Xfree(xs, xp);
} else {
- int len = Xlength(xs, xp);
+ size_t len = Xlength(xs, xp);
+ bool po_coproc = false;
int opipe = 0;
/*
* not enough).
*/
if (coproc.write >= 0 && coproc.write == fd) {
- flags |= PO_COPROC;
+ po_coproc = true;
opipe = block_pipe();
}
- for (s = Xstring(xs, xp); len > 0; ) {
- if ((c = write(fd, s, len)) < 0) {
- if (flags & PO_COPROC)
- restore_pipe(opipe);
+
+ s = Xstring(xs, xp);
+ while (len > 0) {
+ ssize_t nwritten;
+
+ if ((nwritten = write(fd, s, len)) < 0) {
if (errno == EINTR) {
- /* allow user to ^C out */
+ if (po_coproc)
+ restore_pipe(opipe);
+ /* give the user a chance to ^C out */
intrcheck();
- if (flags & PO_COPROC)
+ /* interrupted, try again */
+ if (po_coproc)
opipe = block_pipe();
continue;
}
- return (1);
+ c = 1;
+ break;
}
- s += c;
- len -= c;
+ s += nwritten;
+ len -= nwritten;
}
- if (flags & PO_COPROC)
+ if (po_coproc)
restore_pipe(opipe);
}
- return (0);
+ return (c);
}
static int
int
c_whence(const char **wp)
{
- struct tbl *tp;
- const char *id;
- bool pflag = false, vflag = false, Vflag = false;
- int rv = 0, optc, fcflags;
- bool iam_whence = wp[0][0] == 'w';
- const char *opts = iam_whence ? "pv" : "pvV";
+ int optc;
+ bool pflag = false, vflag = false;
- while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
+ while ((optc = ksh_getopt(wp, &builtin_opt, Tpv)) != -1)
switch (optc) {
case 'p':
pflag = true;
case 'v':
vflag = true;
break;
+ case '?':
+ return (1);
+ }
+ wp += builtin_opt.optind;
+
+ return (do_whence(wp, pflag ? FC_PATH :
+ FC_BI | FC_FUNC | FC_PATH | FC_WHENCE, vflag, false));
+}
+
+/* note: command without -vV is dealt with in comexec() */
+int
+c_command(const char **wp)
+{
+ int optc, fcflags = FC_BI | FC_FUNC | FC_PATH | FC_WHENCE;
+ bool vflag = false;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, TpVv)) != -1)
+ switch (optc) {
+ case 'p':
+ fcflags |= FC_DEFPATH;
+ break;
case 'V':
- Vflag = true;
+ vflag = true;
+ break;
+ case 'v':
+ vflag = false;
break;
case '?':
return (1);
}
wp += builtin_opt.optind;
- fcflags = FC_BI | FC_PATH | FC_FUNC;
- if (!iam_whence) {
- /* Note that -p on its own is deal with in comexec() */
- if (pflag)
- fcflags |= FC_DEFPATH;
- /*
- * Convert command options to whence options - note that
- * command -pV uses a different path search than whence -v
- * or whence -pv. This should be considered a feature.
- */
- vflag = Vflag;
- }
- if (pflag)
- fcflags &= ~(FC_BI | FC_FUNC);
+ return (do_whence(wp, fcflags, vflag, true));
+}
- while ((vflag || rv == 0) && (id = *wp++) != NULL) {
- uint32_t h = 0;
+static int
+do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
+{
+ uint32_t h;
+ int rv = 0;
+ struct tbl *tp;
+ const char *id;
+ while ((vflag || rv == 0) && (id = *wp++) != NULL) {
+ h = hash(id);
tp = NULL;
- if ((iam_whence || vflag) && !pflag)
- tp = ktsearch(&keywords, id, h = hash(id));
- if (!tp && !pflag) {
- tp = ktsearch(&aliases, id, h ? h : hash(id));
+
+ if (fcflags & FC_WHENCE)
+ tp = ktsearch(&keywords, id, h);
+ if (!tp && (fcflags & FC_WHENCE)) {
+ tp = ktsearch(&aliases, id, h);
if (tp && !(tp->flag & ISSET))
tp = NULL;
}
if (!tp)
tp = findcom(id, fcflags);
- if (vflag || (tp->type != CALIAS && tp->type != CEXEC &&
- tp->type != CTALIAS))
- shf_puts(id, shl_stdout);
- if (vflag)
- switch (tp->type) {
- case CKEYWD:
- case CALIAS:
- case CFUNC:
- case CSHELL:
- shf_puts(" is a", shl_stdout);
- break;
- }
switch (tp->type) {
+ case CSHELL:
+ case CFUNC:
case CKEYWD:
- if (vflag)
- shf_puts(" reserved word", shl_stdout);
+ shf_puts(id, shl_stdout);
break;
- case CALIAS:
+ }
+
+ switch (tp->type) {
+ case CSHELL:
if (vflag)
- shprintf("n %s%s for ",
- (tp->flag & EXPORT) ? "exported " : null,
- Talias);
- if (!iam_whence && !vflag)
- shprintf("%s %s=", Talias, id);
- print_value_quoted(shl_stdout, tp->val.s);
+ shprintf(" is a %sshell %s",
+ (tp->flag & SPEC_BI) ? "special " : "",
+ Tbuiltin);
break;
case CFUNC:
if (vflag) {
+ shf_puts(" is a", shl_stdout);
if (tp->flag & EXPORT)
shf_puts("n exported", shl_stdout);
if (tp->flag & TRACE)
shf_puts(T_function, shl_stdout);
}
break;
- case CSHELL:
- if (vflag)
- shprintf("%s %s %s",
- (tp->flag & SPEC_BI) ? " special" : null,
- "shell", Tbuiltin);
- break;
- case CTALIAS:
case CEXEC:
+ case CTALIAS:
if (tp->flag & ISSET) {
if (vflag) {
- shf_puts(" is ", shl_stdout);
+ shprintf("%s is ", id);
if (tp->type == CTALIAS)
shprintf("a tracked %s%s for ",
(tp->flag & EXPORT) ?
- "exported " : null,
+ "exported " : "",
Talias);
}
shf_puts(tp->val.s, shl_stdout);
} else {
if (vflag)
- shprintf(" %s\n", "not found");
+ shprintf(Tnot_found_s, id);
rv = 1;
}
break;
- default:
- shprintf("%s is *GOK*", id);
+ case CALIAS:
+ if (vflag) {
+ shprintf("%s is an %s%s for ", id,
+ (tp->flag & EXPORT) ? "exported " : "",
+ Talias);
+ } else if (iscommand)
+ shprintf("%s %s=", Talias, id);
+ print_value_quoted(shl_stdout, tp->val.s);
+ break;
+ case CKEYWD:
+ if (vflag)
+ shf_puts(" is a reserved word", shl_stdout);
break;
+#ifndef MKSH_SMALL
+ default:
+ bi_errorf("%s is of unknown type %d", id, tp->type);
+ return (1);
+#endif
}
if (vflag || !rv)
shf_putc('\n', shl_stdout);
return (rv);
}
-/* Deal with command -vV - command -p dealt with in comexec() */
-int
-c_command(const char **wp)
-{
- /*
- * Let c_whence do the work. Note that c_command() must be
- * a distinct function from c_whence() (tested in comexec()).
- */
- return (c_whence(wp));
-}
-
/* typeset, global, export, and readonly */
static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
if (fieldstr && !bi_getn(fieldstr, &field))
return (1);
- if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
- bi_errorf("%s: %s", "bad integer base", basestr);
- return (1);
+ if (basestr) {
+ if (!getn(basestr, &base)) {
+ bi_errorf(Tf_sD_s, "bad integer base", basestr);
+ return (1);
+ }
+ if (base < 1 || base > 36)
+ base = 10;
}
if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
shf_putc('\n', shl_stdout);
}
} else if (!typeset(wp[i], fset, fclr, field, base)) {
- bi_errorf("%s: %s", wp[i], "is not an identifier");
+ bi_errorf(Tf_sD_s, wp[i], Tnot_ident);
return (1);
}
}
/* no arguments */
if (!thing && !flag) {
if (any_set == 1) {
- shprintf("%s %s %s\n", Tset, "-A", vp->name);
+ shprintf(Tf_s_s_sN, Tset, "-A", vp->name);
any_set = 2;
}
/*
* leftadj, zerofill, etc., but POSIX says must
* be suitable for re-entry...
*/
- shprintf("%s %s", Ttypeset, "");
+ shprintf(Tf_s_s, Ttypeset, "");
if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
- shprintf("%s ", "-n");
+ shprintf(Tf__c_, 'n');
if ((vp->flag & INTEGER))
- shprintf("%s ", "-i");
+ shprintf(Tf__c_, 'i');
if ((vp->flag & EXPORT))
- shprintf("%s ", "-x");
+ shprintf(Tf__c_, 'x');
if ((vp->flag & RDONLY))
- shprintf("%s ", "-r");
+ shprintf(Tf__c_, 'r');
if ((vp->flag & TRACE))
- shprintf("%s ", "-t");
+ shprintf(Tf__c_, 't');
if ((vp->flag & LJUST))
shprintf("-L%d ", vp->u2.field);
if ((vp->flag & RJUST))
shprintf("-R%d ", vp->u2.field);
if ((vp->flag & ZEROFIL))
- shprintf("%s ", "-Z");
+ shprintf(Tf__c_, 'Z');
if ((vp->flag & LCASEV))
- shprintf("%s ", "-l");
+ shprintf(Tf__c_, 'l');
if ((vp->flag & UCASEV_AL))
- shprintf("%s ", "-u");
+ shprintf(Tf__c_, 'u');
if ((vp->flag & INT_U))
- shprintf("%s ", "-U");
+ shprintf(Tf__c_, 'U');
} else if (pflag) {
- shprintf("%s %s", istset ? Ttypeset :
+ shprintf(Tf_s_s, istset ? Ttypeset :
(flag & EXPORT) ? Texport : Treadonly, "");
}
if (any_set)
for (p = ktsort(t); (ap = *p++) != NULL; )
if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
if (pflag)
- shprintf("%s ", Talias);
+ shprintf(Tf_s_, Talias);
shf_puts(ap->name, shl_stdout);
if (prefix != '+') {
shf_putc('=', shl_stdout);
ap = ktsearch(t, alias, h);
if (ap != NULL && (ap->flag&ISSET)) {
if (pflag)
- shprintf("%s ", Talias);
+ shprintf(Tf_s_, Talias);
shf_puts(ap->name, shl_stdout);
if (prefix != '+') {
shf_putc('=', shl_stdout);
}
shf_putc('\n', shl_stdout);
} else {
- shprintf("%s %s %s\n", alias, Talias,
- "not found");
+ shprintf(Tf_s_s_sN, alias, Talias, Tnot_found);
rv = 1;
}
continue;
if (wp[1] == NULL)
/* AT&T ksh does this */
- bi_errorf("no arguments");
+ bi_errorf(Tno_args);
else
for (wp++; *wp; wp++)
if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) {
int
c_fgbg(const char **wp)
{
- bool bg = strcmp(*wp, "bg") == 0;
+ bool bg = strcmp(*wp, Tbg) == 0;
int rv = 0;
if (!Flag(FMONITOR)) {
rv = j_resume(*wp, bg);
else
rv = j_resume("%%", bg);
- return (bg ? 0 : rv);
+ /* fg returns $? of the job unless POSIX */
+ return ((bg | Flag(FPOSIX)) ? 0 : rv);
}
#endif
/* format a single kill item */
-static char *
+static void
kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
{
const struct kill_info *ki = (const struct kill_info *)arg;
ki->num_width, i,
ki->name_width, sigtraps[i].name,
sigtraps[i].mess);
- return (buf);
}
int
/* assume old style options if -digits or -UPPERCASE */
if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) ||
ksh_isupper(p[1]))) {
- if (!(t = gettrap(p + 1, false))) {
- bi_errorf("bad signal '%s'", p + 1);
+ if (!(t = gettrap(p + 1, false, false))) {
+ bi_errorf(Tbad_sig_s, p + 1);
return (1);
}
i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
lflag = true;
break;
case 's':
- if (!(t = gettrap(builtin_opt.optarg, true))) {
- bi_errorf("bad signal '%s'",
+ if (!(t = gettrap(builtin_opt.optarg,
+ true, false))) {
+ bi_errorf(Tbad_sig_s,
builtin_opt.optarg);
return (1);
}
for (; wp[i]; i++) {
if (!bi_getn(wp[i], &n))
return (1);
-#if (NSIG < 128)
- if (n > 128 && n < 128 + NSIG)
+#if (ksh_NSIG <= 128)
+ if (n > 128 && n < 128 + ksh_NSIG)
n -= 128;
#endif
- if (n > 0 && n < NSIG)
- shprintf("%s\n", sigtraps[n].name);
+ if (n > 0 && n < ksh_NSIG)
+ shprintf(Tf_sN, sigtraps[n].name);
else
- shprintf("%d\n", n);
+ shprintf(Tf_dN, n);
+ }
+ } else if (Flag(FPOSIX)) {
+ n = 1;
+ while (n < ksh_NSIG) {
+ shf_puts(sigtraps[n].name, shl_stdout);
+ shf_putc(++n == ksh_NSIG ? '\n' : ' ',
+ shl_stdout);
}
} else {
- ssize_t w, mess_cols, mess_octs;
- int j;
- struct kill_info ki;
+ ssize_t w, mess_cols = 0, mess_octs = 0;
+ int j = ksh_NSIG - 1;
+ struct kill_info ki = { 0, 0 };
- for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10)
+ do {
ki.num_width++;
- ki.name_width = mess_cols = mess_octs = 0;
- for (j = 0; j < NSIG; j++) {
+ } while ((j /= 10));
+
+ for (j = 1; j < ksh_NSIG; j++) {
w = strlen(sigtraps[j].name);
if (w > ki.name_width)
ki.name_width = w;
mess_cols = w;
}
- print_columns(shl_stdout, (unsigned int)(NSIG - 1),
+ print_columns(shl_stdout, (unsigned int)(ksh_NSIG - 1),
kill_fmt_entry, (void *)&ki,
ki.num_width + 1 + ki.name_width + 1 + mess_octs,
ki.num_width + 1 + ki.name_width + 1 + mess_cols,
if (j_kill(p, sig))
rv = 1;
} else if (!getn(p, &n)) {
- bi_errorf("%s: %s", p,
+ bi_errorf(Tf_sD_s, p,
"arguments must be jobs or process IDs");
rv = 1;
} else {
if (mksh_kill(n, sig) < 0) {
- bi_errorf("%s: %s", p, cstrerror(errno));
+ bi_errorf(Tf_sD_s, p, cstrerror(errno));
rv = 1;
}
}
getopts_reset(int val)
{
if (val >= 1) {
- ksh_getopt_reset(&user_opt, GF_NONAME | GF_PLUSOPT);
+ ksh_getopt_reset(&user_opt, GF_NONAME |
+ (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
user_opt.optind = user_opt.uoptind = val;
}
}
opts = *wp++;
if (!opts) {
- bi_errorf("missing %s argument", "options");
+ bi_errorf(Tf_sD_s, "options", Tno_args);
return (1);
}
var = *wp++;
if (!var) {
- bi_errorf("missing %s argument", "name");
+ bi_errorf(Tf_sD_s, Tname, Tno_args);
return (1);
}
if (!*var || *skip_varname(var, true)) {
- bi_errorf("%s: %s", var, "is not an identifier");
+ bi_errorf(Tf_sD_s, var, Tnot_ident);
return (1);
}
if (e->loc->next == NULL) {
- internal_warningf("%s: %s", "c_getopts", "no argv");
+ internal_warningf(Tf_sD_s, Tgetopts, Tno_args);
return (1);
}
/* Which arguments are we parsing... */
return (1);
arg = wp[builtin_opt.optind];
- if (arg) {
- evaluate(arg, &val, KSH_UNWIND_ERROR, false);
- n = val;
- } else
+ if (!arg)
n = 1;
- if (n < 0) {
- bi_errorf("%s: %s", arg, "bad number");
+ else if (!evaluate(arg, &val, KSH_RETURN_ERROR, false)) {
+ /* error already printed */
+ bi_errorfz();
+ return (1);
+ } else if (!(n = val)) {
+ /* nothing to do */
+ return (0);
+ } else if (n < 0) {
+ bi_errorf(Tf_sD_s, arg, "bad number");
return (1);
}
if (l->argc < n) {
old_umask = ~old_umask;
p = buf;
for (i = 0; i < 3; i++) {
- *p++ = "ugo"[i];
+ *p++ = Tugo[i];
*p++ = '=';
for (j = 0; j < 3; j++)
if (old_umask & (1 << (8 - (3*i + j))))
*p++ = ',';
}
p[-1] = '\0';
- shprintf("%s\n", buf);
+ shprintf(Tf_sN, buf);
} else
shprintf("%#3.3o\n", (unsigned int)old_umask);
} else {
mode_t new_umask;
if (ksh_isdigit(*cp)) {
- for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
- new_umask = new_umask * 8 + (*cp - '0');
+ new_umask = 0;
+ while (*cp >= ord('0') && *cp <= ord('7')) {
+ new_umask = new_umask * 8 + ksh_numdig(*cp);
+ ++cp;
+ }
if (*cp) {
bi_errorf("bad number");
return (1);
new_umask = old_umask;
positions = 0;
while (*cp) {
- while (*cp && vstrchr("augo", *cp))
+ while (*cp && vstrchr(Taugo, *cp))
switch (*cp++) {
case 'a':
positions |= 0111;
c_dot(const char **wp)
{
const char *file, *cp, **argv;
- int argc, i, errcode;
+ int argc, rv, errcode;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return (1);
if ((cp = wp[builtin_opt.optind]) == NULL) {
- bi_errorf("missing argument");
+ bi_errorf(Tno_args);
return (1);
}
- if ((file = search_path(cp, path, R_OK, &errcode)) == NULL) {
- bi_errorf("%s: %s", cp, cstrerror(errcode));
+ file = search_path(cp, path, R_OK, &errcode);
+ if (!file && errcode == ENOENT && wp[0][0] == 's' &&
+ search_access(cp, R_OK) == 0)
+ file = cp;
+ if (!file) {
+ bi_errorf(Tf_sD_s, cp, cstrerror(errcode));
return (1);
}
argc = 0;
argv = NULL;
}
- if ((i = include(file, argc, argv, false)) < 0) {
+ /* SUSv4: OR with a high value never written otherwise */
+ exstat |= 0x4000;
+ if ((rv = include(file, argc, argv, false)) < 0) {
/* should not happen */
- bi_errorf("%s: %s", cp, cstrerror(errno));
+ bi_errorf(Tf_sD_s, cp, cstrerror(errno));
return (1);
}
- return (i);
+ if (exstat & 0x4000)
+ /* detect old exstat, use 0 in that case */
+ rv = 0;
+ return (rv);
}
int
c_read(const char **wp)
{
#define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
- int c, fd = 0, rv = 0, lastparm = 0;
+ int c, fd = 0, rv = 0;
bool savehist = false, intoarray = false, aschars = false;
bool rawmode = false, expanding = false;
+ bool lastparmmode = false, lastparmused = false;
enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
char delim = '\n';
size_t bytesleft = 128, bytesread;
- struct tbl *vp /* FU gcc */ = NULL, *vq;
+ struct tbl *vp /* FU gcc */ = NULL, *vq = NULL;
char *cp, *allocd = NULL, *xp;
const char *ccp;
XString xs;
- ptrdiff_t xsave = 0;
+ size_t xsave = 0;
mksh_ttyst tios;
bool restore_tios = false;
+ /* to catch read -aN2 foo[i] */
+ bool subarray = false;
#if HAVE_SELECT
bool hastimeout = false;
struct timeval tv, tvlim;
if (!bi_getn(builtin_opt.optarg, &c))
return (2);
if (c == -1) {
- readmode = READALL;
+ readmode = readmode == BYTES ? READALL : UPTO;
bytesleft = 1024;
} else
bytesleft = (unsigned int)c;
break;
case 'p':
if ((fd = coproc_getfd(R_OK, &ccp)) < 0) {
- bi_errorf("%s: %s", "-p", ccp);
+ bi_errorf(Tf_coproc, ccp);
return (2);
}
break;
#if HAVE_SELECT
case 't':
if (parse_usec(builtin_opt.optarg, &tv)) {
- bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno),
+ bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno),
builtin_opt.optarg);
return (2);
}
if (!builtin_opt.optarg[0])
fd = 0;
else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
- bi_errorf("%s: %s: %s", "-u", builtin_opt.optarg, ccp);
+ bi_errorf(Tf_sD_sD_s, "-u", builtin_opt.optarg, ccp);
return (2);
}
break;
*--wp = REPLY;
if (intoarray && wp[1] != NULL) {
- bi_errorf("too many arguments");
+ bi_errorf(Ttoo_many_args);
return (2);
}
break;
case 0:
/* timeout expired for this call */
- rv = 1;
- goto c_read_out;
+ bytesread = 0;
+ /* fake EOF read; all cases return 1 */
+ goto c_read_didread;
default:
- bi_errorf("%s: %s", Tselect, cstrerror(errno));
+ bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
rv = 2;
goto c_read_out;
}
}
#endif
- bytesread = blocking_read(fd, xp, bytesleft);
- if (bytesread == (size_t)-1) {
- /* interrupted */
- if (errno == EINTR && fatal_trap_check()) {
- /*
- * Was the offending signal one that would
- * normally kill a process? If so, pretend
- * the read was killed.
- */
- rv = 2;
- goto c_read_out;
+ if ((bytesread = blocking_read(fd, xp, bytesleft)) == (size_t)-1) {
+ if (errno == EINTR) {
+ /* check whether the signal would normally kill */
+ if (!fatal_trap_check()) {
+ /* no, just ignore the signal */
+ goto c_read_readloop;
+ }
+ /* pretend the read was killed */
+ } else {
+ /* unexpected error */
+ bi_errorf(Tf_s, cstrerror(errno));
}
- /* just ignore the signal */
- goto c_read_readloop;
+ rv = 2;
+ goto c_read_out;
}
+ c_read_didread:
switch (readmode) {
case READALL:
if (bytesread == 0) {
if (bytesread == 0) {
/* end of file reached */
rv = 1;
- xp = Xstring(xs, xp);
+ /* may be partial read: $? = 1, but content */
goto c_read_readdone;
}
xp += bytesread;
}
if (savehist)
- histsave(&source->line, Xstring(xs, xp), true, false);
+ histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
ccp = cp = Xclose(xs, xp);
expanding = false;
XinitN(xs, 128, ATEMP);
if (intoarray) {
vp = global(*wp);
+ subarray = last_lookup_was_array;
if (vp->flag & RDONLY) {
c_read_splitro:
- bi_errorf("read-only: %s", *wp);
+ bi_errorf(Tf_ro, *wp);
c_read_spliterr:
rv = 2;
afree(cp, ATEMP);
goto c_read_out;
}
- /* exporting an array is currently pointless */
- unset(vp, 1);
/* counter for array index */
- c = 0;
+ c = subarray ? arrayindex(vp) : 0;
+ /* exporting an array is currently pointless */
+ unset(vp, subarray ? 0 : 1);
}
if (!aschars) {
/* skip initial IFS whitespace */
}
if (!intoarray && wp[1] == NULL)
- lastparm = 1;
+ lastparmmode = true;
c_read_splitlast:
/* copy until IFS character */
}
xsave = Xsavepos(xs, xp);
/* copy word delimiter: IFSWS+IFS,IFSWS */
+ expanding = false;
while (bytesread) {
char ch;
ch = *ccp;
if (!ctype(ch, C_IFS))
break;
- Xcheck(xs, xp);
- Xput(xs, xp, ch);
+ if (lastparmmode && !expanding && !rawmode && ch == '\\') {
+ expanding = true;
+ } else {
+ Xcheck(xs, xp);
+ Xput(xs, xp, ch);
+ }
++ccp;
--bytesread;
+ if (expanding)
+ continue;
if (!ctype(ch, C_IFSWS))
break;
}
--bytesread;
}
/* if no more parameters, rinse and repeat */
- if (lastparm && bytesread) {
- ++lastparm;
+ if (lastparmmode && bytesread) {
+ lastparmused = true;
goto c_read_splitlast;
}
/* get rid of the delimiter unless we pack the rest */
- if (lastparm < 2)
+ if (!lastparmused)
xp = Xrestpos(xs, xp, xsave);
c_read_gotword:
Xput(xs, xp, '\0');
if (intoarray) {
- vq = arraysearch(vp, c++);
+ if (subarray) {
+ /* array element passed, accept first read */
+ if (vq) {
+ bi_errorf("nested arrays not yet supported");
+ goto c_read_spliterr;
+ }
+ vq = vp;
+ if (c)
+ /* [0] doesn't */
+ vq->flag |= AINDEX;
+ } else
+ vq = arraysearch(vp, c++);
} else {
vq = global(*wp);
/* must be checked before exporting */
int
c_trap(const char **wp)
{
- int i;
+ Trap *p = sigtraps;
+ int i = ksh_NSIG;
const char *s;
- Trap *p;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return (1);
wp += builtin_opt.optind;
if (*wp == NULL) {
- for (p = sigtraps, i = NSIG + 1; --i >= 0; p++)
- if (p->trap != NULL) {
+ do {
+ if (p->trap) {
shf_puts("trap -- ", shl_stdout);
print_value_quoted(shl_stdout, p->trap);
- shprintf(" %s\n", p->name);
+ shprintf(Tf__sN, p->name);
}
+ ++p;
+ } while (i--);
return (0);
}
- /*
- * Use case sensitive lookup for first arg so the
- * command 'exit' isn't confused with the pseudo-signal
- * 'EXIT'.
- */
- /* get command */
- s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL;
- if (s != NULL && s[0] == '-' && s[1] == '\0')
+ if (getn(*wp, &i)) {
+ /* first argument is a signal number, reset them all */
s = NULL;
+ } else {
+ /* first argument must be a command, then */
+ s = *wp++;
+ /* reset traps? */
+ if (ksh_isdash(s))
+ s = NULL;
+ }
- /* set/clear traps */
+ /* set/clear the traps */
i = 0;
- while (*wp != NULL)
- if ((p = gettrap(*wp++, true)) == NULL) {
- warningf(true, "%s: %s '%s'", builtin_argv0,
- "bad signal", wp[-1]);
- ++i;
+ while (*wp)
+ if (!(p = gettrap(*wp++, true, true))) {
+ warningf(true, Tbad_sig_ss, builtin_argv0, wp[-1]);
+ i = 1;
} else
settrap(p, s);
return (i);
c_exitreturn(const char **wp)
{
int n, how = LEXIT;
- const char *arg;
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- goto c_exitreturn_err;
- arg = wp[builtin_opt.optind];
-
- if (arg) {
- if (!getn(arg, &n)) {
- exstat = 1;
- warningf(true, "%s: %s", arg, "bad number");
- } else
- exstat = n & 0xFF;
+ if (wp[1]) {
+ if (wp[2])
+ goto c_exitreturn_err;
+ exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1;
} else if (trap_exstat != -1)
exstat = trap_exstat;
+
if (wp[0][0] == 'r') {
/* return */
struct env *ep;
how = LSHELL;
}
- /* get rid of any i/o redirections */
+ /* get rid of any I/O redirections */
quitenv(NULL);
unwind(how);
/* NOTREACHED */
c_exitreturn_err:
+ bi_errorf(Ttoo_many_args);
return (1);
}
goto c_brkcont_err;
if (n <= 0) {
/* AT&T ksh does this for non-interactive shells only - weird */
- bi_errorf("%s: %s", arg, "bad value");
+ bi_errorf("%s: bad value", arg);
goto c_brkcont_err;
}
quit = (unsigned int)n;
* scripts, but don't generate an error (ie, keep going).
*/
if ((unsigned int)n == quit) {
- warningf(true, "%s: %s %s", wp[0], "can't", wp[0]);
+ warningf(true, "%s: can't %s", wp[0], wp[0]);
return (0);
}
/*
return (c_typeset(args));
}
- argi = parse_args(wp, OF_SET, &setargs);
- if (argi < 0)
- return (1);
+ if ((argi = parse_args(wp, OF_SET, &setargs)) < 0)
+ return (2);
/* set $# and $* */
if (setargs) {
wp += argi - 1;
afree(cp, ATEMP);
if ((vp->flag&RDONLY)) {
- warningf(true, "read-only: %s", vp->name);
+ warningf(true, Tf_ro, vp->name);
rv = 1;
} else
unset(vp, optc);
shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width,
tv_sec, tv_usec, suffix);
else
- shf_fprintf(shf, "%s%*ldm%d.%02ds%s", prefix, width,
+ shf_fprintf(shf, "%s%*ldm%02d.%02ds%s", prefix, width,
tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix);
}
getrusage(RUSAGE_SELF, &usage);
p_time(shl_stdout, false, usage.ru_utime.tv_sec,
- usage.ru_utime.tv_usec, 0, null, " ");
+ usage.ru_utime.tv_usec, 0, null, T1space);
p_time(shl_stdout, false, usage.ru_stime.tv_sec,
usage.ru_stime.tv_usec, 0, null, "\n");
getrusage(RUSAGE_CHILDREN, &usage);
p_time(shl_stdout, false, usage.ru_utime.tv_sec,
- usage.ru_utime.tv_usec, 0, null, " ");
+ usage.ru_utime.tv_usec, 0, null, T1space);
p_time(shl_stdout, false, usage.ru_stime.tv_sec,
usage.ru_stime.tv_usec, 0, null, "\n");
timersub(&tv1, &tv0, &tv1);
if (tf & TF_POSIX)
p_time(shl_out, true, tv1.tv_sec, tv1.tv_usec,
- 5, "real ", "\n");
+ 5, Treal_sp1, "\n");
else
p_time(shl_out, false, tv1.tv_sec, tv1.tv_usec,
- 5, null, " real ");
+ 5, null, Treal_sp2);
}
if (tf & TF_POSIX)
p_time(shl_out, true, usrtime.tv_sec, usrtime.tv_usec,
- 5, "user ", "\n");
+ 5, Tuser_sp1, "\n");
else
p_time(shl_out, false, usrtime.tv_sec, usrtime.tv_usec,
- 5, null, " user ");
+ 5, null, Tuser_sp2);
if (tf & TF_POSIX)
p_time(shl_out, true, systime.tv_sec, systime.tv_usec,
5, "sys ", "\n");
t->str[0] |= TF_POSIX;
break;
case '?':
- errorf("time: -%s %s", opt.optarg,
- "unknown option");
+ errorf(Tf_optfoo, Ttime, Tcolsp,
+ opt.optarg[0], Tunknown_option);
case ':':
- errorf("time: -%s %s", opt.optarg,
- "requires an argument");
+ errorf(Tf_optfoo, Ttime, Tcolsp,
+ opt.optarg[0], Treq_arg);
}
/* Copy command words down over options. */
if (opt.optind != 0) {
majnum = strtoul(argv[2], &c, 0);
if ((c == argv[2]) || (*c != '\0')) {
- bi_errorf("non-numeric %s %s '%s'", "device", "major", argv[2]);
+ bi_errorf(Tf_nonnum, "device", "major", argv[2]);
goto c_mknod_err;
}
minnum = strtoul(argv[3], &c, 0);
if ((c == argv[3]) || (*c != '\0')) {
- bi_errorf("non-numeric %s %s '%s'", "device", "minor", argv[3]);
+ bi_errorf(Tf_nonnum, "device", "minor", argv[3]);
goto c_mknod_err;
}
dv = makedev(majnum, minnum);
if ((unsigned long)(major(dv)) != majnum) {
- bi_errorf("%s %s too large: %lu", "device", "major", majnum);
+ bi_errorf(Tf_toolarge, "device", "major", majnum);
goto c_mknod_err;
}
if ((unsigned long)(minor(dv)) != minnum) {
- bi_errorf("%s %s too large: %lu", "device", "minor", minnum);
+ bi_errorf(Tf_toolarge, "device", "minor", minnum);
goto c_mknod_err;
}
if (mknod(argv[0], mode, dv))
goto c_mknod_failed;
} else if (mkfifo(argv[0], mode)) {
c_mknod_failed:
- bi_errorf("%s: %s", argv[0], cstrerror(errno));
+ bi_errorf(Tf_sD_s, argv[0], cstrerror(errno));
c_mknod_err:
rv = 1;
}
umask(oldmode);
return (rv);
c_mknod_usage:
- bi_errorf("%s: %s", "usage", "mknod [-m mode] name b|c major minor");
- bi_errorf("%s: %s", "usage", "mknod [-m mode] name p");
+ bi_errorf("usage: mknod [-m mode] name %s", "b|c major minor");
+ bi_errorf("usage: mknod [-m mode] name %s", "p");
return (1);
}
#endif
int argc, rv, invert = 0;
Test_env te;
Test_op op;
+ Test_meta tm;
const char *lhs, **swp;
te.flags = 0;
for (argc = 0; wp[argc]; argc++)
;
- mkssert(argc > 0);
- mkssert(wp[0] != NULL);
- if (strcmp(wp[0], "[") == 0) {
+ if (strcmp(wp[0], Tbracket) == 0) {
if (strcmp(wp[--argc], "]") != 0) {
bi_errorf("missing ]");
return (T_ERR_EXIT);
/*
* Attempt to conform to POSIX special cases. This is pretty
- * dumb code straight-forward from the 2008 spec, but unless
+ * dumb code straight-forward from the 2008 spec, but unlike
* the old pdksh code doesn't live from so many assumptions.
* It does, though, inline some calls to '(*te.funcname)()'.
*/
ptest_unary:
rv = test_eval(&te, op, *te.pos.wp++, NULL, true);
ptest_out:
+ if (te.flags & TEF_ERROR)
+ return (T_ERR_EXIT);
return ((invert & 1) ? rv : !rv);
}
/* let the parser deal with anything else */
rv = test_eval(&te, op, lhs, *te.pos.wp++, true);
goto ptest_out;
}
+ if (ptest_isa(&te, tm = TM_AND) || ptest_isa(&te, tm = TM_OR)) {
+ /* XSI */
+ argc = test_eval(&te, TO_STNZE, lhs, NULL, true);
+ rv = test_eval(&te, TO_STNZE, *te.pos.wp++, NULL, true);
+ if (tm == TM_AND)
+ rv = argc && rv;
+ else
+ rv = argc || rv;
+ goto ptest_out;
+ }
/* back up to lhs */
te.pos.wp = swp;
if (ptest_isa(&te, TM_NOT)) {
/* = */
case TO_STEQL:
- if (te->flags & TEF_DBRACKET)
- return (gmatchx(opnd1, opnd2, false));
+ if (te->flags & TEF_DBRACKET) {
+ if ((i = gmatchx(opnd1, opnd2, false)))
+ record_match(opnd1);
+ return (i);
+ }
return (strcmp(opnd1, opnd2) == 0);
/* != */
case TO_STNEQ:
- if (te->flags & TEF_DBRACKET)
- return (!gmatchx(opnd1, opnd2, false));
+ if (te->flags & TEF_DBRACKET) {
+ if ((i = gmatchx(opnd1, opnd2, false)))
+ record_match(opnd1);
+ return (!i);
+ }
return (strcmp(opnd1, opnd2) != 0);
/* < */
/* unary expression */
opnd1 = (*te->getopnd)(te, op, do_eval);
if (!opnd1) {
- (*te->error)(te, -1, "missing argument");
+ (*te->error)(te, -1, Tno_args);
return (0);
}
te->flags |= TEF_ERROR;
if ((op = te->pos.wp + ofs >= te->wp_end ? NULL : te->pos.wp[ofs]))
- bi_errorf("%s: %s", op, msg);
+ bi_errorf(Tf_sD_s, op, msg);
else
- bi_errorf("%s", msg);
+ bi_errorf(Tf_s, msg);
}
#ifndef MKSH_NO_LIMITS
# error nonsensical v ulimit
#endif
+struct limits {
+ /* limit resource */
+ int resource;
+ /* multiply by to get rlim_{cur,max} values */
+ unsigned int factor;
+ /* getopts char */
+ char optchar;
+ /* limit name */
+ char name[1];
+};
+
#define RLIMITS_DEFNS
+#define FN(lname,lid,lfac,lopt) \
+ static const struct { \
+ int resource; \
+ unsigned int factor; \
+ char optchar; \
+ char name[sizeof(lname)]; \
+ } rlimits_ ## lid = { \
+ lid, lfac, lopt, lname \
+ };
#include "rlimits.gen"
static void print_ulimit(const struct limits *, int);
found:
if (wp[builtin_opt.optind]) {
if (all || wp[builtin_opt.optind + 1]) {
- bi_errorf("too many arguments");
+ bi_errorf(Ttoo_many_args);
return (1);
}
return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
bi_errorf(Tsynerr);
else if ((rv = rename(wp[0], wp[1])) != 0) {
rv = errno;
- bi_errorf("%s: %s", "failed", cstrerror(rv));
+ bi_errorf(Tf_sD_s, "failed", cstrerror(rv));
}
return (rv);
bi_errorf(Tsynerr);
else if ((buf = do_realpath(wp[0])) == NULL) {
rv = errno;
- bi_errorf("%s: %s", wp[0], cstrerror(rv));
+ bi_errorf(Tf_sD_s, wp[0], cstrerror(rv));
if ((unsigned int)rv > 255)
rv = 255;
} else {
- shprintf("%s\n", buf);
+ shprintf(Tf_sN, buf);
afree(buf, ATEMP);
rv = 0;
}
int
c_cat(const char **wp)
{
- int fd = STDIN_FILENO, rv, eno;
+ int fd = STDIN_FILENO, rv;
ssize_t n, w;
const char *fn = "<stdin>";
char *buf, *cp;
+ int opipe = 0;
#define MKSH_CAT_BUFSIZ 4096
/* parse options: POSIX demands we support "-u" as no-op */
return (1);
}
+ /* catch SIGPIPE */
+ opipe = block_pipe();
+
do {
if (*wp) {
fn = *wp++;
- if (fn[0] == '-' && fn[1] == '\0')
+ if (ksh_isdash(fn))
fd = STDIN_FILENO;
- else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) {
- eno = errno;
- bi_errorf("%s: %s", fn, cstrerror(eno));
+ else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
+ bi_errorf(Tf_sD_s, fn, cstrerror(errno));
rv = 1;
continue;
}
}
while (/* CONSTCOND */ 1) {
- n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ);
- eno = errno;
- /* give the user a chance to ^C out */
- intrcheck();
- if (n == -1) {
- if (eno == EINTR) {
+ if ((n = blocking_read(fd, (cp = buf),
+ MKSH_CAT_BUFSIZ)) == -1) {
+ if (errno == EINTR) {
+ restore_pipe(opipe);
+ /* give the user a chance to ^C out */
+ intrcheck();
/* interrupted, try again */
+ opipe = block_pipe();
continue;
}
/* an error occured during reading */
- bi_errorf("%s: %s", fn, cstrerror(eno));
+ bi_errorf(Tf_sD_s, fn, cstrerror(errno));
rv = 1;
break;
} else if (n == 0)
/* end of file reached */
break;
while (n) {
- w = write(STDOUT_FILENO, cp, n);
- eno = errno;
- /* give the user a chance to ^C out */
- intrcheck();
- if (w == -1) {
- if (eno == EINTR)
- /* interrupted, try again */
- continue;
+ if ((w = write(STDOUT_FILENO, cp, n)) != -1) {
+ n -= w;
+ cp += w;
+ continue;
+ }
+ if (errno == EINTR) {
+ restore_pipe(opipe);
+ /* give the user a chance to ^C out */
+ intrcheck();
+ /* interrupted, try again */
+ opipe = block_pipe();
+ continue;
+ }
+ if (errno == EPIPE) {
+ /* fake receiving signel */
+ rv = ksh_sigmask(SIGPIPE);
+ } else {
/* an error occured during writing */
- bi_errorf("%s: %s", "<stdout>",
- cstrerror(eno));
+ bi_errorf(Tf_sD_s, "<stdout>",
+ cstrerror(errno));
rv = 1;
- if (fd != STDIN_FILENO)
- close(fd);
- goto out;
}
- n -= w;
- cp += w;
+ if (fd != STDIN_FILENO)
+ close(fd);
+ goto out;
}
}
if (fd != STDIN_FILENO)
} while (*wp);
out:
+ restore_pipe(opipe);
free_osfunc(buf);
return (rv);
}
if (!wp[0] || wp[1])
bi_errorf(Tsynerr);
else if (parse_usec(wp[0], &tv))
- bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno), wp[0]);
+ bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno), wp[0]);
else {
#ifndef MKSH_NOPROSPECTOFWORK
sigset_t omask, bmask;
*/
rv = 0;
else
- bi_errorf("%s: %s", Tselect, cstrerror(errno));
+ bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
#ifndef MKSH_NOPROSPECTOFWORK
/* this will re-schedule signal delivery */
sigprocmask(SIG_SETMASK, &omask, NULL);
c_suspend(const char **wp)
{
if (wp[1] != NULL) {
- bi_errorf("too many arguments");
+ bi_errorf(Ttoo_many_args);
return (1);
}
if (Flag(FLOGIN)) {