OSDN Git Service

Updated mksh to ToT as of 12 October 2011.
[android-x86/external-mksh.git] / src / exec.c
index 391321a..c8dd4c4 100644 (file)
@@ -1,7 +1,7 @@
 /*     $OpenBSD: exec.c,v 1.49 2009/01/29 23:27:26 jaredy Exp $        */
 
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.75 2010/07/17 22:09:34 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.96 2011/09/07 15:24:14 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL "/bin/sh"
 #endif
 
-static int comexec(struct op *, struct tbl *volatile, const char **,
+static int comexec(struct op *, struct tbl * volatile, const char **,
     int volatile, volatile int *);
 static void scriptexec(struct op *, const char **) MKSH_A_NORETURN;
 static int call_builtin(struct tbl *, const char **);
 static int iosetup(struct ioword *, struct tbl *);
-static int herein(const char *, int);
+static int herein(const char *, int, char **);
 static const char *do_selectargs(const char **, bool);
 static Test_op dbteste_isa(Test_env *, Test_meta);
 static const char *dbteste_getopnd(Test_env *, Test_op, bool);
 static void dbteste_error(Test_env *, int, const char *);
+static int search_access(const char *, int);
 
 /*
  * execute command tree
  */
 int
-execute(struct op *volatile t,
-    volatile int flags,                /* if XEXEC don't fork */
+execute(struct op * volatile t,
+    /* if XEXEC don't fork */
+    volatile int flags,
     volatile int * volatile xerrok)
 {
        int i;
        volatile int rv = 0, dummy = 0;
        int pv[2];
-       const char ** volatile ap;
+       const char ** volatile ap = NULL;
        char ** volatile up;
-       const char *s, *cp;
+       const char *s, *ccp;
        struct ioword **iowp;
        struct tbl *tp = NULL;
+       char *cp;
 
        if (t == NULL)
                return (0);
@@ -71,15 +74,60 @@ execute(struct op *volatile t,
        if (trap)
                runtraps(0);
 
+       /* we want to run an executable, do some variance checks */
        if (t->type == TCOM) {
-               /* Clear subst_exstat before argument expansion. Used by
+               /* check if this is 'var=<<EOF' */
+               if (
+                   /* we have zero arguments, i.e. no programme to run */
+                   t->args[0] == NULL &&
+                   /* we have exactly one variable assignment */
+                   t->vars[0] != NULL && t->vars[1] == NULL &&
+                   /* we have exactly one I/O redirection */
+                   t->ioact != NULL && t->ioact[0] != NULL &&
+                   t->ioact[1] == NULL &&
+                   /* of type "here document" (or "here string") */
+                   (t->ioact[0]->flag & IOTYPE) == IOHERE &&
+                   /* the variable assignment begins with a valid varname */
+                   (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
+                   /* and has no right-hand side (i.e. "varname=") */
+                   ccp[0] == CHAR && ccp[1] == '=' && ccp[2] == EOS &&
+                   /* plus we can have a here document content */
+                   herein(t->ioact[0]->heredoc, t->ioact[0]->flag & IOEVAL,
+                   &cp) == 0 && cp && *cp) {
+                       char *sp = cp, *dp;
+                       size_t n = ccp - t->vars[0] + 2, z;
+
+                       /* drop redirection (will be garbage collected) */
+                       t->ioact = NULL;
+
+                       /* set variable to its expanded value */
+                       z = strlen(cp) + 1;
+                       if (notoktomul(z, 2) || notoktoadd(z * 2, n))
+                               internal_errorf(Toomem, (unsigned long)-1);
+                       dp = alloc(z * 2 + n, ATEMP);
+                       memcpy(dp, t->vars[0], n);
+                       t->vars[0] = dp;
+                       dp += n;
+                       while (*sp) {
+                               *dp++ = QCHAR;
+                               *dp++ = *sp++;
+                       }
+                       *dp = EOS;
+                       /* free the expanded value */
+                       afree(cp, APERM);
+               }
+
+               /*
+                * Clear subst_exstat before argument expansion. Used by
                 * null commands (see comexec() and c_eval()) and by c_set().
                 */
                subst_exstat = 0;
 
-               current_lineno = t->lineno;     /* for $LINENO */
+               /* for $LINENO */
+               current_lineno = t->lineno;
 
-               /* POSIX says expand command words first, then redirections,
+               /*
+                * POSIX says expand command words first, then redirections,
                 * and assignments last..
                 */
                up = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
@@ -88,8 +136,8 @@ execute(struct op *volatile t,
                        timex_hook(t, &up);
                ap = (const char **)up;
                if (Flag(FXTRACE) && ap[0]) {
-                       shf_fprintf(shl_out, "%s",
-                               substitute(str_val(global("PS4")), 0));
+                       shf_puts(substitute(str_val(global("PS4")), 0),
+                           shl_out);
                        for (i = 0; ap[i]; i++)
                                shf_fprintf(shl_out, "%s%c", ap[i],
                                    ap[i + 1] ? ' ' : '\n');
@@ -101,17 +149,21 @@ execute(struct op *volatile t,
        flags &= ~XTIME;
 
        if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
-               e->savefd = alloc(NUFILE * sizeof(short), ATEMP);
+               e->savefd = alloc2(NUFILE, sizeof(short), ATEMP);
                /* initialise to not redirected */
                memset(e->savefd, 0, NUFILE * sizeof(short));
        }
 
+       /* mark for replacement later (unless TPIPE) */
+       vp_pipest->flag |= INT_L;
+
        /* do redirection, to be restored in quitenv() */
        if (t->ioact != NULL)
                for (iowp = t->ioact; *iowp != NULL; iowp++) {
                        if (iosetup(*iowp, tp) < 0) {
                                exstat = rv = 1;
-                               /* Redirection failures for special commands
+                               /*
+                                * Redirection failures for special commands
                                 * cause (non-interactive) shell to exit.
                                 */
                                if (tp && tp->type == CSHELL &&
@@ -138,7 +190,8 @@ execute(struct op *volatile t,
                e->savefd[1] = savefd(1);
                while (t->type == TPIPE) {
                        openpipe(pv);
-                       ksh_dup2(pv[1], 1, false); /* stdout of curr */
+                       /* stdout of curr */
+                       ksh_dup2(pv[1], 1, false);
                        /**
                         * Let exchild() close pv[0] in child
                         * (if this isn't done, commands like
@@ -147,15 +200,18 @@ execute(struct op *volatile t,
                         */
                        exchild(t->left, flags | XPIPEO | XCCLOSE,
                            NULL, pv[0]);
-                       ksh_dup2(pv[0], 0, false); /* stdin of next */
+                       /* stdin of next */
+                       ksh_dup2(pv[0], 0, false);
                        closepipe(pv);
                        flags |= XPIPEI;
                        t = t->right;
                }
-               restfd(1, e->savefd[1]); /* stdout of last */
-               e->savefd[1] = 0; /* no need to re-restore this */
+               /* stdout of last */
+               restfd(1, e->savefd[1]);
+               /* no need to re-restore this */
+               e->savefd[1] = 0;
                /* Let exchild() close 0 in parent, after fork, before wait */
-               i = exchild(t, flags | XPCLOSE, xerrok, 0);
+               i = exchild(t, flags | XPCLOSE | XPIPEST, xerrok, 0);
                if (!(flags&XBGND) && !(flags&XXCOM))
                        rv = i;
                break;
@@ -169,9 +225,11 @@ execute(struct op *volatile t,
                break;
 
        case TCOPROC: {
+#ifndef MKSH_NOPROSPECTOFWORK
                sigset_t omask;
 
-               /* Block sigchild as we are using things changed in the
+               /*
+                * Block sigchild as we are using things changed in the
                 * signal handler
                 */
                sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
@@ -183,6 +241,7 @@ execute(struct op *volatile t,
                        unwind(i);
                        /* NOTREACHED */
                }
+#endif
                /* Already have a (live) co-process? */
                if (coproc.job && coproc.write >= 0)
                        errorf("coprocess already exists");
@@ -208,15 +267,20 @@ execute(struct op *volatile t,
                        openpipe(pv);
                        coproc.read = pv[0];
                        ksh_dup2(pv[1], 1, false);
-                       coproc.readw = pv[1];    /* closed before first read */
+                       /* closed before first read */
+                       coproc.readw = pv[1];
                        coproc.njobs = 0;
                        /* create new coprocess id */
                        ++coproc.id;
                }
+#ifndef MKSH_NOPROSPECTOFWORK
                sigprocmask(SIG_SETMASK, &omask, NULL);
-               e->type = E_EXEC; /* no more need for error handler */
+               /* no more need for error handler */
+               e->type = E_EXEC;
+#endif
 
-               /* exchild() closes coproc.* in child after fork,
+               /*
+                * exchild() closes coproc.* in child after fork,
                 * will also increment coproc.njobs when the
                 * job is actually created.
                 */
@@ -227,7 +291,8 @@ execute(struct op *volatile t,
        }
 
        case TASYNC:
-               /* XXX non-optimal, I think - "(foo &)", forks for (),
+               /*
+                * XXX non-optimal, I think - "(foo &)", forks for (),
                 * forks again for async... parent should optimise
                 * this to "foo &"...
                 */
@@ -272,7 +337,7 @@ execute(struct op *volatile t,
                    (const char **)eval((const char **)t->vars,
                    DOBLANK | DOGLOB | DOTILDE);
                e->type = E_LOOP;
-               while (1) {
+               while (/* CONSTCOND */ 1) {
                        i = sigsetjmp(e->jbuf, 0);
                        if (!i)
                                break;
@@ -285,20 +350,22 @@ execute(struct op *volatile t,
                                goto Break;
                        }
                }
-               rv = 0; /* in case of a continue */
+               /* in case of a continue */
+               rv = 0;
                if (t->type == TFOR) {
                        while (*ap != NULL) {
                                setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
                                rv = execute(t->left, flags & XERROK, xerrok);
                        }
-               } else { /* TSELECT */
+               } else {
+                       /* TSELECT */
                        for (;;) {
-                               if (!(cp = do_selectargs(ap, is_first))) {
+                               if (!(ccp = do_selectargs(ap, is_first))) {
                                        rv = 1;
                                        break;
                                }
                                is_first = false;
-                               setstr(global(t->str), cp, KSH_UNWIND_ERROR);
+                               setstr(global(t->str), ccp, KSH_UNWIND_ERROR);
                                execute(t->left, flags & XERROK, xerrok);
                        }
                }
@@ -308,7 +375,7 @@ execute(struct op *volatile t,
        case TWHILE:
        case TUNTIL:
                e->type = E_LOOP;
-               while (1) {
+               while (/* CONSTCOND */ 1) {
                        i = sigsetjmp(e->jbuf, 0);
                        if (!i)
                                break;
@@ -321,7 +388,8 @@ execute(struct op *volatile t,
                                goto Break;
                        }
                }
-               rv = 0; /* in case of a continue */
+               /* in case of a continue */
+               rv = 0;
                while ((execute(t->left, XERROK, NULL) == 0) ==
                    (t->type == TWHILE))
                        rv = execute(t->right, flags & XERROK, xerrok);
@@ -330,22 +398,38 @@ execute(struct op *volatile t,
        case TIF:
        case TELIF:
                if (t->right == NULL)
-                       break;  /* should be error */
+                       /* should be error */
+                       break;
                rv = execute(t->left, XERROK, NULL) == 0 ?
                    execute(t->right->left, flags & XERROK, xerrok) :
                    execute(t->right->right, flags & XERROK, xerrok);
                break;
 
        case TCASE:
-               cp = evalstr(t->str, DOTILDE);
-               for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
-                   for (ap = (const char **)t->vars; *ap; ap++)
-                       if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
-                           gmatchx(cp, s, false))
-                               goto Found;
-               break;
- Found:
-               rv = execute(t->left, flags & XERROK, xerrok);
+               i = 0;
+               ccp = evalstr(t->str, DOTILDE);
+               for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
+                       for (ap = (const char **)t->vars; *ap; ap++) {
+                               if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
+                                   gmatchx(ccp, s, false))) {
+                                       rv = execute(t->left, flags & XERROK,
+                                           xerrok);
+                                       i = 0;
+                                       switch (t->u.charflag) {
+                                       case '&':
+                                               i = 1;
+                                               /* FALLTHROUGH */
+                                       case '|':
+                                               goto TCASE_next;
+                                       }
+                                       goto TCASE_out;
+                               }
+                       }
+                       i = 0;
+ TCASE_next:
+                       /* empty */;
+               }
+ TCASE_out:
                break;
 
        case TBRACE:
@@ -357,13 +441,15 @@ execute(struct op *volatile t,
                break;
 
        case TTIME:
-               /* Clear XEXEC so nested execute() call doesn't exit
+               /*
+                * Clear XEXEC so nested execute() call doesn't exit
                 * (allows "ls -l | time grep foo").
                 */
                rv = timex(t, flags & ~XEXEC, xerrok);
                break;
 
-       case TEXEC:             /* an eval'd TCOM */
+       case TEXEC:
+               /* an eval'd TCOM */
                s = t->args[0];
                up = makenv();
                restoresigs();
@@ -382,13 +468,21 @@ execute(struct op *volatile t,
        }
  Break:
        exstat = rv;
+       if (vp_pipest->flag & INT_L) {
+               unset(vp_pipest, 1);
+               vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY |
+                   ARRAY | INT_U;
+               vp_pipest->val.i = rv;
+       }
 
-       quitenv(NULL);          /* restores IO */
+       /* restores IO */
+       quitenv(NULL);
        if ((flags&XEXEC))
-               unwind(LEXIT);  /* exit child */
+               /* exit child */
+               unwind(LEXIT);
        if (rv != 0 && !(flags & XERROK) &&
            (xerrok == NULL || !*xerrok)) {
-               trapsig(SIGERR_);
+               trapsig(ksh_SIGERR);
                if (Flag(FERREXIT))
                        unwind(LERROR);
        }
@@ -400,21 +494,23 @@ execute(struct op *volatile t,
  */
 
 static int
-comexec(struct op *t, struct tbl *volatile tp, const char **ap,
+comexec(struct op *t, struct tbl * volatile tp, const char **ap,
     volatile int flags, volatile int *xerrok)
 {
        int i;
        volatile int rv = 0;
        const char *cp;
        const char **lastp;
-       static struct op texec; /* Must be static (XXX but why?) */
+       /* Must be static (XXX but why?) */
+       static struct op texec;
        int type_flags;
        int keepasn_ok;
        int fcflags = FC_BI|FC_FUNC|FC_PATH;
        bool bourne_function_call = false;
        struct block *l_expand, *l_assign;
 
-       /* snag the last argument for $_ XXX not the same as AT&T ksh,
+       /*
+        * snag the last argument for $_ XXX not the same as AT&T ksh,
         * which only seems to set $_ after a newline (but not in
         * functions/dot scripts, but in interactive and script) -
         * perhaps save last arg here and set it in shell()?.
@@ -427,7 +523,8 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                    KSH_RETURN_ERROR);
        }
 
-       /* Deal with the shell builtins builtin, exec and command since
+       /**
+        * Deal with the shell builtins builtin, exec and command since
         * they can be followed by other commands. This must be done before
         * we know if we should create a local block which must be done
         * before we can do a path search (in case the assignments change
@@ -441,15 +538,16 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
         */
        keepasn_ok = 1;
        while (tp && tp->type == CSHELL) {
-               fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
+               /* undo effects of command */
+               fcflags = FC_BI|FC_FUNC|FC_PATH;
                if (tp->val.f == c_builtin) {
-                       if ((cp = *++ap) == NULL) {
+                       if ((cp = *++ap) == NULL ||
+                           (!strcmp(cp, "--") && (cp = *++ap) == NULL)) {
                                tp = NULL;
                                break;
                        }
-                       tp = findcom(cp, FC_BI);
-                       if (tp == NULL)
-                               errorf("builtin: %s: not a builtin", cp);
+                       if ((tp = findcom(cp, FC_BI)) == NULL)
+                               errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
                        continue;
                } else if (tp->val.f == c_exec) {
                        if (ap[1] == NULL)
@@ -459,27 +557,30 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                } else if (tp->val.f == c_command) {
                        int optc, saw_p = 0;
 
-                       /* Ugly dealing with options in two places (here and
-                        * in c_command(), but such is life)
+                       /*
+                        * Ugly dealing with options in two places (here
+                        * and in c_command(), but such is life)
                         */
                        ksh_getopt_reset(&builtin_opt, 0);
                        while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
                                saw_p = 1;
                        if (optc != EOF)
-                               break;  /* command -vV or something */
+                               /* command -vV or something */
+                               break;
                        /* don't look for functions */
                        fcflags = FC_BI|FC_PATH;
                        if (saw_p) {
                                if (Flag(FRESTRICTED)) {
-                                       warningf(true,
-                                           "command -prestricted");
+                                       warningf(true, "%s: %s",
+                                           "command -p", "restricted");
                                        rv = 1;
                                        goto Leave;
                                }
                                fcflags |= FC_DEFPATH;
                        }
                        ap += builtin_opt.optind;
-                       /* POSIX says special builtins lose their status
+                       /*
+                        * POSIX says special builtins lose their status
                         * if accessed using command.
                         */
                        keepasn_ok = 0;
@@ -488,6 +589,25 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                                subst_exstat = 0;
                                break;
                        }
+#ifndef MKSH_NO_EXTERNAL_CAT
+               } else if (tp->val.f == c_cat) {
+                       /*
+                        * if we have any flags, do not use the builtin
+                        * in theory, we could allow -u, but that would
+                        * mean to use ksh_getopt here and possibly ad-
+                        * ded complexity and more code and isn't worth
+                        * additional hassle (and the builtin must call
+                        * ksh_getopt already but can't come back here)
+                        */
+                       if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
+                           /* argument, begins with -, is not - or -- */
+                           (ap[1][1] != '-' || ap[1][2] != '\0'))
+                               /* don't look for builtins or functions */
+                               fcflags = FC_PATH;
+                       else
+                               /* go on, use the builtin */
+                               break;
+#endif
                } else
                        break;
                tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
@@ -518,8 +638,8 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
 
                if (Flag(FXTRACE)) {
                        if (i == 0)
-                               shf_fprintf(shl_out, "%s",
-                                       substitute(str_val(global("PS4")), 0));
+                               shf_puts(substitute(str_val(global("PS4")), 0),
+                                   shl_out);
                        shf_fprintf(shl_out, "%s%c", cp,
                            t->vars[i + 1] ? ' ' : '\n');
                        if (!t->vars[i + 1])
@@ -535,7 +655,7 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                goto Leave;
        } else if (!tp) {
                if (Flag(FRESTRICTED) && vstrchr(cp, '/')) {
-                       warningf(true, "%s: restricted", cp);
+                       warningf(true, "%s: %s", cp, "restricted");
                        rv = 1;
                        goto Leave;
                }
@@ -543,54 +663,49 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
        }
 
        switch (tp->type) {
-       case CSHELL:                    /* shell built-in */
+
+       /* shell built-in */
+       case CSHELL:
                rv = call_builtin(tp, (const char **)ap);
                break;
 
-       case CFUNC: {                   /* function call */
+       /* function call */
+       case CFUNC: {
                volatile unsigned char old_xflag;
-               volatile Tflag old_inuse;
-               const char *volatile old_kshname;
+               volatile uint32_t old_inuse;
+               const char * volatile old_kshname;
 
                if (!(tp->flag & ISSET)) {
                        struct tbl *ftp;
 
                        if (!tp->u.fpath) {
-                               if (tp->u2.errno_) {
-                                       warningf(true,
-                                           "%s: can't find function "
-                                           "definition file - %s",
-                                           cp, strerror(tp->u2.errno_));
-                                       rv = 126;
-                               } else {
-                                       warningf(true,
-                                           "%s: can't find function "
-                                           "definition file", cp);
-                                       rv = 127;
-                               }
+                               rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
+                               warningf(true, "%s: %s %s: %s", cp,
+                                   "can't find", "function definition file",
+                                   strerror(tp->u2.errnov));
                                break;
                        }
                        if (include(tp->u.fpath, 0, NULL, 0) < 0) {
                                rv = errno;
-                               warningf(true,
-                                   "%s: can't open function definition file %s - %s",
-                                   cp, tp->u.fpath, strerror(rv));
+                               warningf(true, "%s: %s %s %s: %s", cp,
+                                   "can't open", "function definition file",
+                                   tp->u.fpath, strerror(rv));
                                rv = 127;
                                break;
                        }
                        if (!(ftp = findfunc(cp, hash(cp), false)) ||
                            !(ftp->flag & ISSET)) {
-                               warningf(true,
-                                   "%s: function not defined by %s",
-                                   cp, tp->u.fpath);
+                               warningf(true, "%s: %s %s", cp,
+                                   "function not defined by", tp->u.fpath);
                                rv = 127;
                                break;
                        }
                        tp = ftp;
                }
 
-               /* ksh functions set $0 to function name, POSIX functions leave
-                * $0 unchanged.
+               /*
+                * ksh functions set $0 to function name, POSIX
+                * functions leave $0 unchanged.
                 */
                old_kshname = kshname;
                if (tp->flag & FKSH)
@@ -601,7 +716,8 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                for (i = 0; *ap++ != NULL; i++)
                        ;
                e->loc->argc = i - 1;
-               /* ksh-style functions handle getopts sanely,
+               /*
+                * ksh-style functions handle getopts sanely,
                 * Bourne/POSIX functions are insane...
                 */
                if (tp->flag & FKSH) {
@@ -611,7 +727,7 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                }
 
                old_xflag = Flag(FXTRACE);
-               Flag(FXTRACE) = tp->flag & TRACE ? 1 : 0;
+               Flag(FXTRACE) |= tp->flag & TRACE ? 1 : 0;
 
                old_inuse = tp->flag & FINUSE;
                tp->flag |= FINUSE;
@@ -626,9 +742,10 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                kshname = old_kshname;
                Flag(FXTRACE) = old_xflag;
                tp->flag = (tp->flag & ~FINUSE) | old_inuse;
-               /* Were we deleted while executing? If so, free the execution
-                * tree. todo: Unfortunately, the table entry is never re-used
-                * until the lookup table is expanded.
+               /*
+                * Were we deleted while executing? If so, free the
+                * execution tree. TODO: Unfortunately, the table entry
+                * is never re-used until the lookup table is expanded.
                 */
                if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
                        if (tp->flag & ALLOC) {
@@ -651,26 +768,23 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
                        /* NOTREACHED */
                default:
                        quitenv(NULL);
-                       internal_errorf("CFUNC %d", i);
+                       internal_errorf("%s %d", "CFUNC", i);
                }
                break;
        }
 
-       case CEXEC:             /* executable command */
-       case CTALIAS:           /* tracked alias */
+       /* executable command */
+       case CEXEC:
+       /* tracked alias */
+       case CTALIAS:
                if (!(tp->flag&ISSET)) {
-                       /* errno_ will be set if the named command was found
-                        * but could not be executed (permissions, no execute
-                        * bit, directory, etc). Print out a (hopefully)
-                        * useful error message and set the exit status to 126.
-                        */
-                       if (tp->u2.errno_) {
-                               warningf(true, "%s: cannot execute - %s", cp,
-                                   strerror(tp->u2.errno_));
-                               rv = 126;       /* POSIX */
-                       } else {
-                               warningf(true, "%s: not found", cp);
+                       if (tp->u2.errnov == ENOENT) {
                                rv = 127;
+                               warningf(true, "%s: %s", cp, "not found");
+                       } else {
+                               rv = 126;
+                               warningf(true, "%s: %s: %s", cp, "can't execute",
+                                   strerror(tp->u2.errnov));
                        }
                        break;
                }
@@ -694,7 +808,8 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
 
                /* to fork we set up a TEXEC node and call execute */
                texec.type = TEXEC;
-               texec.left = t; /* for tprint */
+               /* for tprint */
+               texec.left = t;
                texec.str = tp->val.s;
                texec.args = ap;
                rv = exchild(&texec, flags, xerrok, -1);
@@ -714,14 +829,15 @@ scriptexec(struct op *tp, const char **ap)
        const char *sh;
 #ifndef MKSH_SMALL
        unsigned char *cp;
-       char buf[64];           /* 64 == MAXINTERP in MirBSD <sys/param.h> */
+       /* 64 == MAXINTERP in MirBSD <sys/param.h> */
+       char buf[64];
        int fd;
 #endif
        union mksh_ccphack args, cap;
 
        sh = str_val(global("EXECSHELL"));
        if (sh && *sh)
-               sh = search(sh, path, X_OK, NULL);
+               sh = search_path(sh, path, X_OK, NULL);
        if (!sh || !*sh)
                sh = MKSH_DEFAULT_EXECSHELL;
 
@@ -734,8 +850,15 @@ scriptexec(struct op *tp, const char **ap)
                        /* read error -> no good */
                        buf[0] = '\0';
                close(fd);
-               /* scan for newline (or CR) or NUL _before_ end of buffer */
+
+               /* skip UTF-8 Byte Order Mark, if present */
                cp = (unsigned char *)buf;
+               if ((cp[0] == 0xEF) && (cp[1] == 0xBB) && (cp[2] == 0xBF))
+                       cp += 3;
+               /* save begin of shebang for later */
+               fd = (char *)cp - buf;          /* either 0 or (if BOM) 3 */
+
+               /* scan for newline (or CR) or NUL _before_ end of buffer */
                while ((char *)cp < (buf + sizeof(buf)))
                        if (*cp == '\0' || *cp == '\n' || *cp == '\r') {
                                *cp = '\0';
@@ -745,13 +868,13 @@ scriptexec(struct op *tp, const char **ap)
                /* if the shebang line is longer than MAXINTERP, bail out */
                if ((char *)cp >= (buf + sizeof(buf)))
                        goto noshebang;
-               /* skip UTF-8 Byte Order Mark, if present */
-               cp = (unsigned char *)buf;
-               if ((cp[0] == 0xEF) && (cp[1] == 0xBB) && (cp[2] == 0xBF))
-                       cp += 3;
+
+               /* restore begin of shebang position (buf+0 or buf+3) */
+               cp = (unsigned char *)(buf + fd);
                /* bail out if read error (above) or no shebang */
                if ((cp[0] != '#') || (cp[1] != '!'))
                        goto noshebang;
+
                cp += 2;
                /* skip whitespace before shell name */
                while (*cp == ' ' || *cp == '\t')
@@ -806,7 +929,7 @@ shcomexec(const char **wp)
 
        tp = ktsearch(&builtins, *wp, hash(*wp));
        if (tp == NULL)
-               internal_errorf("shcomexec: %s", *wp);
+               internal_errorf("%s: %s", "shcomexec", *wp);
        return (call_builtin(tp, wp));
 }
 
@@ -842,20 +965,31 @@ findfunc(const char *name, uint32_t h, bool create)
 int
 define(const char *name, struct op *t)
 {
+       uint32_t nhash;
        struct tbl *tp;
        bool was_set = false;
 
-       while (1) {
-               tp = findfunc(name, hash(name), true);
+       nhash = hash(name);
+
+       if (t != NULL && !tobool(t->u.ksh_func)) {
+               /* drop same-name aliases for POSIX functions */
+               if ((tp = ktsearch(&aliases, name, nhash)))
+                       ktdelete(tp);
+       }
+
+       while (/* CONSTCOND */ 1) {
+               tp = findfunc(name, nhash, true);
 
                if (tp->flag & ISSET)
                        was_set = true;
-               /* If this function is currently being executed, we zap this
-                * table entry so findfunc() won't see it
+               /*
+                * If this function is currently being executed, we zap
+                * this table entry so findfunc() won't see it
                 */
                if (tp->flag & FINUSE) {
                        tp->name[0] = '\0';
-                       tp->flag &= ~DEFINED; /* ensure it won't be found */
+                       /* ensure it won't be found */
+                       tp->flag &= ~DEFINED;
                        tp->flag |= FDELETE;
                } else
                        break;
@@ -866,7 +1000,8 @@ define(const char *name, struct op *t)
                tfree(tp->val.t, tp->areap);
        }
 
-       if (t == NULL) {                /* undefine */
+       if (t == NULL) {
+               /* undefine */
                ktdelete(tp);
                return (was_set ? 0 : 1);
        }
@@ -882,19 +1017,22 @@ define(const char *name, struct op *t)
 /*
  * add builtin
  */
-void
+const char *
 builtin(const char *name, int (*func) (const char **))
 {
        struct tbl *tp;
-       Tflag flag;
+       uint32_t flag;
 
        /* see if any flags should be set for this builtin */
        for (flag = 0; ; name++) {
-               if (*name == '=')       /* command does variable assignment */
+               if (*name == '=')
+                       /* command does variable assignment */
                        flag |= KEEPASN;
-               else if (*name == '*')  /* POSIX special builtin */
+               else if (*name == '*')
+                       /* POSIX special builtin */
                        flag |= SPEC_BI;
-               else if (*name == '+')  /* POSIX regular builtin */
+               else if (*name == '+')
+                       /* POSIX regular builtin */
                        flag |= REG_BI;
                else
                        break;
@@ -904,6 +1042,8 @@ builtin(const char *name, int (*func) (const char **))
        tp->flag = DEFINED | flag;
        tp->type = CSHELL;
        tp->val.f = func;
+
+       return (name);
 }
 
 /*
@@ -916,8 +1056,10 @@ findcom(const char *name, int flags)
        static struct tbl temp;
        uint32_t h = hash(name);
        struct tbl *tp = NULL, *tbi;
-       unsigned char insert = Flag(FTRACKALL); /* insert if not found */
-       char *fpath;                    /* for function autoloading */
+       /* insert if not found */
+       unsigned char insert = Flag(FTRACKALL);
+       /* for function autoloading */
+       char *fpath;
        union mksh_cchack npath;
 
        if (vstrchr(name, '/')) {
@@ -927,7 +1069,8 @@ findcom(const char *name, int flags)
                goto Search;
        }
        tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
-       /* POSIX says special builtins first, then functions, then
+       /*
+        * POSIX says special builtins first, then functions, then
         * POSIX regular builtins, then search path...
         */
        if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
@@ -937,10 +1080,10 @@ findcom(const char *name, int flags)
                if (tp && !(tp->flag & ISSET)) {
                        if ((fpath = str_val(global("FPATH"))) == null) {
                                tp->u.fpath = NULL;
-                               tp->u2.errno_ = 0;
+                               tp->u2.errnov = ENOENT;
                        } else
-                               tp->u.fpath = search(name, fpath, R_OK,
-                                   &tp->u2.errno_);
+                               tp->u.fpath = search_path(name, fpath, R_OK,
+                                   &tp->u2.errnov);
                }
        }
        if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
@@ -949,7 +1092,8 @@ findcom(const char *name, int flags)
                tp = tbi;
        if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
                tp = ktsearch(&taliases, name, h);
-               if (tp && (tp->flag & ISSET) && access(tp->val.s, X_OK) != 0) {
+               if (tp && (tp->flag & ISSET) &&
+                   ksh_access(tp->val.s, X_OK) != 0) {
                        if (tp->flag & ALLOC) {
                                tp->flag &= ~ALLOC;
                                afree(tp->val.s, APERM);
@@ -969,10 +1113,12 @@ findcom(const char *name, int flags)
                                tp = &temp;
                                tp->type = CEXEC;
                        }
-                       tp->flag = DEFINED;     /* make ~ISSET */
+                       /* make ~ISSET */
+                       tp->flag = DEFINED;
                }
-               npath.ro = search(name, flags & FC_DEFPATH ? def_path : path,
-                   X_OK, &tp->u2.errno_);
+               npath.ro = search_path(name,
+                   (flags & FC_DEFPATH) ? def_path : path,
+                   X_OK, &tp->u2.errnov);
                if (npath.ro) {
                        strdupx(tp->val.s, npath.ro, APERM);
                        if (npath.ro != name)
@@ -980,16 +1126,18 @@ findcom(const char *name, int flags)
                        tp->flag |= ISSET|ALLOC;
                } else if ((flags & FC_FUNC) &&
                    (fpath = str_val(global("FPATH"))) != null &&
-                   (npath.ro = search(name, fpath, R_OK,
-                   &tp->u2.errno_)) != NULL) {
-                       /* An undocumented feature of AT&T ksh is that it
-                        * searches FPATH if a command is not found, even
-                        * if the command hasn't been set up as an autoloaded
-                        * function (ie, no typeset -uf).
+                   (npath.ro = search_path(name, fpath, R_OK,
+                   &tp->u2.errnov)) != NULL) {
+                       /*
+                        * An undocumented feature of AT&T ksh is that
+                        * it searches FPATH if a command is not found,
+                        * even if the command hasn't been set up as an
+                        * autoloaded function (ie, no typeset -uf).
                         */
                        tp = &temp;
                        tp->type = CFUNC;
-                       tp->flag = DEFINED; /* make ~ISSET */
+                       /* make ~ISSET */
+                       tp->flag = DEFINED;
                        tp->u.fpath = npath.ro;
                }
        }
@@ -998,9 +1146,10 @@ findcom(const char *name, int flags)
 
 /*
  * flush executable commands with relative paths
+ * (just relative or all?)
  */
 void
-flushcom(int all)      /* just relative or all */
+flushcom(bool all)
 {
        struct tbl *tp;
        struct tstate ts;
@@ -1015,49 +1164,50 @@ flushcom(int all)       /* just relative or all */
                }
 }
 
-/* Check if path is something we want to find. Returns -1 for failure. */
-int
-search_access(const char *lpath, int mode,
-    int *errnop)       /* set if candidate found, but not suitable */
+/* check if path is something we want to find */
+static int
+search_access(const char *fn, int mode)
 {
-       int ret, err = 0;
-       struct stat statb;
-
-       if (stat(lpath, &statb) < 0)
-               return (-1);
-       ret = access(lpath, mode);
-       if (ret < 0)
-               err = errno; /* File exists, but we can't access it */
-       else if (mode == X_OK && (!S_ISREG(statb.st_mode) ||
-           !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) {
-               /* This 'cause access() says root can execute everything */
-               ret = -1;
-               err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
-       }
-       if (err && errnop && !*errnop)
-               *errnop = err;
-       return (ret);
+       struct stat sb;
+
+       if (stat(fn, &sb) < 0)
+               /* file does not exist */
+               return (ENOENT);
+       /* LINTED use of access */
+       if (access(fn, mode) < 0)
+               /* file exists, but we can't access it */
+               return (errno);
+       if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
+           !(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
+               /* access(2) may say root can execute everything */
+               return (S_ISDIR(sb.st_mode) ? EISDIR : EACCES);
+       return (0);
 }
 
 /*
  * search for command with PATH
  */
 const char *
-search(const char *name, const char *lpath,
-    int mode,          /* R_OK or X_OK */
-    int *errnop)       /* set if candidate found, but not suitable */
+search_path(const char *name, const char *lpath,
+    /* R_OK or X_OK */
+    int mode,
+    /* set if candidate found, but not suitable */
+    int *errnop)
 {
        const char *sp, *p;
        char *xp;
        XString xs;
-       int namelen;
+       size_t namelen;
+       int ec = 0, ev;
 
-       if (errnop)
-               *errnop = 0;
        if (vstrchr(name, '/')) {
-               if (search_access(name, mode, errnop) == 0)
+               if ((ec = search_access(name, mode)) == 0) {
+ search_path_ok:
+                       if (errnop)
+                               *errnop = 0;
                        return (name);
-               return (NULL);
+               }
+               goto search_path_err;
        }
 
        namelen = strlen(name) + 1;
@@ -1077,12 +1227,20 @@ search(const char *name, const char *lpath,
                sp = p;
                XcheckN(xs, xp, namelen);
                memcpy(xp, name, namelen);
-               if (search_access(Xstring(xs, xp), mode, errnop) == 0)
-                       return (Xclose(xs, xp + namelen));
+               if ((ev = search_access(Xstring(xs, xp), mode)) == 0) {
+                       name = Xclose(xs, xp + namelen);
+                       goto search_path_ok;
+               }
+               /* accumulate non-ENOENT errors only */
+               if (ev != ENOENT && ec == 0)
+                       ec = ev;
                if (*sp++ == '\0')
                        sp = NULL;
        }
        Xfree(xs, xp);
+ search_path_err:
+       if (errnop)
+               *errnop = ec ? ec : ENOENT;
        return (NULL);
 }
 
@@ -1094,11 +1252,11 @@ call_builtin(struct tbl *tp, const char **wp)
        builtin_argv0 = wp[0];
        builtin_flag = tp->flag;
        shf_reopen(1, SHF_WR, shl_stdout);
-       shl_stdout_ok = 1;
+       shl_stdout_ok = true;
        ksh_getopt_reset(&builtin_opt, GF_ERROR);
        rv = (*tp->val.f)(wp);
        shf_flush(shl_stdout);
-       shl_stdout_ok = 0;
+       shl_stdout_ok = false;
        builtin_flag = 0;
        builtin_argv0 = NULL;
        return (rv);
@@ -1141,7 +1299,8 @@ iosetup(struct ioword *iop, struct tbl *tp)
 
        case IOWRITE:
                flags = O_WRONLY | O_CREAT | O_TRUNC;
-               /* The stat() is here to allow redirections to
+               /*
+                * The stat() is here to allow redirections to
                 * things like /dev/null without error.
                 */
                if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
@@ -1156,7 +1315,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
        case IOHERE:
                do_open = 0;
                /* herein() returns -2 if error has been printed */
-               u = herein(iop->heredoc, iop->flag & IOEVAL);
+               u = herein(iop->heredoc, iop->flag & IOEVAL, NULL);
                /* cp may have wrong name */
                break;
 
@@ -1165,7 +1324,8 @@ iosetup(struct ioword *iop, struct tbl *tp)
 
                do_open = 0;
                if (*cp == '-' && !cp[1]) {
-                       u = 1009;        /* prevent error return below */
+                       /* prevent error return below */
+                       u = 1009;
                        do_close = 1;
                } else if ((u = check_fd(cp,
                    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
@@ -1175,14 +1335,15 @@ iosetup(struct ioword *iop, struct tbl *tp)
                        return (-1);
                }
                if (u == iop->unit)
-                       return (0);             /* "dup from" == "dup to" */
+                       /* "dup from" == "dup to" */
+                       return (0);
                break;
        }
        }
 
        if (do_open) {
                if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
-                       warningf(true, "%s: restricted", cp);
+                       warningf(true, "%s: %s", cp, "restricted");
                        return (-1);
                }
                u = open(cp, flags, 0666);
@@ -1191,7 +1352,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
                /* herein() may already have printed message */
                if (u == -1) {
                        u = errno;
-                       warningf(true, "cannot %s %s: %s",
+                       warningf(true, "can't %s %s: %s",
                            iotype == IODUP ? "dup" :
                            (iotype == IOREAD || iotype == IOHERE) ?
                            "open" : "create", cp, strerror(u));
@@ -1204,7 +1365,8 @@ iosetup(struct ioword *iop, struct tbl *tp)
                if (u == iop->unit)
                        e->savefd[iop->unit] = -1;
                else
-                       /* c_exec() assumes e->savefd[fd] set for any
+                       /*
+                        * c_exec() assumes e->savefd[fd] set for any
                         * redirections. Ask savefd() not to close iop->unit;
                         * this allows error messages to be seen if iop->unit
                         * is 2; also means we can't lose the fd (eg, both
@@ -1220,8 +1382,8 @@ iosetup(struct ioword *iop, struct tbl *tp)
                        int ev;
 
                        ev = errno;
-                       warningf(true,
-                           "could not finish (dup) redirection %s: %s",
+                       warningf(true, "%s %s %s",
+                           "can't finish (dup) redirection",
                            snptreef(NULL, 32, "%R", &iotmp),
                            strerror(ev));
                        if (iotype != IODUP)
@@ -1230,84 +1392,111 @@ iosetup(struct ioword *iop, struct tbl *tp)
                }
                if (iotype != IODUP)
                        close(u);
-               /* Touching any co-process fd in an empty exec
+               /*
+                * Touching any co-process fd in an empty exec
                 * causes the shell to close its copies
                 */
                else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
-                       if (iop->flag & IORDUP) /* possible exec <&p */
+                       if (iop->flag & IORDUP)
+                               /* possible exec <&p */
                                coproc_read_close(u);
-                       else                    /* possible exec >&p */
+                       else
+                               /* possible exec >&p */
                                coproc_write_close(u);
                }
        }
-       if (u == 2) /* Clear any write errors */
+       if (u == 2)
+               /* Clear any write errors */
                shf_reopen(2, SHF_WR, shl_out);
        return (0);
 }
 
 /*
- * open here document temp file.
- * if unquoted here, expand here temp file into second temp file.
+ * Process here documents by providing the content, either as
+ * result (globally allocated) string or in a temp file; if
+ * unquoted, the string is expanded first.
  */
 static int
-herein(const char *content, int sub)
+hereinval(const char *content, int sub, char **resbuf, struct shf *shf)
+{
+       const char *ccp;
+       struct source *s, *osource;
+
+       osource = source;
+       newenv(E_ERRH);
+       if (sigsetjmp(e->jbuf, 0)) {
+               source = osource;
+               quitenv(shf);
+               /* special to iosetup(): don't print error */
+               return (-2);
+       }
+       if (sub) {
+               /* do substitutions on the content of heredoc */
+               s = pushs(SSTRING, ATEMP);
+               s->start = s->str = content;
+               source = s;
+               if (yylex(ONEWORD|HEREDOC) != LWORD)
+                       internal_errorf("%s: %s", "herein", "yylex");
+               source = osource;
+               ccp = evalstr(yylval.cp, 0);
+       } else
+               ccp = content;
+
+       if (resbuf == NULL)
+               shf_puts(ccp, shf);
+       else
+               strdupx(*resbuf, ccp, APERM);
+
+       quitenv(NULL);
+       return (0);
+}
+
+static int
+herein(const char *content, int sub, char **resbuf)
 {
-       volatile int fd = -1;
-       struct source *s, *volatile osource;
-       struct shf *volatile shf;
+       int fd = -1;
+       struct shf *shf;
        struct temp *h;
        int i;
 
        /* ksh -c 'cat << EOF' can cause this... */
        if (content == NULL) {
-               warningf(true, "here document missing");
-               return (-2); /* special to iosetup(): don't print error */
+               warningf(true, "%s missing", "here document");
+               /* special to iosetup(): don't print error */
+               return (-2);
        }
 
-       /* Create temp file to hold content (done before newenv so temp
-        * doesn't get removed too soon).
+       /* skip all the fd setup if we just want the value */
+       if (resbuf != NULL)
+               return (hereinval(content, sub, resbuf, NULL));
+
+       /*
+        * Create temp file to hold content (done before newenv
+        * so temp doesn't get removed too soon).
         */
        h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
        if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) {
-               fd = errno;
+               i = errno;
                warningf(true, "can't %s temporary file %s: %s",
-                   !shf ? "create" : "open",
-                   h->name, strerror(fd));
+                   !shf ? "create" : "open", h->name, strerror(i));
                if (shf)
                        shf_close(shf);
-               return (-2 /* special to iosetup(): don't print error */);
+               /* special to iosetup(): don't print error */
+               return (-2);
        }
 
-       osource = source;
-       newenv(E_ERRH);
-       i = sigsetjmp(e->jbuf, 0);
-       if (i) {
-               source = osource;
-               quitenv(shf);
+       if (hereinval(content, sub, NULL, shf) == -2) {
                close(fd);
-               return (-2); /* special to iosetup(): don't print error */
+               /* special to iosetup(): don't print error */
+               return (-2);
        }
-       if (sub) {
-               /* Do substitutions on the content of heredoc */
-               s = pushs(SSTRING, ATEMP);
-               s->start = s->str = content;
-               source = s;
-               if (yylex(ONEWORD|HEREDOC) != LWORD)
-                       internal_errorf("herein: yylex");
-               source = osource;
-               shf_puts(evalstr(yylval.cp, 0), shf);
-       } else
-               shf_puts(content, shf);
-
-       quitenv(NULL);
 
        if (shf_close(shf) == EOF) {
                i = errno;
                close(fd);
-               fd = errno;
-               warningf(true, "error writing %s: %s, %s", h->name,
-                   strerror(i), strerror(fd));
-               return (-2);    /* special to iosetup(): don't print error */
+               warningf(true, "%s: %s: %s", "write", h->name, strerror(i));
+               /* special to iosetup(): don't print error */
+               return (-2);
        }
 
        return (fd);
@@ -1328,8 +1517,9 @@ do_selectargs(const char **ap, bool print_menu)
 
        for (argct = 0; ap[argct]; argct++)
                ;
-       while (1) {
-               /* Menu is printed if
+       while (/* CONSTCOND */ 1) {
+               /*-
+                * Menu is printed if
                 *      - this is the first time around the select loop
                 *      - the user enters a blank line
                 *      - the REPLY parameter is empty
@@ -1353,11 +1543,11 @@ struct select_menu_info {
        int num_width;
 };
 
-static char *select_fmt_entry(char *, int, int, const void *);
+static char *select_fmt_entry(char *, size_t, int, const void *);
 
 /* format a single select menu item */
 static char *
-select_fmt_entry(char *buf, int buflen, int i, const void *arg)
+select_fmt_entry(char *buf, size_t buflen, int i, const void *arg)
 {
        const struct select_menu_info *smi =
            (const struct select_menu_info *)arg;
@@ -1375,7 +1565,8 @@ pr_menu(const char * const *ap)
 {
        struct select_menu_info smi;
        const char * const *pp;
-       int acols = 0, aocts = 0, i, n;
+       size_t acols = 0, aocts = 0, i;
+       int n;
 
        /*
         * width/column calculations were done once and saved, but this
@@ -1412,19 +1603,20 @@ pr_menu(const char * const *ap)
 }
 
 /* XXX: horrible kludge to fit within the framework */
-static char *plain_fmt_entry(char *, int, int, const void *);
+static char *plain_fmt_entry(char *, size_t, int, const void *);
 
 static char *
-plain_fmt_entry(char *buf, int buflen, int i, const void *arg)
+plain_fmt_entry(char *buf, size_t buflen, int i, const void *arg)
 {
-       shf_snprintf(buf, buflen, "%s", ((const char * const *)arg)[i]);
+       strlcpy(buf, ((const char * const *)arg)[i], buflen);
        return (buf);
 }
 
 int
 pr_list(char * const *ap)
 {
-       int acols = 0, aocts = 0, i, n;
+       size_t acols = 0, aocts = 0, i;
+       int n;
        char * const *pp;
 
        for (n = 0, pp = ap; *pp; n++, pp++) {
@@ -1468,8 +1660,10 @@ dbteste_isa(Test_env *te, Test_meta meta)
 
        if (meta == TM_UNOP || meta == TM_BINOP) {
                if (uqword) {
-                       char buf[8];    /* longer than the longest operator */
+                       /* longer than the longest operator */
+                       char buf[8];
                        char *q = buf;
+
                        for (p = *te->pos.wp;
                            *p == CHAR && q < &buf[sizeof(buf) - 1]; p += 2)
                                *q++ = p[1];