Merge "Upgrade to mksh R59b." am: 4adbc81376 am: efb93a535d

Change-Id: I12d26d6a8756b35fd6ad111a4631c7476853a356
diff --git a/Android.bp b/Android.bp
index e3e374b..15afd71 100644
--- a/Android.bp
+++ b/Android.bp
@@ -107,7 +107,7 @@
         "-DHAVE_SYS_ERRLIST_DECL=0",
         "-DHAVE_SYS_SIGLIST_DECL=1",
         "-DHAVE_PERSISTENT_HISTORY=0",
-        "-DMKSH_BUILD_R=591",
+        "-DMKSH_BUILD_R=592",
 
         // Additional flags
         "-DMKSH_DEFAULT_PROFILEDIR=\"/system/etc\"",
diff --git a/Android.patch.txt b/Android.patch.txt
index d2cd1fa..eefcd5c 100644
--- a/Android.patch.txt
+++ b/Android.patch.txt
@@ -1,6 +1,7 @@
-diff -u mksh-R59/funcs.c src/funcs.c
---- mksh-R59/funcs.c	2020-04-13 12:51:34.000000000 -0700
-+++ src/funcs.c	2020-05-15 16:10:35.035013192 -0700
+Only in src: FAQ.htm
+diff -u mksh-R59b/funcs.c src/funcs.c
+--- mksh-R59b/funcs.c	2020-05-16 15:38:48.000000000 -0700
++++ src/funcs.c	2020-05-20 17:14:19.588510856 -0700
 @@ -104,7 +104,9 @@
  	{Tsgbreak, c_brkcont},
  	{T__builtin, c_builtin},
@@ -32,11 +33,10 @@
  #ifdef __MirBSD__
  	/* alias to "true" for historical reasons */
  	{"domainname", c_true},
-Only in src: funcs.c.orig
-diff -u mksh-R59/main.c src/main.c
---- mksh-R59/main.c	2020-04-13 10:04:41.000000000 -0700
-+++ src/main.c	2020-05-15 16:10:35.035013192 -0700
-@@ -402,6 +402,12 @@
+diff -u mksh-R59b/main.c src/main.c
+--- mksh-R59b/main.c	2020-05-16 15:51:51.000000000 -0700
++++ src/main.c	2020-05-20 17:14:19.588510856 -0700
+@@ -414,6 +414,12 @@
  	/* import environment */
  	init_environ();
  
@@ -50,3 +50,8 @@
  	typeset(TinitIFS, 0, 0, 0, 0);
  
 Only in src: main.c.orig
+Only in src: Rebuild.sh
+Only in src: rlimits.gen
+Only in src: sh_flags.gen
+Only in src: signames.inc
+Only in src: test.sh
diff --git a/src/Build.sh b/src/Build.sh
index 1a95e66..1d30045 100644
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.755 2020/04/07 23:15:11 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.756 2020/05/16 22:53:03 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #		2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
@@ -2461,7 +2461,7 @@
 addsrcs USE_PRINTF_BUILTIN printf.c
 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
 test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
-add_cppflags -DMKSH_BUILD_R=591
+add_cppflags -DMKSH_BUILD_R=592
 
 $e $bi$me: Finished configuration testing, now producing output.$ao
 
diff --git a/src/check.t b/src/check.t
index a750c50..8818822 100644
--- a/src/check.t
+++ b/src/check.t
Binary files differ
diff --git a/src/edit.c b/src/edit.c
index f38092e..8c1c2c8 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -29,7 +29,7 @@
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.350 2020/04/13 20:46:37 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.351 2020/04/15 20:16:19 tg Exp $");
 
 /*
  * in later versions we might use libtermcap for this, but since external
@@ -5603,9 +5603,19 @@
 {
 	/* default must be 0 (bss) */
 	x_term_mode = 0;
-	/* this is what tmux uses, don't ask me about it */
-	if (!strcmp(termtype, "screen") || !strncmp(termtype, "screen-", 7))
-		x_term_mode = 1;
+	/* catch any of the TERM types tmux uses, don’t ask m̲e̲ about it… */
+	switch (*termtype) {
+	case 's':
+		if (!strncmp(termtype, "screen", 6) &&
+		    (termtype[6] == '\0' || termtype[6] == '-'))
+			x_term_mode = 1;
+		break;
+	case 't':
+		if (!strncmp(termtype, "tmux", 4) &&
+		    (termtype[4] == '\0' || termtype[4] == '-'))
+			x_term_mode = 1;
+		break;
+	}
 }
 
 #ifndef MKSH_SMALL
