diff --git a/Build.sh b/Build.sh index 5eed038..3627a4f 100644 --- a/Build.sh +++ b/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.679 2015/05/01 16:08:26 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.681 2015/07/06 17:48:28 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015 @@ -2654,7 +2654,6 @@ MKSH_NOPROSPECTOFWORK disable jobs, co-processes, etc. (do not use) MKSH_NOPWNAM skip PAM calls, for -static on glibc or Solaris MKSH_NO_CMDLINE_EDITING disable command line editing code entirely MKSH_NO_DEPRECATED_WARNING omit warning when deprecated stuff is run -MKSH_NO_EXTERNAL_CAT omit hack to skip cat builtin when flags passed MKSH_NO_LIMITS omit ulimit code MKSH_NO_SIGSETJMP define if sigsetjmp is broken or not available MKSH_NO_SIGSUSPEND use sigprocmask+pause instead of sigsuspend diff --git a/check.t b/check.t index 17b87c6..faf93d0 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.694 2015/05/23 17:43:18 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.699 2015/07/06 17:48:29 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R51 2015/05/23 + @(#)MIRBSD KSH R51 2015/07/06 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R51 2015/05/23 + @(#)LEGACY KSH R51 2015/07/06 description: Check version of legacy shell. stdin: @@ -3583,7 +3583,7 @@ expected-stdout: a new line 1 echo abc def 2 echo FOOBAR def - 3 echo a new line + echo a new line expected-stderr-pattern: /^X*echo FOOBAR def\necho a new line\nX*$/ --- @@ -3665,7 +3665,7 @@ expected-stdout: a new line 1 echo abc def 2 echo FOOBAR def - 3 echo a new line + echo a new line expected-stderr-pattern: /^X*13\n32\necho FOOBAR def\necho a new line\nX*$/ --- @@ -8599,6 +8599,7 @@ description: Ensure concatenating behaviour matches other shells stdin: showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } + showargs 0 ""$@ x=; showargs 1 "$x"$@ set A; showargs 2 "${@:+}" n() { echo "$#"; } @@ -8618,6 +8619,7 @@ stdin: n "$@" n "$@""$e" expected-stdout: + <0> <> . <1> <> . <2> <> . 2 diff --git a/dot.mkshrc b/dot.mkshrc index d24397f..9df3205 100644 --- a/dot.mkshrc +++ b/dot.mkshrc @@ -1,5 +1,5 @@ # $Id$ -# $MirOS: src/bin/mksh/dot.mkshrc,v 1.97 2015/04/29 20:56:18 tg Exp $ +# $MirOS: src/bin/mksh/dot.mkshrc,v 1.99 2015/07/05 19:02:16 tg Exp $ #- # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015 @@ -67,8 +67,9 @@ else \typeset -Uui16 -Z11 pos=0 \typeset -Uui16 -Z5 hv=2147483647 \typeset dasc line i + \set +U - \cat "$@" | { \set +U; if \read -arN -1 line; then + \cat "$@" | if \read -arN -1 line; then \typeset -i1 'line[*]' i=0 while (( i < ${#line[*]} )); do @@ -95,7 +96,7 @@ else \builtin print -n -- '- ' done (( hv == 2147483647 )) || \builtin print -r -- "$dasc|" - fi; } + fi } fi @@ -112,7 +113,7 @@ function chpwd { \: } \chpwd . -function cd { +cd() { \builtin cd "$@" || \return $? \chpwd "$@" } @@ -271,8 +272,8 @@ function smores { # base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe function Lb64decode { - [[ -o utf8-mode ]]; \typeset u=$? c s="$*" t \set +U + \typeset c s="$*" t [[ -n $s ]] || { s=$(\cat; \builtin print x); s=${s%x}; } \typeset -i i=0 j=0 n=${#s} p=0 v x \typeset -i16 o @@ -303,14 +304,13 @@ function Lb64decode { t= done \builtin print -n $t - (( u )) || \set -U } \set -A Lb64encode_tbl -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \ a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + / function Lb64encode { - [[ -o utf8-mode ]]; \typeset u=$? c s t \set +U + \typeset c s t if (( $# )); then \read -raN-1 s <<<"$*" \unset s[${#s[*]}-1] @@ -339,7 +339,6 @@ function Lb64encode { t= fi done - (( u )) || \set -U } # Better Avalanche for the Jenkins Hash @@ -348,8 +347,8 @@ function Lbafh_init { Lbafh_v=0 } function Lbafh_add { - [[ -o utf8-mode ]]; \typeset u=$? s \set +U + \typeset s if (( $# )); then \read -raN-1 s <<<"$*" \unset s[${#s[*]}-1] @@ -362,8 +361,6 @@ function Lbafh_add { ((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 )) ((# Lbafh_v ^= Lbafh_v >> 6 )) done - - (( u )) || \set -U } function Lbafh_finish { \typeset -Ui t @@ -378,10 +375,11 @@ function Lbafh_finish { # strip comments (and leading/trailing whitespace if IFS is set) from # any file(s) given as argument, or stdin if none, and spew to stdout function Lstripcom { - \cat "$@" | { \set -o noglob; while \read _line; do + \set -o noglob + \cat "$@" | while \read _line; do _line=${_line%%#*} [[ -n $_line ]] && \builtin print -r -- $_line - done; } + done } # give MidnightBSD's laffer1 a bit of csh feeling diff --git a/edit.c b/edit.c index 1b7ecdc..e06b69f 100644 --- a/edit.c +++ b/edit.c @@ -28,7 +28,7 @@ #ifndef MKSH_NO_CMDLINE_EDITING -__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.286 2015/05/03 11:28:53 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.287 2015/07/05 19:37:13 tg Exp $"); /* * in later versions we might use libtermcap for this, but since external @@ -3101,7 +3101,7 @@ x_edit_line(int c MKSH_A_UNUSED) } if (modified) { *xep = '\0'; - histsave(&source->line, xbuf, true, true); + histsave(&source->line, xbuf, HIST_STORE, true); x_arg = 0; } else x_arg = source->line - (histptr - x_histp); @@ -4390,8 +4390,8 @@ vi_cmd(int argcnt, const char *cmd) return (-1); if (modified) { es->cbuf[es->linelen] = '\0'; - histsave(&source->line, es->cbuf, true, - true); + histsave(&source->line, es->cbuf, + HIST_STORE, true); } else argcnt = source->line + 1 - (hlast - hnum); diff --git a/eval.c b/eval.c index ccdb7b2..950bfe9 100644 --- a/eval.c +++ b/eval.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.169 2015/05/23 17:43:19 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.170 2015/07/06 17:45:33 tg Exp $"); /* * string expansion @@ -291,21 +291,14 @@ expand( c = *sp++; break; case OQUOTE: - switch (word) { - case IFS_QUOTE: - /* """something */ - word = IFS_WORD; - break; - case IFS_WORD: - break; - default: + if (word != IFS_WORD) word = IFS_QUOTE; - break; - } tilde_ok = 0; quote = 1; continue; case CQUOTE: + if (word == IFS_QUOTE) + word = IFS_WORD; quote = st->quotew; continue; case COMSUB: diff --git a/exec.c b/exec.c index e44063a..9176a31 100644 --- a/exec.c +++ b/exec.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.152 2015/04/29 18:32:43 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.155 2015/07/06 17:48:31 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL UNIXROOT "/bin/sh" @@ -41,8 +41,8 @@ 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); /* XXX: horrible kludge to fit within the framework */ -static char *plain_fmt_entry(char *, size_t, unsigned int, const void *); -static char *select_fmt_entry(char *, size_t, unsigned int, const void *); +static void plain_fmt_entry(char *, size_t, unsigned int, const void *); +static void select_fmt_entry(char *, size_t, unsigned int, const void *); /* * execute command tree @@ -551,6 +551,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, } if ((tp = findcom(cp, FC_BI)) == NULL) errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin"); + if (tp->type == CSHELL && tp->val.f == c_cat) + break; continue; } else if (tp->val.f == c_exec) { if (ap[1] == NULL) @@ -607,25 +609,19 @@ 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 we have any flags, do not use the builtin */ 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 + (ap[1][1] != '-' || ap[1][2] != '\0')) { + struct tbl *ext_cat; + + ext_cat = findcom(Tcat, FC_PATH | FC_FUNC); + if (ext_cat && (ext_cat->type != CTALIAS || + (ext_cat->flag & ISSET))) + tp = ext_cat; + } + break; } else if (tp->val.f == c_trap) { t->u.evalflags &= ~DOTCOMEXEC; break; @@ -705,6 +701,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* shell built-in */ case CSHELL: + do_call_builtin: rv = call_builtin(tp, (const char **)ap, null, resetspec); if (resetspec && tp->val.f == c_shift) { l_expand->argc = l_assign->argc; @@ -729,6 +726,11 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, break; } if (include(tp->u.fpath, 0, NULL, false) < 0) { + if (!strcmp(cp, Tcat)) { + no_cat_in_FPATH: + tp = findcom(Tcat, FC_BI); + goto do_call_builtin; + } warningf(true, "%s: %s %s %s: %s", cp, "can't open", "function definition file", tp->u.fpath, cstrerror(errno)); @@ -737,6 +739,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, } if (!(ftp = findfunc(cp, hash(cp), false)) || !(ftp->flag & ISSET)) { + if (!strcmp(cp, Tcat)) + goto no_cat_in_FPATH; warningf(true, "%s: %s %s", cp, "function not defined by", tp->u.fpath); rv = 127; @@ -1657,7 +1661,7 @@ struct select_menu_info { }; /* format a single select menu item */ -static char * +static void select_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) { const struct select_menu_info *smi = @@ -1665,7 +1669,6 @@ select_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) shf_snprintf(buf, buflen, "%*u) %s", smi->num_width, i + 1, smi->args[i]); - return (buf); } /* @@ -1711,11 +1714,10 @@ pr_menu(const char * const *ap) true); } -static char * +static void plain_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) { strlcpy(buf, ((const char * const *)arg)[i], buflen); - return (buf); } void diff --git a/funcs.c b/funcs.c index 279a7ea..9964b13 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.272 2015/05/01 23:16:29 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.277 2015/07/06 17:48:32 tg Exp $"); #if HAVE_KILLPG /* @@ -99,7 +99,7 @@ const struct builtin mkshbuiltins[] = { {Talias, c_alias}, {"*=break", c_brkcont}, {Tgbuiltin, c_builtin}, - {"cat", c_cat}, + {Tcat, c_cat}, {"cd", c_cd}, /* dash compatibility hack */ {"chdir", c_cd}, @@ -227,7 +227,7 @@ static int test_primary(Test_env *, bool); static Test_op ptest_isa(Test_env *, Test_meta); static const char *ptest_getopnd(Test_env *, Test_op, bool); static void ptest_error(Test_env *, int, const char *); -static char *kill_fmt_entry(char *, size_t, unsigned int, const void *); +static void kill_fmt_entry(char *, size_t, unsigned int, const void *); static void p_time(struct shf *, bool, long, int, int, const char *, const char *); @@ -445,7 +445,7 @@ c_print(const char **wp) if (flags & PO_HIST) { Xput(xs, xp, '\0'); - histsave(&source->line, Xstring(xs, xp), true, false); + histsave(&source->line, Xstring(xs, xp), HIST_STORE, false); Xfree(xs, xp); } else { int len = Xlength(xs, xp); @@ -541,7 +541,7 @@ c_whence(const char **wp) uint32_t h = 0; tp = NULL; - if ((iam_whence || vflag) && !pflag) + if (!pflag) tp = ktsearch(&keywords, id, h = hash(id)); if (!tp && !pflag) { tp = ktsearch(&aliases, id, h ? h : hash(id)); @@ -1310,7 +1310,7 @@ c_fgbg(const char **wp) #endif /* format a single kill item */ -static char * +static void kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) { const struct kill_info *ki = (const struct kill_info *)arg; @@ -1320,7 +1320,6 @@ kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) ki->num_width, i, ki->name_width, sigtraps[i].name, sigtraps[i].mess); - return (buf); } int @@ -1967,8 +1966,9 @@ c_read(const char **wp) break; case 0: /* timeout expired for this call */ - rv = 1; - goto c_read_out; + bytesread = 0; + /* fake EOF read; all cases return 1 */ + goto c_read_didread; default: bi_errorf("%s: %s", Tselect, cstrerror(errno)); rv = 2; @@ -1993,6 +1993,7 @@ c_read(const char **wp) goto c_read_readloop; } + c_read_didread: switch (readmode) { case READALL: if (bytesread == 0) { @@ -2015,7 +2016,7 @@ c_read(const char **wp) if (bytesread == 0) { /* end of file reached */ rv = 1; - xp = Xstring(xs, xp); + /* may be partial read: $? = 1, but content */ goto c_read_readdone; } xp += bytesread; @@ -2078,7 +2079,7 @@ c_read(const char **wp) } if (savehist) - histsave(&source->line, Xstring(xs, xp), true, false); + histsave(&source->line, Xstring(xs, xp), HIST_STORE, false); ccp = cp = Xclose(xs, xp); expanding = false; diff --git a/histrap.c b/histrap.c index 37ee258..d19dbb6 100644 --- a/histrap.c +++ b/histrap.c @@ -27,7 +27,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.143 2015/04/29 20:44:35 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.148 2015/07/05 19:53:45 tg Exp $"); Trap sigtraps[ksh_NSIG + 1]; static struct sigaction Sigact_ign; @@ -38,7 +38,7 @@ static int writehistline(int, int, const char *); static void writehistfile(int, const char *); #endif -static int hist_execute(char *); +static int hist_execute(char *, Area *); static char **hist_get(const char *, bool, bool); static char **hist_get_oldest(void); @@ -84,6 +84,9 @@ static const char TFCEDIT_dollaru[] = "${FCEDIT:-/bin/ed} $_"; /* maximum considered size of persistent history file */ #define MKSH_MAXHISTFSIZE ((off_t)1048576 * 96) +/* hidden option */ +#define HIST_DISCARD 5 + int c_fc(const char **wp) { @@ -223,7 +226,7 @@ c_fc(const char **wp) xp += len; line = Xclose(xs, xp); } - return (hist_execute(line)); + return (hist_execute(line, ATEMP)); } if (editor && (lflag || nflag)) { @@ -360,18 +363,17 @@ c_fc(const char **wp) shf_close(shf); *xp = '\0'; strip_nuls(Xstring(xs, xp), Xlength(xs, xp)); - return (hist_execute(Xstring(xs, xp))); + return (hist_execute(Xstring(xs, xp), hist_source->areap)); } } -/* Save cmd in history, execute cmd (cmd gets trashed) */ +/* save cmd in history, execute cmd (cmd gets afree’d) */ static int -hist_execute(char *cmd) +hist_execute(char *cmd, Area *areap) { static int last_line = -1; Source *sold; int ret; - char *p, *q; /* Back up over last histsave */ if (histptr >= history && last_line != hist_source->line) { @@ -381,22 +383,12 @@ hist_execute(char *cmd) last_line = hist_source->line; } - for (p = cmd; p; p = q) { - if ((q = strchr(p, '\n'))) { - /* kill the newline */ - *q++ = '\0'; - if (!*q) - /* ignore trailing newline */ - q = NULL; - } - histsave(&hist_source->line, p, true, true); - - /* POSIX doesn't say this is done... */ - shellf("%s\n", p); - if (q) - /* restore \n (trailing \n not restored) */ - q[-1] = '\n'; - } + histsave(&hist_source->line, cmd, HIST_STORE, true); + /* now *histptr == cmd without all trailing newlines */ + afree(cmd, areap); + cmd = *histptr; + /* pdksh says POSIX doesn’t say this is done, testsuite needs it */ + shellf("%s\n", cmd); /*- * Commands are executed here instead of pushing them onto the @@ -578,6 +570,7 @@ sethistfile(const char *name) afree(hname, APERM); hname = NULL; /* let's reset the history */ + histsave(NULL, NULL, HIST_DISCARD, true); histptr = history - 1; hist_source->line = 0; } @@ -612,6 +605,8 @@ histsync(void) { bool changed = false; + /* called by histsave(), may not HIST_DISCARD, caller should flush */ + if (histfd != -1) { int lno = hist_source->line; @@ -631,29 +626,73 @@ histsync(void) * save command in history */ void -histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups) +histsave(int *lnp, const char *cmd, int svmode, bool ignoredups) { - char **hp; - char *c, *cp; + static char *enqueued = NULL; + char **hp, *c; + const char *ccp; - strdupx(c, cmd, APERM); - if ((cp = strchr(c, '\n')) != NULL) - *cp = '\0'; + if (svmode == HIST_DISCARD) { + afree(enqueued, APERM); + enqueued = NULL; + return; + } - if (ignoredups && !strcmp(c, *histptr) + if (svmode == HIST_APPEND) { + if (!enqueued) + svmode = HIST_STORE; + } else if (enqueued) { + c = enqueued; + enqueued = NULL; + --*lnp; + histsave(lnp, c, HIST_STORE, true); + afree(c, APERM); + } + + if (svmode == HIST_FLUSH) + return; + + ccp = cmd + strlen(cmd); + while (ccp > cmd && ccp[-1] == '\n') + --ccp; + strndupx(c, cmd, ccp - cmd, APERM); + + if (svmode != HIST_APPEND) { + if (ignoredups && !strcmp(c, *histptr) #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY - && !histsync() + && !histsync() #endif - ) { + ) { + afree(c, APERM); + return; + } + ++*lnp; + } + +#if HAVE_PERSISTENT_HISTORY + if (svmode == HIST_STORE && histfd != -1) + writehistfile(*lnp, c); +#endif + + if (svmode == HIST_QUEUE || svmode == HIST_APPEND) { + size_t nenq, ncmd; + + if (!enqueued) { + if (*c) + enqueued = c; + else + afree(c, APERM); + return; + } + + nenq = strlen(enqueued); + ncmd = strlen(c); + enqueued = aresize(enqueued, nenq + 1 + ncmd + 1, APERM); + enqueued[nenq] = '\n'; + memcpy(enqueued + nenq + 1, c, ncmd + 1); afree(c, APERM); return; } - ++*lnp; - -#if HAVE_PERSISTENT_HISTORY - if (dowrite && histfd != -1) - writehistfile(*lnp, c); -#endif hp = histptr; @@ -707,6 +746,8 @@ hist_init(Source *s) enum { hist_init_first, hist_init_retry, hist_init_restore } hs; #endif + histsave(NULL, NULL, HIST_DISCARD, true); + if (Flag(FTALKING) == 0) return; @@ -864,7 +905,7 @@ histload(Source *s, unsigned char *base, size_t bytes) } } else { s->line = lno--; - histsave(&lno, (char *)(base + 4), false, false); + histsave(&lno, (char *)(base + 4), HIST_NOTE, false); } /* advance base pointer past NUL */ bytes -= ++cp - base; diff --git a/lex.c b/lex.c index 3046e52..fb80244 100644 --- a/lex.c +++ b/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.201 2015/04/29 20:07:33 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.204 2015/07/05 19:53:46 tg Exp $"); /* * states while lexing word @@ -1461,16 +1461,23 @@ getsc_line(Source *s) if (s->type == SFILE) shf_fdclose(s->u.shf); s->str = NULL; - } else if (interactive && *s->str && - (cur_prompt != PS1 || !ctype(*s->str, C_IFS | C_IFSWS))) { - histsave(&s->line, s->str, true, true); + } else if (interactive && *s->str) { + if (cur_prompt != PS1) + histsave(&s->line, s->str, HIST_APPEND, true); + else if (!ctype(*s->str, C_IFS | C_IFSWS)) + histsave(&s->line, s->str, HIST_QUEUE, true); #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY + else + goto check_for_sole_return; } else if (interactive && cur_prompt == PS1) { + check_for_sole_return: cp = Xstring(s->xs, xp); while (*cp && ctype(*cp, C_IFSWS)) ++cp; - if (!*cp) + if (!*cp) { + histsave(&s->line, NULL, HIST_FLUSH, true); histsync(); + } #endif } if (interactive) @@ -1495,6 +1502,7 @@ set_prompt(int to, Source *s) struct shf *shf; char * volatile ps1; Area *saved_atemp; + int saved_lineno; ps1 = str_val(global("PS1")); shf = shf_sopen(NULL, strlen(ps1) * 2, @@ -1506,6 +1514,9 @@ set_prompt(int to, Source *s) shf_fprintf(shf, "%lu", s ? (unsigned long)s->line + 1 : 0UL); ps1 = shf_sclose(shf); + saved_lineno = current_lineno; + if (s) + current_lineno = s->line + 1; saved_atemp = ATEMP; newenv(E_ERRH); if (kshsetjmp(e->jbuf)) { @@ -1521,6 +1532,7 @@ set_prompt(int to, Source *s) char *cp = substitute(ps1, 0); strdupx(prompt, cp, saved_atemp); } + current_lineno = saved_lineno; quitenv(NULL); } break; diff --git a/main.c b/main.c index 7a97005..3602372 100644 --- a/main.c +++ b/main.c @@ -34,7 +34,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.293 2015/04/29 20:07:33 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.295 2015/07/06 17:48:34 tg Exp $"); extern char **environ; @@ -87,7 +87,7 @@ static const char *initcoms[] = { NULL, /* this is what AT&T ksh seems to track, with the addition of emacs */ Talias, "-tU", - "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls", + Tcat, "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", NULL, NULL }; @@ -825,6 +825,8 @@ shell(Source * volatile s, volatile bool toplevel) set_prompt(PS1, s); } t = compile(s, sfirst); + if (interactive) + histsave(&s->line, NULL, HIST_FLUSH, true); sfirst = false; if (!t) goto source_no_tree; diff --git a/mirhash.h b/mirhash.h index 05729bc..df4a9dc 100644 --- a/mirhash.h +++ b/mirhash.h @@ -1,6 +1,6 @@ /*- - * Copyright © 2011, 2014 - * Thorsten Glaser + * Copyright © 2011, 2014, 2015 + * Thorsten “mirabilos” Glaser * * Provided that these terms and disclaimer and all copyright notices * are retained or reproduced in an accompanying document, permission @@ -44,7 +44,7 @@ #include -__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.3 2014/10/02 19:34:06 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.4 2015/05/30 22:14:06 tg Exp $"); /*- * BAFH itself is defined by the following primitives: @@ -61,7 +61,8 @@ __RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.3 2014/10/02 19:34:06 tg Exp $"); * the context is (still) zero, adding a NUL byte is not ignored. * * • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”, - * rotated right by “cl” ∈ [0;31]; no casting, be careful! + * rotated right by “cl” ∈ [0; 31] (no casting, be careful!) where + * “eax” must be uint32_t and “cl” an in-range integer. * * • BAFHFinish(ctx) avalanches the context around so every sub-byte * depends on all input octets; afterwards, the context variable’s @@ -88,7 +89,7 @@ __RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.3 2014/10/02 19:34:06 tg Exp $"); * • BAFHHostStr(ctx,buf) does the same for C strings. * * All macros may use ctx multiple times in their expansion, but all - * other arguments are always evaluated at most once. + * other arguments are always evaluated at most once except BAFHror. * * To stay portable, never use the BAFHHost*() macros (these are for * host-local entropy shuffling), and encode numbers using ULEB128. @@ -206,6 +207,7 @@ __RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.3 2014/10/02 19:34:06 tg Exp $"); } BAFHHost_v; \ \ BAFHUpdate_s = (const void *)(s); \ + BAFHHost_v.as_u32 = 0; \ if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0) \ ++BAFHUpdate_s; \ if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0) \ diff --git a/misc.c b/misc.c index 87bed50..ad989a6 100644 --- a/misc.c +++ b/misc.c @@ -30,7 +30,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.232 2015/05/01 23:16:30 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.236 2015/07/05 14:58:33 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -173,11 +173,11 @@ struct options_info { int opts[NELEM(options)]; }; -static char *options_fmt_entry(char *, size_t, unsigned int, const void *); +static void options_fmt_entry(char *, size_t, unsigned int, const void *); static void printoptions(bool); /* format a single select menu item */ -static char * +static void options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) { const struct options_info *oi = (const struct options_info *)arg; @@ -185,7 +185,6 @@ options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) shf_snprintf(buf, buflen, "%-*s %s", oi->opt_width, OFN(oi->opts[i]), Flag(oi->opts[i]) ? "on" : "off"); - return (buf); } static void @@ -1227,7 +1226,7 @@ print_value_quoted(struct shf *shf, const char *s) */ void print_columns(struct shf *shf, unsigned int n, - char *(*func)(char *, size_t, unsigned int, const void *), + void (*func)(char *, size_t, unsigned int, const void *), const void *arg, size_t max_oct, size_t max_colz, bool prefcol) { unsigned int i, r, c, rows, cols, nspace, max_col; @@ -1256,17 +1255,20 @@ print_columns(struct shf *shf, unsigned int n, str = alloc(max_oct, ATEMP); /* - * We use (max_col + 1) to consider the space separator. - * Note that no space is printed after the last column - * to avoid problems with terminals that have auto-wrap. + * We use (max_col + 2) to consider the separator space. + * Note that no spaces are printed after the last column + * to avoid problems with terminals that have auto-wrap, + * but we need to also take this into account in x_cols. */ - cols = x_cols / (max_col + 1); + cols = (x_cols + 1) / (max_col + 2); /* if we can only print one column anyway, skip the goo */ if (cols < 2) { - for (i = 0; i < n; ++i) - shf_fprintf(shf, "%s\n", - (*func)(str, max_oct, i, arg)); + for (i = 0; i < n; ++i) { + (*func)(str, max_oct, i, arg); + shf_puts(str, shf); + shf_putc('\n', shf); + } goto out; } @@ -1277,18 +1279,19 @@ print_columns(struct shf *shf, unsigned int n, } nspace = (x_cols - max_col * cols) / cols; + if (nspace < 2) + nspace = 2; max_col = -max_col; - if (nspace <= 0) - nspace = 1; for (r = 0; r < rows; r++) { for (c = 0; c < cols; c++) { - i = c * rows + r; - if (i < n) { - shf_fprintf(shf, "%*s", max_col, - (*func)(str, max_oct, i, arg)); - if (c + 1 < cols) - shf_fprintf(shf, "%*s", nspace, null); - } + if ((i = c * rows + r) >= n) + break; + (*func)(str, max_oct, i, arg); + if (i + rows >= n) + shf_puts(str, shf); + else + shf_fprintf(shf, "%*s%*s", + max_col, str, nspace, null); } shf_putchar('\n', shf); } diff --git a/mksh.1 b/mksh.1 index 6f2c257..85dbda4 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,5 +1,5 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.367 2015/05/23 17:43:20 tg Exp $ -.\" $OpenBSD: ksh.1,v 1.159 2015/03/25 12:10:52 jca Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.373 2015/07/06 17:48:35 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, .\" 2010, 2011, 2012, 2013, 2014, 2015 @@ -74,7 +74,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" use our own definition. And .Dd must come *first*, always. .\" -.Dd $Mdocdate: May 23 2015 $ +.Dd $Mdocdate: July 6 2015 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -476,7 +476,7 @@ and .Ql } delimit .Xr csh 1 Ns -style -alterations (see +alternations (see .Sx Brace expansion below); and finally, @@ -1859,7 +1859,8 @@ below for more information. .It Ev HISTFILE The name of the file used to store command history. When assigned to or unset, the file is opened, history is truncated -then loaded from the file; subsequent new lines are appended. +then loaded from the file; subsequent new commands (possibly consisting +of several lines) are appended once they successfully compiled. Also, several invocations of the shell will share history if their .Ev HISTFILE parameters all point to the same file. @@ -2145,7 +2146,7 @@ The .Ic alias Fl d command may be used to list, change, and add to this cache (e.g.\& .Ic alias \-d fac=/usr/local/facilities; cd \*(TIfac/bin ) . -.Ss Brace expansion (alteration) +.Ss Brace expansion (alternation) Brace expressions take the following form: .Bd -unfilled -offset indent .Sm off @@ -3160,15 +3161,13 @@ If a is a single dash .Pq Sq - or absent, read from standard input. -Unless compiled with -.Dv MKSH_NO_EXTERNAL_CAT , -if any options are given, an external -.Xr cat 1 -utility is invoked instead if called from the shell. For direct builtin calls, the .Tn POSIX .Fl u option is supported as a no-op. +For calls from shell, if any options are given, an external +.Xr cat 1 +utility is preferred over the builtin. .Pp .It Xo .Ic cd @@ -3296,9 +3295,9 @@ option is given, instead of executing .Ar cmd , information about what would be executed is given (and the same is done for .Ar arg ... ) . -For special and regular built-in commands and functions, their names are simply -printed; for aliases, a command that defines them is printed; and for commands -found by searching the +For builtins, functions and keywords, their names are simply printed; +for aliases, a command that defines them is printed; +for utilities found by searching the .Ev PATH parameter, the full path of the command is printed. If no command is found @@ -3832,7 +3831,8 @@ if empty, instead of the ASCII newline character as input line delimiter. .It Fl N Ar z Instead of reading till end-of-line, read exactly .Ar z -bytes; less if EOF or a timeout occurs. +bytes. +If EOF or a timeout occurs, a partial read is returned with exit status 1. .It Fl n Ar z Instead of reading till end-of-line, read up to .Ar z @@ -3851,6 +3851,9 @@ The argument must immediately follow the option character. Interrupt reading after .Ar n seconds (specified as positive decimal value with an optional fractional part). +The exit status of +.Nm read +is 1 if the timeout occurred, but partial reads may still be returned. .It Fl r Normally, the ASCII backslash character escapes the special meaning of the following character and is stripped from the input; diff --git a/sh.h b/sh.h index 83e4b1f..cde4def 100644 --- a/sh.h +++ b/sh.h @@ -172,9 +172,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.730 2015/05/23 17:43:22 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.734 2015/07/06 17:48:37 tg Exp $"); #endif -#define MKSH_VERSION "R51 2015/05/23" +#define MKSH_VERSION "R51 2015/07/06" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -861,6 +861,7 @@ EXTERN const char T_typeset[] E_INIT("=typeset"); #define Ttypeset (T_typeset + 1) /* "typeset" */ EXTERN const char Talias[] E_INIT("alias"); EXTERN const char Tunalias[] E_INIT("unalias"); +EXTERN const char Tcat[] E_INIT("cat"); EXTERN const char Tsgset[] E_INIT("*=set"); #define Tset (Tsgset + 2) /* "set" */ EXTERN const char Tsgexport[] E_INIT("*=export"); @@ -1665,6 +1666,13 @@ EXTERN char **history; /* saved commands */ EXTERN char **histptr; /* last history item */ EXTERN mksh_ari_t histsize; /* history size */ +/* flags to histsave */ +#define HIST_FLUSH 0 +#define HIST_QUEUE 1 +#define HIST_APPEND 2 +#define HIST_STORE 3 +#define HIST_NOTE 4 + /* user and system time of last j_waitjed job */ EXTERN struct timeval j_usrtime, j_systime; @@ -1791,7 +1799,7 @@ void hist_init(Source *); #if HAVE_PERSISTENT_HISTORY void hist_finish(void); #endif -void histsave(int *, const char *, bool, bool); +void histsave(int *, const char *, int, bool); #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY bool histsync(void); #endif @@ -1934,7 +1942,7 @@ int ksh_getopt(const char **, Getopt *, const char *); void print_value_quoted(struct shf *, const char *); char *quote_value(const char *); void print_columns(struct shf *, unsigned int, - char *(*)(char *, size_t, unsigned int, const void *), + void (*)(char *, size_t, unsigned int, const void *), const void *, size_t, size_t, bool); void strip_nuls(char *, size_t) MKSH_A_BOUNDED(__string__, 1, 2);