summaryrefslogtreecommitdiff
path: root/src/funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/funcs.c')
-rw-r--r--src/funcs.c252
1 files changed, 137 insertions, 115 deletions
diff --git a/src/funcs.c b/src/funcs.c
index ade00d6..a5cfc69 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -5,7 +5,8 @@
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2019, 2020
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@@ -38,7 +39,7 @@
#endif
#endif
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.355 2018/10/20 21:04:28 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.372 2020/04/13 19:51:07 tg Exp $");
#if HAVE_KILLPG
/*
@@ -119,8 +120,6 @@ const struct builtin mkshbuiltins[] = {
{Tfalse, c_false},
{"fc", c_fc},
{Tgetopts, c_getopts},
- /* deprecated, replaced by typeset -g */
- {"^=global", c_typeset},
{Tjobs, c_jobs},
{"kill", c_kill},
{"let", c_let},
@@ -133,8 +132,8 @@ const struct builtin mkshbuiltins[] = {
#endif
{"~rename", c_rename},
{"*=return", c_exitreturn},
- {Tsgset, c_set},
- {"*=shift", c_shift},
+ {Tsghset, c_set},
+ {"*=#shift", c_shift},
{Tgsource, c_dot},
#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
{Tsuspend, c_suspend},
@@ -183,11 +182,8 @@ struct kill_info {
int name_width;
};
-static const struct t_op {
- char op_text[4];
- Test_op op_num;
-} u_ops[] = {
- {"-a", TO_FILAXST },
+const struct t_op u_ops[] = {
+/* 0*/ {"-a", TO_FILAXST },
{"-b", TO_FILBDEV },
{"-c", TO_FILCDEV },
{"-d", TO_FILID },
@@ -199,22 +195,23 @@ static const struct t_op {
{"-h", TO_FILSYM },
{"-k", TO_FILSTCK },
{"-L", TO_FILSYM },
- {"-n", TO_STNZE },
+/*12*/ {"-n", TO_STNZE },
{"-O", TO_FILUID },
- {"-o", TO_OPTION },
+/*14*/ {"-o", TO_OPTION },
{"-p", TO_FILFIFO },
- {"-r", TO_FILRD },
+/*16*/ {"-r", TO_FILRD },
{"-S", TO_FILSOCK },
{"-s", TO_FILGZ },
{"-t", TO_FILTT },
- {"-u", TO_FILSETU },
+/*20*/ {"-u", TO_FILSETU },
{"-v", TO_ISSET },
{"-w", TO_FILWR },
- {"-x", TO_FILEX },
+/*23*/ {"-x", TO_FILEX },
{"-z", TO_STZER },
{"", TO_NONOP }
};
-static const struct t_op b_ops[] = {
+cta(u_ops_size, NELEM(u_ops) == 26);
+const struct t_op b_ops[] = {
{"=", TO_STEQL },
{"==", TO_STEQL },
{"!=", TO_STNEQ },
@@ -337,7 +334,7 @@ c_print(const char **wp)
/* BSD "echo" cmd, Debian Policy 10.4 compliant */
++wp;
bsd_echo:
- if (*wp && !strcmp(*wp, "-n")) {
+ if (*wp && !strcmp(*wp, Tdn)) {
po.nl = false;
++wp;
}
@@ -724,12 +721,16 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
}
break;
case CALIAS:
- if (vflag) {
- shprintf("%s is an %s%s for ", id,
+ if (!vflag && iscommand)
+ shprintf(Tf_s_, Talias);
+ if (vflag || iscommand)
+ print_value_quoted(shl_stdout, id);
+ if (vflag)
+ shprintf(" is an %s%s for ",
(tp->flag & EXPORT) ? "exported " : "",
Talias);
- } else if (iscommand)
- shprintf("%s %s=", Talias, id);
+ else if (iscommand)
+ shf_putc('=', shl_stdout);
print_value_quoted(shl_stdout, tp->val.s);
break;
case CKEYWD:
@@ -751,10 +752,15 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
bool
valid_alias_name(const char *cp)
{
- if (ord(*cp) == ORD('-'))
- return (false);
- if (ord(cp[0]) == ORD('[') && ord(cp[1]) == ORD('[') && !cp[2])
+ switch (ord(*cp)) {
+ case ORD('+'):
+ case ORD('-'):
return (false);
+ case ORD('['):
+ if (ord(cp[1]) == ORD('[') && !cp[2])
+ return (false);
+ break;
+ }
while (*cp)
if (ctype(*cp, C_ALIAS))
++cp;
@@ -843,7 +849,7 @@ c_alias(const char **wp)
if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
if (pflag)
shprintf(Tf_s_, Talias);
- shf_puts(ap->name, shl_stdout);
+ print_value_quoted(shl_stdout, ap->name);
if (prefix != '+') {
shf_putc('=', shl_stdout);
print_value_quoted(shl_stdout, ap->val.s);
@@ -873,7 +879,7 @@ c_alias(const char **wp)
if (ap != NULL && (ap->flag&ISSET)) {
if (pflag)
shprintf(Tf_s_, Talias);
- shf_puts(ap->name, shl_stdout);
+ print_value_quoted(shl_stdout, ap->name);
if (prefix != '+') {
shf_putc('=', shl_stdout);
print_value_quoted(shl_stdout, ap->val.s);
@@ -1297,54 +1303,32 @@ c_bind(const char **wp)
#ifndef MKSH_SMALL
bool macro = false;
#endif
- bool list = false;
- const char *cp;
- char *up;
- while ((optc = ksh_getopt(wp, &builtin_opt,
-#ifndef MKSH_SMALL
- "lm"
-#else
- "l"
-#endif
- )) != -1)
+ if (x_bind_check()) {
+ bi_errorf("can't bind, not a tty");
+ return (1);
+ }
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != -1)
switch (optc) {
case 'l':
- list = true;
- break;
+ return (x_bind_list());
#ifndef MKSH_SMALL
case 'm':
macro = true;
break;
#endif
- case '?':
+ default:
return (1);
}
wp += builtin_opt.optind;
if (*wp == NULL)
- /* list all */
- rv = x_bind(NULL, NULL,
-#ifndef MKSH_SMALL
- false,
-#endif
- list);
+ return (x_bind_showall());
- for (; *wp != NULL; wp++) {
- if ((cp = cstrchr(*wp, '=')) == NULL)
- up = NULL;
- else {
- strdupx(up, *wp, ATEMP);
- up[cp++ - *wp] = '\0';
- }
- if (x_bind(up ? up : *wp, cp,
-#ifndef MKSH_SMALL
- macro,
-#endif
- false))
- rv = 1;
- afree(up, ATEMP);
- }
+ do {
+ rv |= x_bind(*wp SMALLP(macro));
+ } while (*++wp);
return (rv);
}
@@ -1353,10 +1337,17 @@ c_bind(const char **wp)
int
c_shift(const char **wp)
{
- struct block *l = e->loc;
int n;
mksh_ari_t val;
const char *arg;
+ struct block *l = e->loc;
+
+ if ((l->flags & BF_RESETSPEC)) {
+ /* prevent pollution */
+ l->flags &= ~BF_RESETSPEC;
+ /* operate on parent environment */
+ l = l->next;
+ }
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return (1);
@@ -1375,6 +1366,7 @@ c_shift(const char **wp)
bi_errorf(Tf_sD_s, Tbadnum, arg);
return (1);
}
+
if (l->argc < n) {
bi_errorf("nothing to shift");
return (1);
@@ -1589,7 +1581,6 @@ c_wait(const char **wp)
return (rv);
}
-static const char REPLY[] = "REPLY";
int
c_read(const char **wp)
{
@@ -1670,7 +1661,7 @@ c_read(const char **wp)
if (!builtin_opt.optarg[0])
fd = 0;
else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
- bi_errorf(Tf_sD_sD_s, "-u", builtin_opt.optarg, ccp);
+ bi_errorf(Tf_sD_sD_s, Tdu, builtin_opt.optarg, ccp);
return (2);
}
break;
@@ -1679,7 +1670,7 @@ c_read(const char **wp)
}
wp += builtin_opt.optind;
if (*wp == NULL)
- *--wp = REPLY;
+ *--wp = TREPLY;
if (intoarray && wp[1] != NULL) {
bi_errorf(Ttoo_many_args);
@@ -2029,7 +2020,6 @@ int
c_eval(const char **wp)
{
struct source *s, *saves = source;
- unsigned char savef;
int rv;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
@@ -2072,10 +2062,7 @@ c_eval(const char **wp)
/* SUSv4: OR with a high value never written otherwise */
exstat |= 0x4000;
- savef = Flag(FERREXIT);
- Flag(FERREXIT) |= 0x80;
rv = shell(s, 2);
- Flag(FERREXIT) = savef;
source = saves;
afree(s, ATEMP);
if (exstat & 0x4000)
@@ -2237,7 +2224,13 @@ c_set(const char **wp)
int argi;
bool setargs;
struct block *l = e->loc;
- const char **owp;
+
+ if ((l->flags & BF_RESETSPEC)) {
+ /* prevent pollution */
+ l->flags &= ~BF_RESETSPEC;
+ /* operate on parent environment */
+ l = l->next;
+ }
if (wp[1] == NULL) {
static const char *args[] = { Tset, "-", NULL };
@@ -2248,6 +2241,8 @@ c_set(const char **wp)
return (2);
/* set $# and $* */
if (setargs) {
+ const char **owp;
+
wp += argi - 1;
owp = wp;
/* save $0 */
@@ -2579,25 +2574,25 @@ c_mknod(const char **wp)
#endif
/*-
- test(1) roughly accepts the following grammar:
- oexpr ::= aexpr | aexpr "-o" oexpr ;
- aexpr ::= nexpr | nexpr "-a" aexpr ;
- nexpr ::= primary | "!" nexpr ;
- primary ::= unary-operator operand
- | operand binary-operator operand
- | operand
- | "(" oexpr ")"
- ;
-
- unary-operator ::= "-a"|"-b"|"-c"|"-d"|"-e"|"-f"|"-G"|"-g"|"-H"|"-h"|
- "-k"|"-L"|"-n"|"-O"|"-o"|"-p"|"-r"|"-S"|"-s"|"-t"|
- "-u"|"-v"|"-w"|"-x"|"-z";
-
- binary-operator ::= "="|"=="|"!="|"<"|">"|"-eq"|"-ne"|"-gt"|"-ge"|
- "-lt"|"-le"|"-ef"|"-nt"|"-ot";
-
- operand ::= <anything>
-*/
+ * test(1) roughly accepts the following grammar:
+ * oexpr ::= aexpr | aexpr "-o" oexpr ;
+ * aexpr ::= nexpr | nexpr "-a" aexpr ;
+ * nexpr ::= primary | "!" nexpr ;
+ * primary ::= unary-operator operand
+ * | operand binary-operator operand
+ * | operand
+ * | "(" oexpr ")"
+ * ;
+ *
+ * unary-operator ::= "-a"|"-b"|"-c"|"-d"|"-e"|"-f"|"-G"|"-g"|"-H"|"-h"|
+ * "-k"|"-L"|"-n"|"-O"|"-o"|"-p"|"-r"|"-S"|"-s"|"-t"|
+ * "-u"|"-v"|"-w"|"-x"|"-z";
+ *
+ * binary-operator ::= "="|"=="|"!="|"<"|">"|"-eq"|"-ne"|"-gt"|"-ge"|
+ * "-lt"|"-le"|"-ef"|"-nt"|"-ot";
+ *
+ * operand ::= <anything>
+ */
/* POSIX says > 1 for errors */
#define T_ERR_EXIT 2
@@ -2749,12 +2744,35 @@ test_isop(Test_meta meta, const char *s)
}
#ifdef __OS2__
-#define test_access(name, mode) access_ex(access, (name), (mode))
-#define test_stat(name, buffer) stat_ex((name), (buffer))
+#define test_access(name,mode) access_ex(access, (name), (mode))
+#define test_stat(name,buffer) stat_ex(stat, (name), (buffer))
+#define test_lstat(name,buffer) stat_ex(lstat, (name), (buffer))
#else
-#define test_access(name, mode) access((name), (mode))
-#define test_stat(name, buffer) stat((name), (buffer))
+#define test_access(name,mode) access((name), (mode))
+#define test_stat(name,buffer) stat((name), (buffer))
+#define test_lstat(name,buffer) lstat((name), (buffer))
+#endif
+
+#if HAVE_ST_MTIM
+#undef st_mtimensec
+#define st_mtimensec st_mtim.tv_nsec
+#endif
+
+static int
+mtimecmp(const struct stat *sb1, const struct stat *sb2)
+{
+ if (sb1->st_mtime < sb2->st_mtime)
+ return (-1);
+ if (sb1->st_mtime > sb2->st_mtime)
+ return (1);
+#if (HAVE_ST_MTIMENSEC || HAVE_ST_MTIM)
+ if (sb1->st_mtimensec < sb2->st_mtimensec)
+ return (-1);
+ if (sb1->st_mtimensec > sb2->st_mtimensec)
+ return (1);
#endif
+ return (0);
+}
int
test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
@@ -2849,31 +2867,31 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
/* -d */
case TO_FILID:
- return (stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode));
+ return (test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode));
/* -c */
case TO_FILCDEV:
- return (stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode));
+ return (test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode));
/* -b */
case TO_FILBDEV:
- return (stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode));
+ return (test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode));
/* -p */
case TO_FILFIFO:
- return (stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode));
+ return (test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode));
/* -h or -L */
case TO_FILSYM:
#ifdef MKSH__NO_SYMLINK
return (0);
#else
- return (lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode));
+ return (test_lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode));
#endif
/* -S */
case TO_FILSOCK:
- return (stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode));
+ return (test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode));
/* -H => HP context dependent files (directories) */
case TO_FILCDF:
@@ -2892,7 +2910,7 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
*/
nv = shf_smprintf("%s+", opnd1);
- i = (stat(nv, &b1) == 0 && S_ISCDF(b1.st_mode));
+ i = (test_stat(nv, &b1) == 0 && S_ISCDF(b1.st_mode));
afree(nv, ATEMP);
return (i);
}
@@ -2902,18 +2920,18 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
/* -u */
case TO_FILSETU:
- return (stat(opnd1, &b1) == 0 &&
+ return (test_stat(opnd1, &b1) == 0 &&
(b1.st_mode & S_ISUID) == S_ISUID);
/* -g */
case TO_FILSETG:
- return (stat(opnd1, &b1) == 0 &&
+ return (test_stat(opnd1, &b1) == 0 &&
(b1.st_mode & S_ISGID) == S_ISGID);
/* -k */
case TO_FILSTCK:
#ifdef S_ISVTX
- return (stat(opnd1, &b1) == 0 &&
+ return (test_stat(opnd1, &b1) == 0 &&
(b1.st_mode & S_ISVTX) == S_ISVTX);
#else
return (0);
@@ -2921,7 +2939,8 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
/* -s */
case TO_FILGZ:
- return (stat(opnd1, &b1) == 0 && (off_t)b1.st_size > (off_t)0);
+ return (test_stat(opnd1, &b1) == 0 &&
+ (off_t)b1.st_size > (off_t)0);
/* -t */
case TO_FILTT:
@@ -2934,11 +2953,13 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
/* -O */
case TO_FILUID:
- return (stat(opnd1, &b1) == 0 && (uid_t)b1.st_uid == ksheuid);
+ return (test_stat(opnd1, &b1) == 0 &&
+ (uid_t)b1.st_uid == ksheuid);
/* -G */
case TO_FILGID:
- return (stat(opnd1, &b1) == 0 && (gid_t)b1.st_gid == getegid());
+ return (test_stat(opnd1, &b1) == 0 &&
+ (gid_t)b1.st_gid == kshegid);
/*
* Binary Operators
@@ -2976,9 +2997,9 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
* ksh88/ksh93 succeed if file2 can't be stated
* (subtly different from 'does not exist').
*/
- return (stat(opnd1, &b1) == 0 &&
- (((s = stat(opnd2, &b2)) == 0 &&
- b1.st_mtime > b2.st_mtime) || s < 0));
+ return (test_stat(opnd1, &b1) == 0 &&
+ (((s = test_stat(opnd2, &b2)) == 0 &&
+ mtimecmp(&b1, &b2) > 0) || s < 0));
/* -ot */
case TO_FILOT:
@@ -2986,13 +3007,14 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
* ksh88/ksh93 succeed if file1 can't be stated
* (subtly different from 'does not exist').
*/
- return (stat(opnd2, &b2) == 0 &&
- (((s = stat(opnd1, &b1)) == 0 &&
- b1.st_mtime < b2.st_mtime) || s < 0));
+ return (test_stat(opnd2, &b2) == 0 &&
+ (((s = test_stat(opnd1, &b1)) == 0 &&
+ mtimecmp(&b1, &b2) < 0) || s < 0));
/* -ef */
case TO_FILEQ:
- return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 &&
+ return (test_stat(opnd1, &b1) == 0 &&
+ test_stat(opnd2, &b2) == 0 &&
b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
/* all other cases */
@@ -3155,7 +3177,7 @@ ptest_isa(Test_env *te, Test_meta meta)
{
/* Order important - indexed by Test_meta values */
static const char * const tokens[] = {
- "-o", "-a", "!", "(", ")"
+ Tdo, Tda, "!", "(", ")"
};
Test_op rv;
@@ -3469,7 +3491,7 @@ c_cat(const char **wp)
#define MKSH_CAT_BUFSIZ 4096
/* parse options: POSIX demands we support "-u" as no-op */
- while ((rv = ksh_getopt(wp, &builtin_opt, "u")) != -1) {
+ while ((rv = ksh_getopt(wp, &builtin_opt, Tu)) != -1) {
switch (rv) {
case 'u':
/* we already operate unbuffered */