diff --git a/src/eval.c b/src/eval.c
index 6e7b505..33a8ea1 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -24,7 +24,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.230 2020/04/07 23:14:41 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.231 2020/05/05 21:34:27 tg Exp $");
 
 /*
  * string expansion
@@ -882,6 +882,7 @@
 					c = ORD('\\');
 				else
 					++x.str;
+				quote |= 2;
 				break;
 			/* ctype(c, C_PATMO) */
 			case ORD('!'):
diff --git a/src/funcs.c b/src/funcs.c
index a5cfc69..d3427d0 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -39,7 +39,7 @@
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.372 2020/04/13 19:51:07 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.373 2020/05/16 22:38:21 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -330,7 +330,7 @@
 #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
 		    Flag(FSH) ||
 #endif
-		    Flag(FAS_BUILTIN)) {
+		    as_builtin) {
 			/* BSD "echo" cmd, Debian Policy 10.4 compliant */
 			++wp;
  bsd_echo:
diff --git a/src/main.c b/src/main.c
index 3d440dd..1328045 100644
--- a/src/main.c
+++ b/src/main.c
@@ -35,7 +35,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.364 2020/04/13 17:04:14 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.372 2020/05/16 22:51:24 tg Exp $");
 
 #ifndef MKSHRC_PATH
 #define MKSHRC_PATH	"~/.mkshrc"
@@ -242,6 +242,9 @@
 
 #ifdef __OS2__
 	os2_init(&argc, &argv);
+#define builtin_name_cmp stricmp
+#else
+#define builtin_name_cmp strcmp
 #endif
 
 	/* do things like getpgrp() et al. */
@@ -276,10 +279,11 @@
 			ccp += argi;
  begin_parsing_kshname:
 			argi = 0;
-			if (*ccp == '-')
-				++ccp;
 		}
 	}
+	Flag(FLOGIN) = (ord(*ccp) == ORD('-')) || (ord(*kshname) == ORD('-'));
+	if (ord(*ccp) == ORD('-'))
+		++ccp;
 	if (!*ccp)
 		ccp = empty_argv[0];
 
@@ -304,24 +308,32 @@
 	ktinit(APERM, &builtins,
 	    /* currently up to 52 builtins: 75% of 128 = 2^7 */
 	    7);
