Please review changes against upstream code using SCM,
see the Vcs-* tags in debian/control for its location.

--- mksh-56b.orig/Build.sh
+++ mksh-56b/Build.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.727 2017/08/29 13:38:28 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.730 2018/01/05 20:05:26 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #		2011, 2012, 2013, 2014, 2015, 2016, 2017
@@ -796,6 +796,8 @@ Harvey)
 	add_cppflags -DMKSH_ASSUME_UTF8
 	HAVE_ISSET_MKSH_ASSUME_UTF8=1
 	HAVE_ISOFF_MKSH_ASSUME_UTF8=0
+	add_cppflags -DMKSH__NO_SYMLINK
+	check_categories="$check_categories nosymlink"
 	add_cppflags -DMKSH_NO_CMDLINE_EDITING
 	add_cppflags -DMKSH__NO_SETEUGID
 	oswarn=' and will currently not work'
@@ -819,6 +821,20 @@ Interix)
 IRIX*)
 	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
+Jehanne)
+	add_cppflags -DMKSH_ASSUME_UTF8
+	HAVE_ISSET_MKSH_ASSUME_UTF8=1
+	HAVE_ISOFF_MKSH_ASSUME_UTF8=0
+	add_cppflags -DMKSH__NO_SYMLINK
+	check_categories="$check_categories nosymlink"
+	add_cppflags -DMKSH_NO_CMDLINE_EDITING
+	add_cppflags -DMKSH_DISABLE_REVOKE_WARNING
+	add_cppflags '-D_PATH_DEFPATH=\"/cmd\"'
+	add_cppflags '-DMKSH_DEFAULT_EXECSHELL=\"/cmd/mksh\"'
+	add_cppflags '-DMKSH_DEFAULT_PROFILEDIR=\"/cfg/mksh\"'
+	add_cppflags '-DMKSH_ENVDIR=\"/env\"'
+	SRCS="$SRCS jehanne.c"
+	;;
 Linux)
 	case $CC in
 	*tendracc*) ;;
@@ -947,6 +963,8 @@ Plan9)
 	add_cppflags -DMKSH_ASSUME_UTF8
 	HAVE_ISSET_MKSH_ASSUME_UTF8=1
 	HAVE_ISOFF_MKSH_ASSUME_UTF8=0
+	add_cppflags -DMKSH__NO_SYMLINK
+	check_categories="$check_categories nosymlink"
 	add_cppflags -DMKSH_NO_CMDLINE_EDITING
 	add_cppflags -DMKSH__NO_SETEUGID
 	oswarn=' and will currently not work'
--- mksh-56b.orig/check.t
+++ mksh-56b/check.t
@@ -1,4 +1,4 @@
-# $MirOS: src/bin/mksh/check.t,v 1.797 2017/08/29 13:38:29 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.800 2017/12/15 13:35:34 tg Exp $
 # -*- mode: sh -*-
 #-
 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -30,7 +30,7 @@
 # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
 
 expected-stdout:
-	@(#)MIRBSD KSH R56 2017/08/29
+	@(#)MIRBSD KSH R56 2017/10/17
 description:
 	Check base version of full shell
 stdin:
@@ -39,7 +39,7 @@ name: KSH_VERSION
 category: !shell:legacy-yes
 ---
 expected-stdout:
-	@(#)LEGACY KSH R56 2017/08/29
+	@(#)LEGACY KSH R56 2017/10/17
 description:
 	Check base version of legacy shell
 stdin:
@@ -3328,7 +3328,7 @@ stdin:
 		echo B
 	      ) &
 	    ' &
-	sleep 2
+	sleep 5
 	echo Left overs: *
 expected-stdout:
 	A
@@ -3392,7 +3392,7 @@ stdin:
 		(sleep 1; foo) &
 		foo
 	    ' &
-	sleep 2
+	sleep 5
 	echo Left overs: *
 expected-stdout:
 	hi
@@ -6702,7 +6702,7 @@ name: regression-65
 description:
 	check for a regression with sleep builtin and signal mask
 category: !nojsig
-time-limit: 3
+time-limit: 5
 stdin:
 	sleep 1
 	echo blub |&
--- mksh-56b.orig/exec.c
+++ mksh-56b/exec.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.199 2017/08/07 21:16:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.201 2017/10/11 21:09:24 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL	MKSH_UNIXROOT "/bin/sh"
@@ -953,8 +953,12 @@ scriptexec(struct op *tp, const char **a
 		}
 #ifdef __OS2__
 		/*
-		 * Search shell/interpreter name without directory in PATH
-		 * if specified path does not exist
+		 * On OS/2, the directory structure differs from normal
+		 * Unix, which can make many scripts whose shebang
+		 * hardcodes the path to an interpreter fail (and there
+		 * might be no /usr/bin/env); for user convenience, if
+		 * the specified interpreter is not usable, do a PATH
+		 * search to find it.
 		 */
 		if (mksh_vdirsep(sh) && !search_path(sh, path, X_OK, NULL)) {
 			cp = search_path(_getname(sh), path, X_OK, NULL);
@@ -1168,11 +1172,7 @@ findcom(const char *name, int flags)
 	char *fpath;
 	union mksh_cchack npath;
 
-	if (mksh_vdirsep(name)
-#ifdef MKSH_DOSPATH
-	    && (strcmp(name, T_builtin) != 0)
-#endif
-	    ) {
+	if (mksh_vdirsep(name)) {
 		insert = 0;
 		/* prevent FPATH search below */
 		flags &= ~FC_FUNC;
--- mksh-56b.orig/expr.c
+++ mksh-56b/expr.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.100 2017/08/07 21:38:55 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.101 2017/11/18 12:01:53 tg Exp $");
 
 #define EXPRTOK_DEFNS
 #include "exprtok.h"
@@ -884,7 +884,7 @@ static int mb_ucsbsearch(const struct mb
 
 /*
  * Generated from the Unicode Character Database, Version 10.0.0, by
- * MirOS: contrib/code/Snippets/eawparse,v 1.10 2017/07/12 22:47:26 tg Exp $
+ * MirOS: contrib/code/Snippets/eawparse,v 1.12 2017/09/06 16:05:45 tg Exp $
  */
 
 static const struct mb_ucsrange mb_ucs_combining[] = {
@@ -895,16 +895,14 @@ static const struct mb_ucsrange mb_ucs_c
 	{ 0x05C1, 0x05C2 },
 	{ 0x05C4, 0x05C5 },
 	{ 0x05C7, 0x05C7 },
-	{ 0x0600, 0x0605 },
 	{ 0x0610, 0x061A },
 	{ 0x061C, 0x061C },
 	{ 0x064B, 0x065F },
 	{ 0x0670, 0x0670 },
-	{ 0x06D6, 0x06DD },
+	{ 0x06D6, 0x06DC },
 	{ 0x06DF, 0x06E4 },
 	{ 0x06E7, 0x06E8 },
 	{ 0x06EA, 0x06ED },
-	{ 0x070F, 0x070F },
 	{ 0x0711, 0x0711 },
 	{ 0x0730, 0x074A },
 	{ 0x07A6, 0x07B0 },
@@ -914,7 +912,8 @@ static const struct mb_ucsrange mb_ucs_c
 	{ 0x0825, 0x0827 },
 	{ 0x0829, 0x082D },
 	{ 0x0859, 0x085B },
-	{ 0x08D4, 0x0902 },
+	{ 0x08D4, 0x08E1 },
+	{ 0x08E3, 0x0902 },
 	{ 0x093A, 0x093A },
 	{ 0x093C, 0x093C },
 	{ 0x0941, 0x0948 },
--- mksh-56b.orig/funcs.c
+++ mksh-56b/funcs.c
@@ -38,7 +38,7 @@
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.350 2017/05/05 22:53:28 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.351 2017/11/20 02:32:32 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -3533,7 +3533,7 @@ c_cat(const char **wp)
 					continue;
 				}
 				if (errno == EPIPE) {
-					/* fake receiving signel */
+					/* fake receiving signal */
 					rv = ksh_sigmask(SIGPIPE);
 				} else {
 					/* an error occured during writing */
--- /dev/null
+++ mksh-56b/jehanne.c
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2017
+ *	Giacomo Tesio <giacomo@tesio.it>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * Initialisation code for the Jehanne operating system (a Plan 9 de-
+ * rivative, using GCC)
+ */
+
+static const char __rcsid[] __attribute__((__used__)) =
+    "$MirOS: src/bin/mksh/jehanne.c,v 1.1 2017/12/22 16:30:00 tg Exp $";
+
+#include <u.h>
+#include <lib9.h>
+#include <posix.h>
+
+void
+__application_newlib_init(int argc, char *argv[])
+{
+	rfork(RFFDG | RFREND | RFNOTEG);
+	libposix_emulate_SIGCHLD();
+}
--- mksh-56b.orig/jobs.c
+++ mksh-56b/jobs.c
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
- *		 2012, 2013, 2014, 2015, 2016
+ *		 2012, 2013, 2014, 2015, 2016, 2018
  *	mirabilos <m@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.124 2017/08/08 14:30:10 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.125 2018/01/05 20:08:34 tg Exp $");
 
 #if HAVE_KILLPG
 #define mksh_killpg		killpg
@@ -1545,7 +1545,9 @@ j_print(Job *j, int how, struct shf *shf
 	Proc *p;
 	int state;
 	int status;
+#ifdef WCOREDUMP
 	bool coredumped;
+#endif
 	char jobchar = ' ';
 	char buf[64];
 	const char *filler;
@@ -1569,7 +1571,9 @@ j_print(Job *j, int how, struct shf *shf
 		jobchar = '-';
 
 	for (p = j->proc_list; p != NULL;) {
+#ifdef WCOREDUMP
 		coredumped = false;
+#endif
 		switch (p->state) {
 		case PRUNNING:
 			memcpy(buf, "Running", 8);
@@ -1603,7 +1607,10 @@ j_print(Job *j, int how, struct shf *shf
 			 * kludge for not reporting 'normal termination
 			 * signals' (i.e. SIGINT, SIGPIPE)
 			 */
-			if (how == JP_SHORT && !coredumped &&
+			if (how == JP_SHORT &&
+#ifdef WCOREDUMP
+			    !coredumped &&
+#endif
 			    (termsig == SIGINT || termsig == SIGPIPE)) {
 				buf[0] = '\0';
 			} else
@@ -1629,14 +1636,22 @@ j_print(Job *j, int how, struct shf *shf
 		if (how == JP_SHORT) {
 			if (buf[0]) {
 				output = 1;
+#ifdef WCOREDUMP
 				shf_fprintf(shf, "%s%s ",
 				    buf, coredumped ? " (core dumped)" : null);
+#else
+				shf_puts(buf, shf);
+				shf_putchar(' ', shf);
+#endif
 			}
 		} else {
 			output = 1;
 			shf_fprintf(shf, "%-20s %s%s%s", buf, p->command,
 			    p->next ? "|" : null,
-			    coredumped ? " (core dumped)" : null);
+#ifdef WCOREDUMP
+			    coredumped ? " (core dumped)" :
+#endif
+			     null);
 		}
 
 		state = p->state;
--- mksh-56b.orig/lex.c
+++ mksh-56b/lex.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.239 2017/05/05 22:53:29 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.240 2017/10/17 23:45:18 tg Exp $");
 
 /*
  * states while lexing word
@@ -284,15 +284,6 @@ yylex(int cf)
 						}
 						afree(tmp, ATEMP);
 						break;
-					} else {
-						Source *s;
-
-						s = pushs(SREREAD,
-						    source->areap);
-						s->start = s->str =
-						    s->u.freeme = tmp;
-						s->next = source;
-						source = s;
 					}
 				}
 				*wp++ = CHAR;
--- mksh-56b.orig/main.c
+++ mksh-56b/main.c
@@ -34,9 +34,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.342 2017/04/28 11:13:47 tg Exp $");
-
-extern char **environ;
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.345 2017/10/14 21:05:22 tg Exp $");
 
 #ifndef MKSHRC_PATH
 #define MKSHRC_PATH	"~/.mkshrc"
@@ -52,6 +50,7 @@ void chvt_reinit(void);
 static void reclaim(void);
 static void remove_temps(struct temp *);
 static mksh_uari_t rndsetup(void);
+static void init_environ(void);
 #ifdef SIGWINCH
 static void x_sigwinch(int);
 #endif
@@ -242,10 +241,6 @@ main_init(int argc, const char *argv[],
 	set_ifs(TC_IFSWS);
 
 #ifdef __OS2__
-	for (i = 0; i < 3; ++i)
-		if (!isatty(i))
-			setmode(i, O_BINARY);
-
 	os2_init(&argc, &argv);
 #endif
 
@@ -401,14 +396,7 @@ main_init(int argc, const char *argv[],
 #endif
 
 	/* import environment */
-	if (environ != NULL) {
-		wp = (const char **)environ;
-		while (*wp != NULL) {
-			rndpush(*wp);
-			typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
-			++wp;
-		}
-	}
+	init_environ();
 
 	/* for security */
 	typeset(TinitIFS, 0, 0, 0, 0);
@@ -665,8 +653,7 @@ main_init(int argc, const char *argv[],
 		if (Flag(FLOGIN))
 			include(substitute("$HOME/.profile", 0), 0, NULL, true);
 		if (Flag(FTALKING)) {
-			cp = substitute(substitute("${ENV:-" MKSHRC_PATH "}",
-			    0), DOTILDE);
+			cp = substitute("${ENV:-" MKSHRC_PATH "}", DOTILDE);
 			if (cp[0] != '\0')
 				include(cp, 0, NULL, true);
 		}
@@ -1981,3 +1968,84 @@ x_mkraw(int fd, mksh_ttyst *ocb, bool fo
 
 	mksh_tcset(fd, &cb);
 }
+
+#ifdef MKSH_ENVDIR
+static void
+init_environ(void)
+{
+	char *xp;
+	ssize_t n;
+	XString xs;
+	struct shf *shf;
+	DIR *dirp;
+	struct dirent *dent;
+
+	if ((dirp = opendir(MKSH_ENVDIR)) == NULL) {
+		warningf(false, "cannot read environment from %s: %s",
+		    MKSH_ENVDIR, cstrerror(errno));
+		return;
+	}
+	XinitN(xs, 256, ATEMP);
+ read_envfile:
+	errno = 0;
+	if ((dent = readdir(dirp)) != NULL) {
+		if (skip_varname(dent->d_name, true)[0] == '\0') {
+			xp = shf_smprintf(Tf_sSs, MKSH_ENVDIR, dent->d_name);
+			if (!(shf = shf_open(xp, O_RDONLY, 0, 0))) {
+				warningf(false,
+				    "cannot read environment %s from %s: %s",
+				    dent->d_name, MKSH_ENVDIR,
+				    cstrerror(errno));
+				goto read_envfile;
+			}
+			afree(xp, ATEMP);
+			n = strlen(dent->d_name);
+			xp = Xstring(xs, xp);
+			XcheckN(xs, xp, n + 32);
+			memcpy(xp, dent->d_name, n);
+			xp += n;
+			*xp++ = '=';
+			while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
+				xp += n;
+				if (Xnleft(xs, xp) <= 0)
+					XcheckN(xs, xp, Xlength(xs, xp));
+			}
+			if (n < 0) {
+				warningf(false,
+				    "cannot read environment %s from %s: %s",
+				    dent->d_name, MKSH_ENVDIR,
+				    cstrerror(shf_errno(shf)));
+			} else {
+				*xp = '\0';
+				xp = Xstring(xs, xp);
+				rndpush(xp);
+				typeset(xp, IMPORT | EXPORT, 0, 0, 0);
+			}
+			shf_close(shf);
+		}
+		goto read_envfile;
+	} else if (errno)
+		warningf(false, "cannot read environment from %s: %s",
+		    MKSH_ENVDIR, cstrerror(errno));
+	closedir(dirp);
+	Xfree(xs, xp);
+}
+#else
+extern char **environ;
+
+static void
+init_environ(void)
+{
+	const char **wp;
+
+	if (environ == NULL)
+		return;
+
+	wp = (const char **)environ;
+	while (*wp != NULL) {
+		rndpush(*wp);
+		typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
+		++wp;
+	}
+}
+#endif
--- mksh-56b.orig/misc.c
+++ mksh-56b/misc.c
@@ -32,7 +32,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.279 2017/08/07 21:39:25 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.288 2017/10/15 20:21:51 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -1661,6 +1661,15 @@ do_realpath(const char *upath)
 	if (mksh_abspath(upath)) {
 		/* upath is an absolute pathname */
 		strdupx(ipath, upath, ATEMP);
+#ifdef MKSH_DOSPATH
+	} else if (mksh_drvltr(upath)) {
+		/* upath is a drive-relative pathname */
+		if (getdrvwd(&ldest, ord(*upath)))
+			return (NULL);
+		/* A:foo -> A:/cwd/foo; A: -> A:/cwd */
+		ipath = shf_smprintf(Tf_sss, ldest,
+		    upath[2] ? "/" : "", upath + 2);
+#endif
 	} else {
 		/* upath is a relative pathname, prepend cwd */
 		if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp))
@@ -1695,6 +1704,7 @@ do_realpath(const char *upath)
 				continue;
 			else if (len == 2 && tp[1] == '.') {
 				/* strip off last pathname component */
+				/*XXX consider a rooted pathname */
 				while (xp > Xstring(xs, xp))
 					if (mksh_cdirsep(*--xp))
 						break;
@@ -1762,11 +1772,23 @@ do_realpath(const char *upath)
 			 * restart if symlink target is an absolute path,
 			 * otherwise continue with currently resolved prefix
 			 */
+#ifdef MKSH_DOSPATH
+ assemble_symlink:
+#endif
 			/* append rest of current input path to link target */
 			tp = shf_smprintf(Tf_sss, ldest, *ip ? "/" : "", ip);
 			afree(ipath, ATEMP);
 			ip = ipath = tp;
-			if (!mksh_abspath(ldest)) {
+			if (!mksh_abspath(ipath)) {
+#ifdef MKSH_DOSPATH
+				/* symlink target might be drive-relative */
+				if (mksh_drvltr(ipath)) {
+					if (getdrvwd(&ldest, ord(*ipath)))
+						goto notfound;
+					ip += 2;
+					goto assemble_symlink;
+				}
+#endif
 				/* symlink target is a relative path */
 				xp = Xrestpos(xs, xp, pos);
 			} else
@@ -1775,7 +1797,7 @@ do_realpath(const char *upath)
 				/* symlink target is an absolute path */
 				xp = Xstring(xs, xp);
  beginning_of_a_pathname:
-				/* assert: mksh_cdirsep((ip == ipath)[0]) */
+				/* assert: mksh_abspath(ip == ipath) */
 				/* assert: xp == xs.beg => start of path */
 
 				/* exactly two leading slashes? (SUSv4 3.266) */
@@ -1783,6 +1805,14 @@ do_realpath(const char *upath)
 					/* keep them, e.g. for UNC pathnames */
 					Xput(xs, xp, '/');
 				}
+#ifdef MKSH_DOSPATH
+				/* drive letter? */
+				if (mksh_drvltr(ip)) {
+					/* keep it */
+					Xput(xs, xp, *ip++);
+					Xput(xs, xp, *ip++);
+				}
+#endif
 			}
 		}
 		/* otherwise (no symlink) merely go on */
@@ -1932,6 +1962,15 @@ make_path(const char *cwd, const char *f
  * ..					..
  * ./foo				foo
  * foo/../../../bar			../../bar
+ * C:/foo/../..				C:/
+ * C:.					C:
+ * C:..					C:..
+ * C:foo/../../blah			C:../blah
+ *
+ * XXX consider a rooted pathname: we cannot really 'cd ..' for
+ * pathnames like: '/', 'c:/', '//foo', '//foo/', '/@unixroot/'
+ * (no effect), 'c:', 'c:.' (effect is retaining the '../') but
+ * we need to honour this throughout the shell
  */
 void
 simplify_path(char *p)
@@ -1939,6 +1978,17 @@ simplify_path(char *p)
 	char *dp, *ip, *sp, *tp;
 	size_t len;
 	bool needslash;
+#ifdef MKSH_DOSPATH
+	bool needdot = true;
+
+	/* keep drive letter */
+	if (mksh_drvltr(p)) {
+		p += 2;
+		needdot = false;
+	}
+#else
+#define needdot true
+#endif
 
 	switch (*p) {
 	case 0:
@@ -1977,7 +2027,7 @@ simplify_path(char *p)
 				/* just continue with the next one */
 				continue;
 			else if (len == 2 && tp[1] == '.') {
-				/* parent level, but how? */
+				/* parent level, but how? (see above) */
 				if (mksh_abspath(p))
 					/* absolute path, only one way */
 					goto strip_last_component;
@@ -2016,10 +2066,15 @@ simplify_path(char *p)
 		needslash = true;
 		/* try next component */
 	}
-	if (dp == p)
-		/* empty path -> dot */
-		*dp++ = needslash ? '/' : '.';
+	if (dp == p) {
+		/* empty path -> dot (or slash, when absolute) */
+		if (needslash)
+			*dp++ = '/';
+		else if (needdot)
+			*dp++ = '.';
+	}
 	*dp = '\0';
+#undef needdot
 }
 
 void
@@ -2133,6 +2188,18 @@ c_cd(const char **wp)
 		return (2);
 	}
 
+#ifdef MKSH_DOSPATH
+	tryp = NULL;
+	if (mksh_drvltr(dir) && !mksh_cdirsep(dir[2]) &&
+	    !getdrvwd(&tryp, ord(*dir))) {
+		dir = shf_smprintf(Tf_sss, tryp,
+		    dir[2] ? "/" : "", dir + 2);
+		afree(tryp, ATEMP);
+		afree(allocd, ATEMP);
+		allocd = dir;
+	}
+#endif
+
 #ifdef MKSH__NO_PATH_MAX
 	/* only a first guess; make_path will enlarge xs if necessary */
 	XinitN(xs, 1024, ATEMP);
--- mksh-56b.orig/os2.c
+++ mksh-56b/os2.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2015
+ * Copyright (c) 2015, 2017
  *	KO Myung-Hun <komh@chollian.net>
  * Copyright (c) 2017
  *	mirabilos <m@mirbsd.org>
@@ -26,18 +26,18 @@
 #include "sh.h"
 
 #include <klibc/startup.h>
+#include <errno.h>
 #include <io.h>
 #include <unistd.h>
 #include <process.h>
 
-__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.2 2017/04/29 22:04:29 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.8 2017/12/22 16:41:42 tg Exp $");
 
 static char *remove_trailing_dots(char *);
 static int access_stat_ex(int (*)(), const char *, void *);
 static int test_exec_exist(const char *, char *);
 static void response(int *, const char ***);
 static char *make_response_file(char * const *);
-static void env_slashify(void);
 static void add_temp(const char *);
 static void cleanup_temps(void);
 static void cleanup(void);
@@ -169,44 +169,12 @@ init_extlibpath(void)
 	}
 }
 
-/*
- * Convert backslashes of environmental variables to forward slahes.
- * A backslash may be used as an escaped character when doing 'echo'.
- * This leads to an unexpected behavior.
- */
-static void
-env_slashify(void)
-{
-	/*
-	 * PATH and TMPDIR are used by OS/2 as well. That is, they may
-	 * have backslashes as a directory separator.
-	 * BEGINLIBPATH and ENDLIBPATH are special variables on OS/2.
-	 */
-	const char *var_list[] = {
-		"PATH",
-		"TMPDIR",
-		"BEGINLIBPATH",
-		"ENDLIBPATH",
-		NULL
-	};
-	const char **var;
-	char *value;
-
-	for (var = var_list; *var; var++) {
-		value = getenv(*var);
-
-		if (value)
-			_fnslashify(value);
-	}
-}
-
 void
 os2_init(int *argcp, const char ***argvp)
 {
 	response(argcp, argvp);
 
 	init_extlibpath();
-	env_slashify();
 
 	if (!isatty(STDIN_FILENO))
 		setmode(STDIN_FILENO, O_BINARY);
@@ -361,49 +329,30 @@ real_exec_name(const char *name)
 	return (real_name);
 }
 
-/* OS/2 can process a command line up to 32 KiB */
-#define MAX_CMD_LINE_LEN 32768
-
 /* make a response file to pass a very long command line */
 static char *
 make_response_file(char * const *argv)
 {
 	char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
 	char *rsp_name = &rsp_name_arg[1];
-	int arg_len = 0;
 	int i;
+	int fd;
+	char *result;
 
-	for (i = 0; argv[i]; i++)
-		arg_len += strlen(argv[i]) + 1;
-
-	/*
-	 * If a length of command line is longer than MAX_CMD_LINE_LEN, then
-	 * use a response file. OS/2 cannot process a command line longer
-	 * than 32K. Of course, a response file cannot be recognised by a
-	 * normal OS/2 program, that is, neither non-EMX or non-kLIBC. But
-	 * it cannot accept a command line longer than 32K in itself. So
-	 * using a response file in this case, is an acceptable solution.
-	 */
-	if (arg_len > MAX_CMD_LINE_LEN) {
-		int fd;
-		char *result;
-
-		if ((fd = mkstemp(rsp_name)) == -1)
-			return (NULL);
-
-		/* write all the arguments except a 0th program name */
-		for (i = 1; argv[i]; i++) {
-			write(fd, argv[i], strlen(argv[i]));
-			write(fd, "\n", 1);
-		}
+	if ((fd = mkstemp(rsp_name)) == -1)
+		return (NULL);
 
-		close(fd);
-		add_temp(rsp_name);
-		strdupx(result, rsp_name_arg, ATEMP);
-		return (result);
+	/* write all the arguments except a 0th program name */
+	for (i = 1; argv[i]; i++) {
+		write(fd, argv[i], strlen(argv[i]));
+		write(fd, "\n", 1);
 	}
 
-	return (NULL);
+	close(fd);
+	add_temp(rsp_name);
+	strdupx(result, rsp_name_arg, ATEMP);
+
+	return (result);
 }
 
 /* alias of execve() */
@@ -416,12 +365,12 @@ execve(const char *name, char * const *a
 	const char *exec_name;
 	FILE *fp;
 	char sign[2];
-	char *rsp_argv[3];
-	char *rsp_name_arg;
 	int pid;
 	int status;
 	int fd;
 	int rc;
+	int saved_mode;
+	int saved_errno;
 
 	/*
 	 * #! /bin/sh : append .exe
@@ -461,23 +410,41 @@ execve(const char *name, char * const *a
 	if (errno == ENOEXEC)
 		return (-1);
 
-	rsp_name_arg = make_response_file(argv);
+	/*
+	 * Normal OS/2 programs expect that standard IOs, especially stdin,
+	 * are opened in text mode at the startup. By the way, on OS/2 kLIBC
+	 * child processes inherit a translation mode of a parent process.
+	 * As a result, if stdin is set to binary mode in a parent process,
+	 * stdin of child processes is opened in binary mode as well at the
+	 * startup. In this case, some programs such as sed suffer from CR.
+	 */
+	saved_mode = setmode(STDIN_FILENO, O_TEXT);
 
-	if (rsp_name_arg) {
-		rsp_argv[0] = argv[0];
-		rsp_argv[1] = rsp_name_arg;
-		rsp_argv[2] = NULL;
+	pid = spawnve(P_NOWAIT, exec_name, argv, envp);
+	saved_errno = errno;
 
-		argv = rsp_argv;
-	}
+	/* arguments too long? */
+	if (pid == -1 && saved_errno == EINVAL) {
+		/* retry with a response file */
+		char *rsp_name_arg = make_response_file(argv);
 
-	pid = spawnve(P_NOWAIT, exec_name, argv, envp);
+		if (rsp_name_arg) {
+			char *rsp_argv[3] = { argv[0], rsp_name_arg, NULL };
+
+			pid = spawnve(P_NOWAIT, exec_name, rsp_argv, envp);
+			saved_errno = errno;
+
+			afree(rsp_name_arg, ATEMP);
+		}
+	}
 
-	afree(rsp_name_arg, ATEMP);
+	/* restore translation mode of stdin */
+	setmode(STDIN_FILENO, saved_mode);
 
 	if (pid == -1) {
 		cleanup_temps();
 
+		errno = saved_errno;
 		return (-1);
 	}
 
@@ -557,3 +524,52 @@ cleanup(void)
 {
 	cleanup_temps();
 }
+
+int
+getdrvwd(char **cpp, unsigned int drvltr)
+{
+	PBYTE cp;
+	ULONG sz;
+	APIRET rc;
+	ULONG drvno;
+
+	if (DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH,
+	    &sz, sizeof(sz)) != 0) {
+		errno = EDOOFUS;
+		return (-1);
+	}
+
+	/* allocate 'X:/' plus sz plus NUL */
+	checkoktoadd((size_t)sz, (size_t)4);
+	cp = aresize(*cpp, (size_t)sz + (size_t)4, ATEMP);
+	cp[0] = ksh_toupper(drvltr);
+	cp[1] = ':';
+	cp[2] = '/';
+	drvno = ksh_numuc(cp[0]) + 1;
+	/* NUL is part of space within buffer passed */
+	++sz;
+	if ((rc = DosQueryCurrentDir(drvno, cp + 3, &sz)) == 0) {
+		/* success! */
+		*cpp = cp;
+		return (0);
+	}
+	afree(cp, ATEMP);
+	*cpp = NULL;
+	switch (rc) {
+	case 15: /* invalid drive */
+		errno = ENOTBLK;
+		break;
+	case 26: /* not dos disk */
+		errno = ENODEV;
+		break;
+	case 108: /* drive locked */
+		errno = EDEADLK;
+		break;
+	case 111: /* buffer overflow */
+		errno = ENAMETOOLONG;
+		break;
+	default:
+		errno = EINVAL;
+	}
+	return (-1);
+}
--- mksh-56b.orig/sh.h
+++ mksh-56b/sh.h
@@ -182,9 +182,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.841 2017/08/29 13:38:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.849 2017/10/17 23:45:19 tg Exp $");
 #endif
-#define MKSH_VERSION "R56 2017/08/29"
+#define MKSH_VERSION "R56 2017/10/17"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -2734,24 +2734,29 @@ extern int tty_init_fd(void);	/* initial
 #endif
 
 #ifdef MKSH_DOSPATH
+#define mksh_drvltr(s)			__extension__({			\
+	const char *mksh_drvltr_s = (s);				\
+	(ctype(mksh_drvltr_s[0], C_ALPHA) && mksh_drvltr_s[1] == ':');	\
+})
 #define mksh_abspath(s)			__extension__({			\
 	const char *mksh_abspath_s = (s);				\
 	(mksh_cdirsep(mksh_abspath_s[0]) ||				\
-	    (ctype(mksh_abspath_s[0], C_ALPHA) &&			\
-	    mksh_abspath_s[1] == ':'));					\
+	    (mksh_drvltr(mksh_abspath_s) &&				\
+	    mksh_cdirsep(mksh_abspath_s[2])));				\
 })
 #define mksh_cdirsep(c)			__extension__({			\
 	char mksh_cdirsep_c = (c);					\
 	(mksh_cdirsep_c == '/' || mksh_cdirsep_c == '\\');		\
 })
-#define mksh_sdirsep(s)			__extension__({			\
-	const char *mksh_sdirsep_s = (s);				\
-	((char *)((ctype(mksh_sdirsep_s[0], C_ALPHA) &&			\
-	    mksh_sdirsep_s[1] == ':' &&					\
-	    !mksh_cdirsep(mksh_sdirsep_s[2])) ?				\
-	    (mksh_sdirsep_s + 1) : strpbrk(mksh_sdirsep_s, "/\\")));	\
+#define mksh_sdirsep(s)			strpbrk((s), "/\\")
+#define mksh_vdirsep(s)			__extension__({			\
+	const char *mksh_vdirsep_s = (s);				\
+	(((mksh_drvltr(mksh_vdirsep_s) &&				\
+	    !mksh_cdirsep(mksh_vdirsep_s[2])) ? (!0) :			\
+	    (mksh_sdirsep(mksh_vdirsep_s) != NULL)) &&			\
+	    (strcmp(mksh_vdirsep_s, T_builtin) != 0));			\
 })
-#define mksh_vdirsep(s)			(mksh_sdirsep((s)) != NULL)
+int getdrvwd(char **, unsigned int);
 #else
 #define mksh_abspath(s)			(ord((s)[0]) == ord('/'))
 #define mksh_cdirsep(c)			(ord(c) == ord('/'))
--- mksh-56b.orig/var.c
+++ mksh-56b/var.c
@@ -28,7 +28,7 @@
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.220 2017/07/26 23:02:28 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.221 2017/10/13 23:34:49 tg Exp $");
 
 /*-
  * Variables
@@ -1294,9 +1294,29 @@ setspec(struct tbl *vp)
 {
 	mksh_ari_u num;
 	char *s;
-	int st;
+	int st = special(vp->name);
 
-	switch ((st = special(vp->name))) {
+#ifdef MKSH_DOSPATH
+	switch (st) {
+	case V_PATH:
+	case V_TMPDIR:
+#ifdef __OS2__
+	case V_BEGINLIBPATH:
+	case V_ENDLIBPATH:
+#endif
+		/* convert backslashes to slashes for convenience */
+		if (!(vp->flag&INTEGER)) {
+			s = str_val(vp);
+			do {
+				if (*s == ord('\\'))
+					*s = '/';
+			} while (*s++);
+		}
+		break;
+	}
+#endif
+
+	switch (st) {
 #ifdef __OS2__
 	case V_BEGINLIBPATH:
 	case V_ENDLIBPATH:
