oksh-noxz

[fork] Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
git clone https://noxz.tech/git/oksh-noxz.git
oksh-noxz

commit: fe33dbf67b94df102603fdcf26d4d95d317e43a8
parent: 189dc1e3a6f3b21d602c8e62b755755dad98b82c
author: Brian Callahan <bcallah@openbsd.org>
date:   Fri, 30 Oct 2020 20:42:25 -0400
This is oksh-6.8
MCVS/Entries66++++++++---------
ACVS/Entries.Log2+
MREADME.md4+-
Meval.c65++++++++++++-----
Mksh.115+++-
Mvi.c76+++++++++++++-------
6 files changed, 147 insertions(+), 81 deletions(-)
diff --git a/CVS/Entries b/CVS/Entries
@@ -1,7 +1,6 @@
 /config.h/1.19/Tue Jan 16 02:21:56 2018//
 /c_test.c/1.27/Result of merge//
 /edit.c/1.69/Result of merge//
-/eval.c/1.65/Result of merge//
 /exec.c/1.74/Result of merge//
 /main.c/1.98/Result of merge//
 /tty.c/1.18/Result of merge+Tue Jul 23 23:36:05 2019//
@@ -11,36 +10,37 @@
 /var.c/1.71/Result of merge//
 /emacs.c/1.87/Result of merge//
 /sh.h/1.76/Result of merge//
-/CONTRIBUTORS/1.11/Sat Jul 25 01:41:12 2020//
-/LEGAL/1.2/Sat Jul 25 01:41:12 2020//
-/Makefile/1.39/Sat Jul 25 01:41:20 2020//
-/NOTES/1.16/Sat Jul 25 01:41:12 2020//
-/PROJECTS/1.9/Sat Jul 25 01:41:12 2020//
-/README/1.16/Sat Jul 25 01:41:20 2020//
-/alloc.c/1.19/Sat Jul 25 01:41:12 2020//
-/c_ksh.c/1.62/Sat Jul 25 01:41:12 2020//
-/c_sh.c/1.64/Sat Jul 25 01:41:12 2020//
-/c_test.h/1.4/Sat Jul 25 01:41:12 2020//
-/c_ulimit.c/1.29/Sat Jul 25 01:41:12 2020//
-/edit.h/1.12/Sat Jul 25 01:41:12 2020//
-/expand.h/1.15/Sat Jul 25 01:41:12 2020//
-/expr.c/1.34/Sat Jul 25 01:41:12 2020//
-/jobs.c/1.62/Sat Jul 25 01:41:12 2020//
-/ksh.1/1.209/Sat Jul 25 01:41:12 2020//
-/lex.c/1.78/Sat Jul 25 01:41:12 2020//
-/lex.h/1.21/Sat Jul 25 01:41:12 2020//
-/mail.c/1.27/Sat Jul 25 01:41:12 2020//
-/misc.c/1.75/Result of merge//
-/path.c/1.23/Sat Jul 25 01:41:12 2020//
-/sh.1/1.152/Sat Jul 25 01:41:12 2020//
-/shf.c/1.34/Sat Jul 25 01:41:12 2020//
-/shf.h/1.8/Sat Jul 25 01:41:12 2020//
-/syn.c/1.39/Sat Jul 25 01:41:12 2020//
-/table.c/1.25/Sat Jul 25 01:41:12 2020//
-/table.h/1.15/Sat Jul 25 01:41:12 2020//
-/tree.c/1.34/Sat Jul 25 01:41:12 2020//
-/tree.h/1.12/Sat Jul 25 01:41:12 2020//
-/tty.h/1.6/Sat Jul 25 01:41:12 2020//
-/version.c/1.12/Sat Jul 25 01:41:12 2020//
-/vi.c/1.56/Sat Jul 25 01:41:12 2020//
+/CONTRIBUTORS/1.11/Sat Oct 31 00:41:26 2020//
+/LEGAL/1.2/Sat Oct 31 00:41:26 2020//
+/Makefile/1.39/Sat Oct 31 00:41:34 2020//
+/NOTES/1.16/Sat Oct 31 00:41:26 2020//
+/PROJECTS/1.9/Sat Oct 31 00:41:26 2020//
+/README/1.16/Sat Oct 31 00:41:34 2020//
+/alloc.c/1.19/Sat Oct 31 00:41:26 2020//
+/c_ksh.c/1.62/Sat Oct 31 00:41:26 2020//
+/c_sh.c/1.64/Sat Oct 31 00:41:26 2020//
+/c_test.h/1.4/Sat Oct 31 00:41:26 2020//
+/c_ulimit.c/1.29/Sat Oct 31 00:41:26 2020//
+/edit.h/1.12/Sat Oct 31 00:41:26 2020//
+/eval.c/1.66/Result of merge//
+/expand.h/1.15/Sat Oct 31 00:41:26 2020//
+/expr.c/1.34/Sat Oct 31 00:41:26 2020//
+/jobs.c/1.62/Sat Oct 31 00:41:26 2020//
+/ksh.1/1.210/Sat Oct 31 00:41:35 2020//
+/lex.c/1.78/Sat Oct 31 00:41:26 2020//
+/lex.h/1.21/Sat Oct 31 00:41:26 2020//
+/mail.c/1.27/Sat Oct 31 00:41:26 2020//
+/misc.c/1.76/Result of merge//
+/path.c/1.23/Sat Oct 31 00:41:26 2020//
+/sh.1/1.152/Sat Oct 31 00:41:26 2020//
+/shf.c/1.34/Sat Oct 31 00:41:26 2020//
+/shf.h/1.8/Sat Oct 31 00:41:26 2020//
+/syn.c/1.39/Sat Oct 31 00:41:26 2020//
+/table.c/1.25/Sat Oct 31 00:41:26 2020//
+/table.h/1.15/Sat Oct 31 00:41:26 2020//
+/tree.c/1.34/Sat Oct 31 00:41:26 2020//
+/tree.h/1.12/Sat Oct 31 00:41:26 2020//
+/tty.h/1.6/Sat Oct 31 00:41:26 2020//
+/version.c/1.12/Sat Oct 31 00:41:26 2020//
+/vi.c/1.57/Sat Oct 31 00:41:35 2020//
 D