-	for (i = 0; mkshbuiltins[i].name != NULL; i++)
-		if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
-		    mkshbuiltins[i].func)))
-			Flag(FAS_BUILTIN) = 1;
+	for (i = 0; mkshbuiltins[i].name != NULL; ++i) {
+		const char *builtin_name;
 
-	if (!Flag(FAS_BUILTIN)) {
+		builtin_name = builtin(mkshbuiltins[i].name,
+		    mkshbuiltins[i].func);
+		if (!builtin_name_cmp(ccp, builtin_name)) {
+			/* canonicalise argv[0] */
+			ccp = builtin_name;
+			as_builtin = true;
+		}
+	}
+
+	if (!as_builtin) {
 		/* check for -T option early */
 		argi = parse_args(argv, OF_FIRSTTIME, NULL);
 		if (argi < 0)
 			return (1);
-		/* called as rsh, rmksh, -rsh, -rmksh, etc.? */
-		if (ord(*ccp) == ORD('r')) {
+		/* called as rsh, rmksh, -rsh, RKSH.EXE, etc.? */
+		if (ksh_eq(*ccp, 'R', 'r')) {
 			++ccp;
 			++restricted_shell;
 		}
 #if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
-		/* are we called as -sh or /bin/sh or so? */
-		if (!strcmp(ccp, "sh" MKSH_EXE_EXT)) {
+		/* are we called as -rsh or /bin/sh or SH.EXE or so? */
+		if (ksh_eq(ccp[0], 'S', 's') &&
+		    ksh_eq(ccp[1], 'H', 'h')) {
 			/* either also turns off braceexpand */
 #ifdef MKSH_BINSHPOSIX
 			/* enable better POSIX conformance */
@@ -474,7 +486,7 @@
 	/* this to note if utf-8 mode is set on command line (see below) */
 	UTFMODE = 2;
 
-	if (!Flag(FAS_BUILTIN)) {
+	if (!as_builtin) {
 		argi = parse_args(argv, OF_CMDLINE, NULL);
 		if (argi < 0)
 			return (1);
@@ -484,7 +496,7 @@
 	utf_flag = UTFMODE;
 	UTFMODE = 0;
 
-	if (Flag(FAS_BUILTIN)) {
+	if (as_builtin) {
 		/* auto-detect from environment variables, always */
 		utf_flag = 3;
 	} else if (Flag(FCOMMAND)) {
@@ -549,8 +561,8 @@
 	}
 
 	/* this bizarreness is mandated by POSIX */
-	if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
-	    Flag(FTALKING))
+	if (Flag(FTALKING) && fstat(0, &s_stdin) >= 0 &&
+	    S_ISCHR(s_stdin.st_mode))
 		reset_nonblock(0);
 
 	/* initialise job control */
@@ -582,7 +594,7 @@
 #endif
 
 	l = e->loc;
-	if (Flag(FAS_BUILTIN)) {
+	if (as_builtin) {
 		l->argc = argc;
 		l->argv = argv;
 		l->argv[0] = ccp;
@@ -650,6 +662,21 @@
 	errexit = Flag(FERREXIT);
 	Flag(FERREXIT) = 0;
 
+	/* save flags for "set +o" handling */
+	memcpy(baseline_flags, shell_flags, sizeof(shell_flags));
+	/* disable these because they have special handling */
+	baseline_flags[(int)FPOSIX] = 0;
+	baseline_flags[(int)FSH] = 0;
+	/* ensure these always show up setting, for FPOSIX/FSH */
+	baseline_flags[(int)FBRACEEXPAND] = 0;
+	baseline_flags[(int)FUNNYCODE] = 0;
+#if !defined(MKSH_SMALL) || defined(DEBUG)
+	/* mark as initialised */
+	baseline_flags[(int)FNFLAGS] = 1;
+#endif
+	if (as_builtin)
+		goto skip_startup_files;
+
 	/*
 	 * Do this before profile/$ENV so that if it causes problems in them,
 	 * user will know why things broke.
@@ -668,6 +695,8 @@
 		else
 			/* turn off -p if not set explicitly */
 			change_flag(FPRIVILEGED, OF_INTERNAL, false);
+		/* track shell-imposed changes */
+		baseline_flags[(int)FPRIVILEGED] = Flag(FPRIVILEGED);
 	} else {
 		if (Flag(FLOGIN))
 			include(substitute("$HOME/.profile", 0), 0, NULL, true);
@@ -681,14 +710,20 @@
 		c_builtin(restr_com);
 		/* After typeset command... */
 		Flag(FRESTRICTED) = 1;
+		/* track shell-imposed changes */
+		baseline_flags[(int)FRESTRICTED] = 1;
 	}
 	Flag(FERREXIT) = errexit;
 
 	if (Flag(FTALKING) && s)
 		hist_init(s);
-	else
+	else {
 		/* set after ENV */
+ skip_startup_files:
 		Flag(FTRACKALL) = 1;
+		/* track shell-imposed change (might lower surprise) */
+		baseline_flags[(int)FTRACKALL] = 1;
+	}
 
 	alarm_init();
 
@@ -707,7 +742,7 @@
 	struct block *l;
 
 	if ((rv = main_init(argc, argv, &s, &l)) == 0) {
-		if (Flag(FAS_BUILTIN)) {
+		if (as_builtin) {
 			rv = c_builtin(l->argv);
 		} else {
 			shell(s, 0);
diff --git a/src/misc.c b/src/misc.c
index 9e5b572..b19a253 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -3,7 +3,8 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019
+ *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
+ *		 2020
  *	mirabilos <m@mirbsd.org>
  * Copyright (c) 2015
  *	Daniel Richard G. <skunk@iSKUNK.ORG>
@@ -32,7 +33,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.297 2020/04/07 11:56:46 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.299 2020/05/16 22:19:58 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -141,7 +142,8 @@
 };
 
 static void options_fmt_entry(char *, size_t, unsigned int, const void *);
-static void printoptions(bool);
+static int printoptions(bool);
+static int printoption(size_t);
 
 /* format a single select menu item */
 static void
@@ -154,10 +156,32 @@
 	    Flag(oi->opts[i]) ? "on" : "off");
 }
 
-static void
+static int
+printoption(size_t i)
+{
+	if (Flag(i) == baseline_flags[i])
+		return (0);
+	if (!OFN(i)[0]) {
+#if !defined(MKSH_SMALL) || defined(DEBUG)
+		bi_errorf(Tf_sd, "change in unnamed option", (int)i);
+#endif
+		return (1);
+	}
+	if (Flag(i) != 0 && Flag(i) != 1) {
+#if !defined(MKSH_SMALL) || defined(DEBUG)
+		bi_errorf(Tf_s_sD_s, Tdo, OFN(i), "not 0 or 1");
+#endif
+		return (1);
+	}
+	shprintf(Tf__s_s, Flag(i) ? Tdo : Tpo, OFN(i));
+	return (0);
+}
+
+static int
 printoptions(bool verbose)
 {
 	size_t i = 0;
+	int rv = 0;
 
 	if (verbose) {
 		size_t n = 0, len, octs = 0;
@@ -187,13 +211,17 @@
 	} else {
 		/* short version like AT&T ksh93 */
 		shf_puts(Tset, shl_stdout);
-		while (i < NELEM(options)) {
-			if (Flag(i) && OFN(i)[0])
-				shprintf(" -o %s", OFN(i));
+		shf_puts(To_o_reset, shl_stdout);
+		printoption(FSH);
+		printoption(FPOSIX);
+		while (i < FNFLAGS) {
+			if (i != FSH && i != FPOSIX)
+				rv |= printoption(i);
 			++i;
 		}
 		shf_putc('\n', shl_stdout);
 	}
+	return (rv);
 }
 
 char *
@@ -362,7 +390,8 @@
 #undef SHFLAGS_NOT_CMD
 	    ;
 	bool set;
-	const char *opts;
+	const char *opts = what == OF_CMDLINE || what == OF_FIRSTTIME ?
+	    cmd_opts : set_opts;
 	const char *array = NULL;
 	Getopt go;
 	size_t i;
@@ -370,22 +399,6 @@
 	bool sortargs = false;
 	bool fcompatseen = false;
 
-	if (what == OF_CMDLINE) {
-		const char *p = argv[0], *q;
-		/*
-		 * Set FLOGIN before parsing options so user can clear
-		 * flag using +l.
-		 */
-		if (*p != '-')
-			for (q = p; *q; )
-				if (mksh_cdirsep(*q++))
-					p = q;
-		Flag(FLOGIN) = (*p == '-');
-		opts = cmd_opts;
-	} else if (what == OF_FIRSTTIME) {
-		opts = cmd_opts;
-	} else
-		opts = set_opts;
 	ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT);
 	while ((optc = ksh_getopt(argv, &go, opts)) != -1) {
 		set = tobool(!(go.info & GI_PLUS));
@@ -408,7 +421,15 @@
 				 * an option (ie, can't get here if what is
 				 * OF_CMDLINE).
 				 */
-				printoptions(set);
+#if !defined(MKSH_SMALL) || defined(DEBUG)
+				if (!set && !baseline_flags[(int)FNFLAGS]) {
+					bi_errorf(Tf_s_s, "too early",
+					    Tset_po);
+					return (-1);
+				}
+#endif
+				if (printoptions(set))
+					return (-1);
 				break;
 			}
 			i = option(go.optarg);
@@ -433,7 +454,23 @@
 				;
 			else if ((i != (size_t)-1) && (OFF(i) & what))
 				change_flag((enum sh_flag)i, what, set);
-			else {
+			else if (!strcmp(go.optarg, To_reset)) {
+#if !defined(MKSH_SMALL) || defined(DEBUG)
+				if (!baseline_flags[(int)FNFLAGS]) {
+					bi_errorf(Tf_ss, "too early",
+					    To_o_reset);
+					return (-1);
+				}
+#endif
+				/*
+				 * ordering, with respect to side effects,
+				 * was ensured above by printoptions
+				 */
+				for (i = 0; i < FNFLAGS; ++i)
+					if (Flag(i) != baseline_flags[i])
+						change_flag((enum sh_flag)i,
+						    what, baseline_flags[i]);
+			} else {
 				bi_errorf(Tf_sD_s, go.optarg,
 				    Tunknown_option);
 				return (-1);
diff --git a/src/mksh.1 b/src/mksh.1
index 672e6b6..1f1a121 100644
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,4 +1,4 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.489 2020/04/14 22:45:21 tg Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.491 2020/05/16 22:12:36 tg Exp $
 .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
 .\"-
 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@@ -84,7 +84,7 @@
 .\" with -mandoc, it might implement .Mx itself, but we want to
 .\" use our own definition. And .Dd must come *first*, always.
 .\"
-.Dd $Mdocdate: April 14 2020 $
+.Dd $Mdocdate: May 16 2020 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -270,7 +270,7 @@
 command below).
 .It Fl l
 Login shell.
-If the basename the shell is called with (i.e. argv[0])
+If the name or basename the shell is called with (i.e. argv[0])
 starts with
 .Ql \-
 or if this option is used,
@@ -297,7 +297,9 @@
 Restricted shell.
 A shell is
 .Dq restricted
-if the basename the shell is called with (i.e. argv[0]) starts with
+if the basename the shell is called with, after
+.Ql \-
+processing, starts with
 .Ql r
 or if this option is used.
 The following restrictions come into effect after the shell processes any
@@ -382,7 +384,7 @@
 .Fl c
 option is used and there is a non-option argument, it is used as the name;
 if commands are being read from a file, the file is used as the name;
-otherwise, the basename the shell was called with (i.e. argv[0]) is used.
+otherwise, the name the shell was called with (i.e. argv[0]) is used.
 .Pp
 The exit status of the shell is 127 if the command file specified on the
 command line could not be opened, or non-zero if a fatal syntax error
@@ -1801,12 +1803,11 @@
 .Fl c
 option and arguments were given; otherwise the
 .Ar file
-argument, if it was supplied;
-or else the basename the shell was invoked with (i.e.\&
-.Li argv[0] ) .
+argument, if it was supplied; or else the name the shell was invoked with
+.Pq i.e.\& Li argv[0] .
 .Ev $0
-is also set to the name of the current script or
-the name of the current function, if it was defined with the
+is also set to the name of the current script,
+or to the name of the current function if it was defined with the
 .Ic function
 keyword (i.e. a Korn shell style function).
 .It Ev 1 No .. Ev 9
@@ -2024,7 +2025,7 @@
 .Xc
 See the end of the Emacs editing mode documentation for an example.
 .It Ev KSH_VERSION
-The name and version of the shell (read-only).
+The name (self-identification) and version of the shell (read-only).
 See also the version commands in
 .Sx Emacs editing mode
 and
@@ -4562,34 +4563,42 @@
 (see
 .Sx POSIX mode
 for details).
-Automatically enabled if the basename of the shell invocation begins with
+Automatically enabled if the shell invocation basename, after
+.Sq \-
+and
+.Sq r
+processing, begins with
 .Dq sh
-and this autodetection feature is compiled in (not in MirBSD; commonly used for
-.Nm lksh
-only).
+and
+.Pq often used for the Nm lksh No binary
+this autodetection feature is compiled in.
 As a side effect, setting this flag turns off the
 .Ic braceexpand
 and
 .Ic utf8\-mode
 flags, which can be turned back on manually, and
-.Pq unless both are enabled at the same time
+.Pq unless both are set in the same command
 .Ic sh
 mode.
 .It Fl o Ic sh
-Enable
+Enable kludge
 .Pa /bin/sh
-.Pq kludge
-mode (see
-.Sx SH mode ) .
-Automatically enabled if the basename of the shell invocation begins with
+compatibility mode (see
+.Sx SH mode
+below for details).
+Automatically enabled if the basename of the shell invocation, after
+.Sq \-
+and
+.Sq r
+processing, begins with
 .Dq sh
 and this autodetection feature is compiled in
 .Pq rather uncommon .
-As a side effect, setting this flag turns off
+As a side effect, setting this flag turns off the
 .Ic braceexpand
-mode, which can be turned back on manually, and
+flag, which can be turned back on manually, and
 .Ic posix
-mode (unless both are enabled at the same time).
+mode (unless both are set in the same command).
 .It Fl o Ic vi
 Enable
 .Xr vi 1 Ns -like
@@ -4623,12 +4632,10 @@
 .Ic set Fl o
 with no option name will list all the options and whether each is on or off;
 .Ic set +o
-will print the long names of all options that are currently on.
-In a future version,
-.Ic set +o
-will behave
-.Tn POSIX
-compliant and print commands to restore the current options instead.
+prints a command to restore the current option set, using the internal
+.Ic set Fl o Ic .reset
+construct, which is an implementation detail; these commands are transient
+.Pq only valid within the current shell session .
 .Pp
 Remaining arguments, if any, are positional parameters and are assigned, in
 order, to the positional parameters (i.e. $1, $2, etc.).
@@ -7065,7 +7072,7 @@
 .Xr memmove 3 .
 .Pp
 This document attempts to describe
-.Nm mksh\ R59
+.Nm mksh\ R59b
 and up,
 .\" with vendor patches from insert-your-name-here,
 compiled without any options impacting functionality, such as
diff --git a/src/mksh.faq b/src/mksh.faq
index 1fc3b7d..83e0191 100644
--- a/src/mksh.faq
+++ b/src/mksh.faq
@@ -1,4 +1,4 @@
-RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.6 2020/04/13 20:46:39 tg Exp $
+RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.7 2020/04/25 12:09:55 tg Exp $
 ToC: spelling
 Title: How do you spell <tt>mksh</tt>? How do you pronounce it?
 
@@ -357,7 +357,7 @@
 The shell itself provides static deterministic tab completion.
 However, you can use hooks like reprogramming the Tab key to a
 command line editor macro, and using the <tt>evaluate-region</tt>
-editor command (modulo a bugfix) together with <tt>quote-region<tt> and shell functions to
+editor command (modulo a bugfix) together with <tt>quote-region</tt> and shell functions to
 implement a programmable completion engine. Multiple people have
 been considering doing so in our IRC channel; we’ll hyperlink to
 these engines when they are available.
diff --git a/src/sh.h b/src/sh.h
index c5e4dc5..8394c89 100644
--- a/src/sh.h
+++ b/src/sh.h
@@ -191,9 +191,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.892 2020/04/14 22:45:22 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.898 2020/05/16 22:38:23 tg Exp $");
 #endif
-#define MKSH_VERSION "R59 2020/04/14"
+#define MKSH_VERSION "R59 2020/05/16"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -513,9 +513,8 @@
 #define O_BINARY	0
 #endif
 
-#ifndef O_MAYEXEC
+#undef O_MAYEXEC	/* https://lwn.net/Articles/820658/ */
 #define O_MAYEXEC	0
-#endif
 
 #ifdef MKSH__NO_SYMLINK
 #undef S_ISLNK
@@ -669,7 +668,7 @@
 #endif
 #endif
 
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 591)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 592)
 #error Must run Build.sh to compile this.
 extern void thiswillneverbedefinedIhope(void);
 int
@@ -917,6 +916,12 @@
 EXTERN short trap_exstat;	/* exit status before running a trap */
 EXTERN uint8_t trap_nested;	/* running nested traps */
 EXTERN uint8_t shell_flags[FNFLAGS];
+EXTERN uint8_t baseline_flags[FNFLAGS
+#if !defined(MKSH_SMALL) || defined(DEBUG)
+    + 1
+#endif
+    ];
+EXTERN bool as_builtin;		/* direct builtin call */
 EXTERN const char *kshname;	/* $0 */
 EXTERN struct {
 	uid_t kshuid_v;		/* real UID of shell at startup */
@@ -1038,7 +1043,10 @@
 #define Tnot_started (Tjob_not_started + 4)
 #define TOLDPWD (Tno_OLDPWD + 3)
 #define Topen (Tcant_open + 6)
+EXTERN const char To_o_reset[] E_INIT(" -o .reset");
+#define To_reset (To_o_reset + 4)
 #define TPATH (TFPATH + 1)
+#define Tpo (Tset_po + 4)
 #define Tpv (TpVv + 1)
 EXTERN const char TpVv[] E_INIT("Vpv");
 #define TPWD (Tno_OLDPWD + 6)
@@ -1053,6 +1061,7 @@
 EXTERN const char Treq_arg[] E_INIT("requires an argument");
 EXTERN const char Tselect[] E_INIT("select");
 #define Tset (Tf_parm + 18)
+EXTERN const char Tset_po[] E_INIT("set +o");
 EXTERN const char Tsghset[] E_INIT("*=#set");
 #define Tsh (Tmksh + 2)
 #define TSHELL (TEXECSHELL + 4)
@@ -1083,6 +1092,7 @@
 #define Twrite (Tshf_write + 4)
 EXTERN const char Tf__S[] E_INIT(" %S");
 #define Tf__d (Tunexpected_type + 22)
+#define Tf_ss (Tf__ss + 1)
 EXTERN const char Tf__ss[] E_INIT(" %s%s");
 #define Tf__sN (Tf_s_s_sN + 5)
 #define Tf_T (Tf_s_T + 3)
@@ -1091,6 +1101,7 @@
 EXTERN const char Tf_s_T[] E_INIT("%s %T");
 EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
 #define Tf_s_s (Tf_sD_s_s + 4)
+#define Tf__s_s (Tf_sD_s_s + 3)
 #define Tf_s_sD_s (Tf_cant_ss_s + 6)
 EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
 EXTERN const char Tf_sD_[] E_INIT("%s: ");
@@ -1198,7 +1209,10 @@
 #define Tnot_started "not started"
 #define TOLDPWD "OLDPWD"
 #define Topen "open"
+#define To_o_reset " -o .reset"
+#define To_reset ".reset"
 #define TPATH "PATH"
+#define Tpo "+o"
 #define Tpv "pv"
 #define TpVv "Vpv"
 #define TPWD "PWD"
@@ -1213,6 +1227,7 @@
 #define Treq_arg "requires an argument"
 #define Tselect "select"
 #define Tset "set"
+#define Tset_po "set +o"
 #define Tsghset "*=#set"
 #define Tsh "sh"
 #define TSHELL "SHELL"
@@ -1243,6 +1258,7 @@
 #define Twrite "write"
 #define Tf__S " %S"
 #define Tf__d " %d"
+#define Tf_ss "%s%s"
 #define Tf__ss " %s%s"
 #define Tf__sN " %s\n"
 #define Tf_T "%T"
@@ -1251,6 +1267,7 @@
 #define Tf_s_T "%s %T"
 #define Tf_s_s_sN "%s %s %s\n"
 #define Tf_s_s "%s %s"
+#define Tf__s_s " %s %s"
 #define Tf_s_sD_s "%s %s: %s"
 #define Tf_optfoo "%s%s-%c: %s"
 #define Tf_sD_ "%s: "
diff --git a/src/sh_flags.gen b/src/sh_flags.gen
index a0a0f6a..538baf1 100644
--- a/src/sh_flags.gen
+++ b/src/sh_flags.gen
@@ -21,7 +21,7 @@
 
 #ifndef SHFLAGS_OPTCS
 #if defined(SHFLAGS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.8 2019/12/30 03:58:58 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.9 2020/05/16 22:38:25 tg Exp $");
 #elif defined(SHFLAGS_ENUMS)
 #define FN(sname,cname,flags,ochar)	cname,
 #define F0(sname,cname,flags,ochar)	cname = 0,
@@ -95,7 +95,6 @@
 #ifndef SHFLAGS_NOT_CMD
 FN("", FCOMMAND, OF_CMDLINE, 'c')
 #endif
-FN("", FAS_BUILTIN, OF_INTERNAL, 0)
 FN("", FTALKING_I, OF_INTERNAL, 0)
 #undef F0
 #undef FN
diff --git a/src/sh_flags.opt b/src/sh_flags.opt
index d81d9d9..d84d1f1 100644
--- a/src/sh_flags.opt
+++ b/src/sh_flags.opt
@@ -19,7 +19,7 @@
  */
 
 @SHFLAGS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.8 2019/12/30 03:58:58 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.9 2020/05/16 22:38:25 tg Exp $");
 @SHFLAGS_ENUMS
 #define FN(sname,cname,flags,ochar)	cname,
 #define F0(sname,cname,flags,ochar)	cname = 0,
@@ -187,10 +187,6 @@
  * anonymous flags: used internally by shell only (not visible to user)
  */
 
-/* ./.	direct builtin call (divined from argv[0] multi-call binary) */
->|
-FN("", FAS_BUILTIN, OF_INTERNAL
-
 /* ./.	(internal) initial shell was interactive */
 >|
 FN("", FTALKING_I, OF_INTERNAL