loksh-noxz

[fork] a Linux port of OpenBSD's ksh
git clone git://git.noxz.tech/loksh-noxz
Log | Files | Refs | Submodules | README

commit 5f43fd7f991c08d7b694579b643bc7423c75b957
parent 116a1847123df86241856d5e744c0afeb35a2f78
Author: Chris Noxz <chris@noxz.tech>
Date:   Tue,  9 Mar 2021 19:25:38 +0100

Match upstream 6.8

Diffstat:
Mc_sh.c | 8+++++++-
Memacs.c | 12+++++++-----
Meval.c | 65++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mjobs.c | 30++++++++++++++++++++++++++++--
Mksh.1 | 23+++++++++++++++++++----
Mmisc.c | 6+++++-
Msh.h | 3++-
Mvi.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
8 files changed, 166 insertions(+), 57 deletions(-)

diff --git a/c_sh.c b/c_sh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: c_sh.c,v 1.63 2018/04/09 17:53:36 tobias Exp $ */ +/* $OpenBSD: c_sh.c,v 1.64 2020/05/22 07:50:07 benno Exp $ */ /* * built-in Bourne commands @@ -425,6 +425,8 @@ int c_eval(char **wp) { struct source *s; + struct source *saves = source; + int savef; int rv; if (ksh_getopt(wp, &builtin_opt, null) == '?') @@ -459,7 +461,11 @@ c_eval(char **wp) exstat = subst_exstat; } + savef = Flag(FERREXIT); + Flag(FERREXIT) = 0; rv = shell(s, false); + Flag(FERREXIT) = savef; + source = saves; afree(s, ATEMP); return (rv); } diff --git a/emacs.c b/emacs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: emacs.c,v 1.86 2019/04/03 14:55:12 jca Exp $ */ +/* $OpenBSD: emacs.c,v 1.87 2020/05/08 14:30:42 jca Exp $ */ /* * Emacs-like command line editing and history @@ -41,8 +41,10 @@ static Area aedit; #define KEOL 1 /* ^M, ^J */ #define KINTR 2 /* ^G, ^C */ +typedef int (*kb_func)(int); + struct x_ftab { - int (*xf_func)(int c); + kb_func xf_func; const char *xf_name; short xf_flags; }; @@ -861,7 +863,7 @@ x_eot_del(int c) return (x_del_char(c)); } -static void * +static kb_func kb_find_hist_func(char c) { struct kb_entry *k; @@ -1315,7 +1317,7 @@ kb_del(struct kb_entry *k) } static struct kb_entry * -kb_add_string(void *func, void *args, char *str) +kb_add_string(kb_func func, void *args, char *str) { unsigned int ele, count; struct kb_entry *k; @@ -1350,7 +1352,7 @@ kb_add_string(void *func, void *args, char *str) } static struct kb_entry * -kb_add(void *func, ...) +kb_add(kb_func func, ...) { va_list ap; unsigned char ch; 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/jobs.c b/jobs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: jobs.c,v 1.61 2019/06/28 13:34:59 deraadt Exp $ */ +/* $OpenBSD: jobs.c,v 1.62 2020/07/07 10:33:58 jca Exp $ */ /* * Process and job control @@ -71,6 +71,7 @@ struct proc { #define JF_REMOVE 0x200 /* flagged for removal (j_jobs()/j_notify()) */ #define JF_USETTYMODE 0x400 /* tty mode saved if process exits normally */ #define JF_SAVEDTTYPGRP 0x800 /* j->saved_ttypgrp is valid */ +#define JF_PIPEFAIL 0x1000 /* pipefail on when job was started */ typedef struct job Job; struct job { @@ -426,6 +427,8 @@ exchild(struct op *t, int flags, volatile int *xerrok, */ j->flags = (flags & XXCOM) ? JF_XXCOM : ((flags & XBGND) ? 0 : (JF_FG|JF_USETTYMODE)); + if (Flag(FPIPEFAIL)) + j->flags |= JF_PIPEFAIL; timerclear(&j->usrtime); timerclear(&j->systime); j->state = PRUNNING; @@ -1089,7 +1092,30 @@ j_waitj(Job *j, j_usrtime = j->usrtime; j_systime = j->systime; - rv = j->status; + + if (j->flags & JF_PIPEFAIL) { + Proc *p; + int status; + + rv = 0; + for (p = j->proc_list; p != NULL; p = p->next) { + switch (p->state) { + case PEXITED: + status = WEXITSTATUS(p->status); + break; + case PSIGNALLED: + status = 128 + WTERMSIG(p->status); + break; + default: + status = 0; + break; + } + if (status) + rv = status; + } + } else + rv = j->status; + if (!(flags & JW_ASYNCNOTIFY) && (!Flag(FMONITOR) || j->state != PSTOPPED)) { diff --git a/ksh.1 b/ksh.1 @@ -1,8 +1,8 @@ -.\" $OpenBSD: ksh.1,v 1.208 2019/11/26 22:49:01 jmc Exp $ +.\" $OpenBSD: ksh.1,v 1.210 2020/09/20 14:40:45 millert Exp $ .\" .\" Public Domain .\" -.Dd $Mdocdate: November 26 2019 $ +.Dd $Mdocdate: September 20 2020 $ .Dt KSH 1 .Os .Sh NAME @@ -361,7 +361,9 @@ token to form pipelines, in which the standard output of each command but the last is piped (see .Xr pipe 2 ) to the standard input of the following command. -The exit status of a pipeline is that of its last command. +The exit status of a pipeline is that of its last command, unless the +.Ic pipefail +option is set. A pipeline may be prefixed by the .Ql \&! reserved word, which causes the exit status of the pipeline to be logically @@ -3664,6 +3666,10 @@ See the and .Ic pwd commands above for more details. +.It Ic pipefail +The exit status of a pipeline is the exit status of the rightmost +command in the pipeline that doesn't return 0, or 0 if all commands +returned a 0 exit status. .It Ic posix Enable POSIX mode. See @@ -5047,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 @@ -5504,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/misc.c b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.73 2019/06/28 13:34:59 deraadt Exp $ */ +/* $OpenBSD: misc.c,v 1.75 2020/07/22 19:20:41 millert Exp $ */ /* * Miscellaneous functions @@ -149,6 +149,7 @@ const struct option sh_options[] = { { "notify", 'b', OF_ANY }, { "nounset", 'u', OF_ANY }, { "physical", 0, OF_ANY }, /* non-standard */ + { "pipefail", 0, OF_ANY }, /* non-standard */ { "posix", 0, OF_ANY }, /* non-standard */ { "privileged", 'p', OF_ANY }, { "restricted", 'r', OF_CMDLINE }, @@ -613,6 +614,9 @@ do_gmatch(const unsigned char *s, const unsigned char *se, break; case '*': + /* collapse consecutive stars */ + while (ISMAGIC(p[0]) && p[1] == '*') + p += 2; if (p == pe) return 1; s--; diff --git a/sh.h b/sh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sh.h,v 1.75 2019/02/20 23:59:17 schwarze Exp $ */ +/* $OpenBSD: sh.h,v 1.76 2020/07/07 10:33:58 jca Exp $ */ /* * Public Domain Bourne/Korn shell @@ -160,6 +160,7 @@ enum sh_flag { FNOTIFY, /* -b: asynchronous job completion notification */ FNOUNSET, /* -u: using an unset var is an error */ FPHYSICAL, /* -o physical: don't do logical cd's/pwd's */ + FPIPEFAIL, /* -o pipefail: all commands in pipeline can affect $? */ FPOSIX, /* -o posix: be posixly correct */ FPRIVILEGED, /* -p: use suid_profile */ FRESTRICTED, /* -r: restricted shell */ 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 */ @@ -56,8 +58,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); @@ -275,9 +278,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; @@ -302,7 +305,7 @@ vi_hook(int ch) return -1; } else if (putbuf("?", 1, 0) != 0) return -1; - refresh(0); + refresh_line(0); } } } @@ -314,7 +317,7 @@ vi_hook(int ch) vi_error(); } else es->cbuf[es->cursor++] = ch; - refresh(1); + refresh_line(1); state = VNORMAL; break; @@ -379,7 +382,7 @@ vi_hook(int ch) if (!srchpat[0]) { vi_error(); state = VNORMAL; - refresh(0); + refresh_line(0); return 0; } } else { @@ -396,17 +399,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; @@ -425,7 +428,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) @@ -450,7 +453,7 @@ vi_hook(int ch) es->cbuf[es->linelen++] = ch; } es->cursor = es->linelen; - refresh(0); + refresh_line(0); } return 0; } @@ -463,15 +466,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 */ @@ -486,7 +489,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) { @@ -499,10 +502,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 */ @@ -655,6 +658,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); @@ -712,6 +719,9 @@ vi_cmd(int argcnt, const char *cmd) switch (*cmd) { case CTRL('l'): + do_clear_screen(); + break; + case CTRL('r'): redraw_line(1); break; @@ -1032,7 +1042,7 @@ vi_cmd(int argcnt, const char *cmd) c1, srchpat)) < 0) { if (c3) { restore_cbuf(); - refresh(0); + refresh_line(0); } return -1; } else { @@ -1721,10 +1731,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'); } @@ -1734,7 +1758,7 @@ redraw_line(int newline) } static void -refresh(int leftside) +refresh_line(int leftside) { if (outofwin()) rewindow(); @@ -2037,7 +2061,7 @@ expand_word(int command) modified = 1; hnum = hlast; set_insert(INSERT); lastac = 0; - refresh(0); + refresh_line(0); return rval; } @@ -2141,7 +2165,7 @@ complete_word(int command, int count) modified = 1; hnum = hlast; set_insert(INSERT); lastac = 0; /* prevent this from being redone... */ - refresh(0); + refresh_line(0); return rval; }