diff --git a/CVS/Entries.Log b/CVS/Entries.Log
@@ -0,0 +1,2 @@
+A D/tests////
+R D/tests////
diff --git a/README.md b/README.md
@@ -112,5 +112,5 @@ for details.
 
 Get a tarball
 -------------
-See releases tab. The latest release is oksh-6.7.1, which matches the ksh(1)
-from OpenBSD 6.8-beta as of 2020-09-12.
+See releases tab. The latest release is oksh-6.8, which matches the ksh(1)
+from OpenBSD 6.8.
diff --git a/eval.c b/eval.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: eval.c,v 1.65 2019/06/28 13:34:59 deraadt Exp $	*/
+/*	$OpenBSD: eval.c,v 1.66 2020/09/13 15:39:09 tb Exp $	*/
 
 /*
  * Expansion - quoting, separation, substitution, globbing
@@ -47,6 +47,8 @@ typedef struct Expand {
 #define IFS_WORD	0	/* word has chars (or quotes) */
 #define IFS_WS		1	/* have seen IFS white-space */
 #define IFS_NWS		2	/* have seen IFS non-white-space */
+#define IFS_IWS		3	/* beginning of word, ignore IFS white-space */
+#define IFS_QUOTE	4	/* beg.w/quote, becomes IFS_WORD unless "$@" */
 
 static	int	varsub(Expand *, char *, char *, int *, int *);
 static	int	comsub(Expand *, char *);
@@ -217,7 +219,17 @@ expand(char *cp,	/* input word */
 				c = *sp++;
 				break;
 			case OQUOTE:
-				word = IFS_WORD;
+				switch (word) {
+				case IFS_QUOTE:
+					/* """something */
+					word = IFS_WORD;
+					break;
+				case IFS_WORD:
+					break;
+				default:
+					word = IFS_QUOTE;
+					break;
+				}
 				tilde_ok = 0;
 				quote = 1;
 				continue;
@@ -297,6 +309,8 @@ expand(char *cp,	/* input word */
 				if (f&DOBLANK)
 					doblank++;
 				tilde_ok = 0;
+				if (word == IFS_QUOTE && type != XNULLSUB)
+					word = IFS_WORD;
 				if (type == XBASE) {	/* expand? */
 					if (!st->next) {
 						SubType *newst;
@@ -358,6 +372,11 @@ expand(char *cp,	/* input word */
 						f |= DOTEMP_;
 						/* FALLTHROUGH */
 					default:
+						/* '-' '+' '?' */
+						if (quote)
+							word = IFS_WORD;
+						else if (dp == Xstring(ds, dp))
+							word = IFS_IWS;
 						/* Enable tilde expansion */
 						tilde_ok = 1;
 						f |= DOTILDE;
@@ -387,10 +406,17 @@ expand(char *cp,	/* input word */
 					 */
 					x.str = trimsub(str_val(st->var),
 						dp, st->stype);
-					if (x.str[0] != '\0' || st->quote)
+					if (x.str[0] != '\0') {
+						word = IFS_IWS;
 						type = XSUB;
-					else
+					} else if (quote) {
+						word = IFS_WORD;
+						type = XSUB;
+					} else {
+						if (dp == Xstring(ds, dp))
+							word = IFS_IWS;
 						type = XNULLSUB;
+					}
 					if (f&DOBLANK)
 						doblank++;
 					st = st->prev;
@@ -422,6 +448,10 @@ expand(char *cp,	/* input word */
 					if (f&DOBLANK)
 						doblank++;
 					st = st->prev;
+					if (quote || !*x.str)
+						word = IFS_WORD;
+					else
+						word = IFS_IWS;
 					continue;
 				case '?':
 				    {
@@ -463,12 +493,8 @@ expand(char *cp,	/* input word */
 			type = XBASE;
 			if (f&DOBLANK) {
 				doblank--;
-				/* not really correct: x=; "$x$@" should
-				 * generate a null argument and
-				 * set A; "${@:+}" shouldn't.
-				 */
-				if (dp == Xstring(ds, dp))
-					word = IFS_WS;
+				if (dp == Xstring(ds, dp) && word != IFS_WORD)
+					word = IFS_IWS;
 			}
 			continue;
 
@@ -503,7 +529,12 @@ expand(char *cp,	/* input word */
 				if (c == 0) {
 					if (quote && !x.split)
 						continue;
+					if (!quote && word == IFS_WS)
+						continue;
+					/* this is so we don't terminate */
 					c = ' ';
+					/* now force-emit a word */
+					goto emit_word;
 				}
 				if (quote && x.split) {
 					/* terminate word for "$@" */
@@ -554,15 +585,15 @@ expand(char *cp,	/* input word */
 			 *	-----------------------------------
 			 *	IFS_WORD	w/WS	w/NWS	w
 			 *	IFS_WS		-/WS	w/NWS	-
-			 *	IFS_NWS		-/NWS	w/NWS	w
+			 *	IFS_NWS		-/NWS	w/NWS	-
+			 *	IFS_IWS		-/WS	w/NWS	-
 			 *   (w means generate a word)
-			 * Note that IFS_NWS/0 generates a word (at&t ksh
-			 * doesn't do this, but POSIX does).
 			 */
-			if (word == IFS_WORD ||
-			    (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
-				char *p;
-
+			if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c &&
+			    (word == IFS_IWS || word == IFS_NWS) &&
+			    !ctype(c, C_IFSWS))) {
+ 				char *p;
+ emit_word:
 				*dp++ = '\0';
 				p = Xclose(ds, dp);
 				if (fdo & DOBRACE_)
diff --git a/ksh.1 b/ksh.1
@@ -1,8 +1,8 @@
-.\"	$OpenBSD: ksh.1,v 1.209 2020/07/07 10:33:58 jca Exp $
+.\"	$OpenBSD: ksh.1,v 1.210 2020/09/20 14:40:45 millert Exp $
 .\"
 .\"	Public Domain
 .\"
-.Dd $Mdocdate: July 7 2020 $
+.Dd $Mdocdate: September 20 2020 $
 .Dt KSH 1
 .Os
 .Sh NAME
@@ -5053,6 +5053,13 @@ Erases previous character.
 .It ^J | ^M
 End of line.
 The current line is read, parsed, and executed by the shell.
+.It ^L
+Clear the screen (if possible) and redraw the current line.
+See the
+.Em clear-screen
+command in
+.Sx Emacs editing mode
+for more information.
 .It ^V
 Literal next.
 The next character typed is not treated specially (can be used
@@ -5510,7 +5517,9 @@ Miscellaneous vi commands
 .Bl -tag -width Ds
 .It ^J and ^M
 The current line is read, parsed, and executed by the shell.
-.It ^L and ^R
+.It ^L
+Clear the screen (if possible) and redraw the current line.
+.It ^R
 Redraw the current line.
 .It Xo
 .Oo Ar n Oc Ns \&.
diff --git a/vi.c b/vi.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vi.c,v 1.56 2018/03/15 16:51:29 anton Exp $	*/
+/*	$OpenBSD: vi.c,v 1.57 2020/09/20 14:40:45 millert Exp $	*/
 
 /*
  *	vi command editing
@@ -14,12 +14,14 @@
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
+#ifndef SMALL
+# include <term.h>
+# include <curses.h>
+#endif
 
 #include "sh.h"
 #include "edit.h"
 
-#define CTRL(c)		(c & 0x1f)
-
 struct edstate {
 	char	*cbuf;		/* main buffer to build the command line */
 	int	cbufsize;	/* number of bytes allocated for cbuf */
@@ -52,8 +54,9 @@ static int	Backword(int);
 static int	Endword(int);
 static int	grabhist(int, int);
 static int	grabsearch(int, int, int, char *);
+static void	do_clear_screen(void);
 static void	redraw_line(int);
-static void	refresh(int);
+static void	refresh_line(int);
 static int	outofwin(void);
 static void	rewindow(void);
 static int	newcol(int, int);
@@ -271,9 +274,9 @@ vi_hook(int ch)
 			case 0:
 				if (state == VLIT) {
 					es->cursor--;
-					refresh(0);
+					refresh_line(0);
 				} else
-					refresh(insert != 0);
+					refresh_line(insert != 0);
 				break;
 			case 1:
 				return 1;
@@ -298,7 +301,7 @@ vi_hook(int ch)
 							return -1;
 					} else if (putbuf("?", 1, 0) != 0)
 						return -1;
-					refresh(0);
+					refresh_line(0);
 				}
 			}
 		}
@@ -310,7 +313,7 @@ vi_hook(int ch)
 			vi_error();
 		} else
 			es->cbuf[es->cursor++] = ch;
-		refresh(1);
+		refresh_line(1);
 		state = VNORMAL;
 		break;
 
@@ -375,7 +378,7 @@ vi_hook(int ch)
 				if (!srchpat[0]) {
 					vi_error();
 					state = VNORMAL;
-					refresh(0);
+					refresh_line(0);
 					return 0;
 				}
 			} else {
@@ -392,17 +395,17 @@ vi_hook(int ch)
 				} while (srchlen > 0 &&
 				    isu8cont(locpat[srchlen]));
 				es->cursor = es->linelen;
-				refresh(0);
+				refresh_line(0);
 				return 0;
 			}
 			restore_cbuf();
 			state = VNORMAL;
-			refresh(0);
+			refresh_line(0);
 		} else if (ch == edchars.kill) {
 			srchlen = 0;
 			es->linelen = 1;
 			es->cursor = 1;
-			refresh(0);
+			refresh_line(0);
 			return 0;
 		} else if (ch == edchars.werase) {
 			struct edstate new_es, *save_es;
@@ -421,7 +424,7 @@ vi_hook(int ch)
 				es->linelen -= char_len((unsigned char)locpat[i]);
 			srchlen = n;
 			es->cursor = es->linelen;
-			refresh(0);
+			refresh_line(0);
 			return 0;
 		} else {
 			if (srchlen == SRCHLEN - 1)
@@ -446,7 +449,7 @@ vi_hook(int ch)
 					es->cbuf[es->linelen++] = ch;
 				}
 				es->cursor = es->linelen;
-				refresh(0);
+				refresh_line(0);
 			}
 			return 0;
 		}
@@ -459,15 +462,15 @@ vi_hook(int ch)
 		switch (vi_cmd(argc1, curcmd)) {
 		case -1:
 			vi_error();
-			refresh(0);
+			refresh_line(0);
 			break;
 		case 0:
 			if (insert != 0)
 				inslen = 0;
-			refresh(insert != 0);
+			refresh_line(insert != 0);
 			break;
 		case 1:
-			refresh(0);
+			refresh_line(0);
 			return 1;
 		case 2:
 			/* back from a 'v' command - don't redraw the screen */
@@ -482,7 +485,7 @@ vi_hook(int ch)
 		switch (vi_cmd(lastac, lastcmd)) {
 		case -1:
 			vi_error();
-			refresh(0);
+			refresh_line(0);
 			break;
 		case 0:
 			if (insert != 0) {
@@ -495,10 +498,10 @@ vi_hook(int ch)
 						vi_error();
 				}
 			}
-			refresh(0);
+			refresh_line(0);
 			break;
 		case 1:
-			refresh(0);
+			refresh_line(0);
 			return 1;
 		case 2:
 			/* back from a 'v' command - can't happen */
@@ -651,6 +654,10 @@ vi_insert(int ch)
 		print_expansions(es);
 		break;
 
+	case CTRL('l'):
+		do_clear_screen();
+		break;
+
 	case CTRL('i'):
 		if (Flag(FVITABCOMPLETE)) {
 			complete_word(0, 0);
@@ -708,6 +715,9 @@ vi_cmd(int argcnt, const char *cmd)
 		switch (*cmd) {
 
 		case CTRL('l'):
+			do_clear_screen();
+			break;
+
 		case CTRL('r'):
 			redraw_line(1);
 			break;
@@ -1028,7 +1038,7 @@ vi_cmd(int argcnt, const char *cmd)
 			    c1, srchpat)) < 0) {
 				if (c3) {
 					restore_cbuf();
-					refresh(0);
+					refresh_line(0);
 				}
 				return -1;
 			} else {
@@ -1717,10 +1727,24 @@ grabsearch(int save, int start, int fwd, char *pat)
 }
 
 static void
-redraw_line(int newline)
+do_clear_screen(void)
+{
+	int neednl = 1;
+
+#ifndef SMALL
+	if (cur_term != NULL && clear_screen != NULL) {
+		if (tputs(clear_screen, 1, x_putc) != ERR)
+			neednl = 0;
+	}
+#endif
+	redraw_line(neednl);
+}
+
+static void
+redraw_line(int neednl)
 {
 	(void) memset(wbuf[win], ' ', wbuf_len);
-	if (newline) {
+	if (neednl) {
 		x_putc('\r');
 		x_putc('\n');
 	}
@@ -1730,7 +1754,7 @@ redraw_line(int newline)
 }
 
 static void
-refresh(int leftside)
+refresh_line(int leftside)
 {
 	if (outofwin())
 		rewindow();
@@ -2033,7 +2057,7 @@ expand_word(int command)
 	modified = 1; hnum = hlast;
 	insert = INSERT;
 	lastac = 0;
-	refresh(0);
+	refresh_line(0);
 	return rval;
 }
 
@@ -2137,7 +2161,7 @@ complete_word(int command, int count)
 	modified = 1; hnum = hlast;
 	insert = INSERT;
 	lastac = 0;	 /* prevent this from being redone... */
-	refresh(0);
+	refresh_line(0);
 
 	return rval;
 }