diff --git a/Build.sh b/Build.sh index d9f6761..2a078c5 100644 --- a/Build.sh +++ b/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.696 2016/01/21 18:24:33 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.697 2016/03/04 18:28:39 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015, 2016 @@ -2347,7 +2347,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c 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=522 +add_cppflags -DMKSH_BUILD_R=523 $e $bi$me: Finished configuration testing, now producing output.$ao diff --git a/Makefile b/Makefile deleted file mode 100644 index 871f27d..0000000 --- a/Makefile +++ /dev/null @@ -1,188 +0,0 @@ -# $MirOS: src/bin/mksh/Makefile,v 1.146 2016/01/21 18:24:34 tg Exp $ -#- -# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013, 2014, 2015, 2016 -# mirabilos -# -# 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. - -.ifmake d -__CRAZY= Yes -MKC_DEBG= cpp -DEBUGFILE= Yes -NOMAN= Yes -.endif - -.include - -SRCDIR= ${.CURDIR} - -PROG= mksh -SRCS= edit.c eval.c exec.c expr.c funcs.c histrap.c jobs.c \ - lalloc.c lex.c main.c misc.c shf.c syn.c tree.c var.c -.if !make(test-build) -CPPFLAGS+= -DMKSH_ASSUME_UTF8 -DMKSH_DISABLE_DEPRECATED \ - -DHAVE_ATTRIBUTE_BOUNDED=1 -DHAVE_ATTRIBUTE_FORMAT=1 \ - -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 \ - -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 \ - -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 \ - -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 \ - -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 \ - -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 \ - -DHAVE_SYS_SYSMACROS_H=0 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 \ - -DHAVE_IO_H=0 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 \ - -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 \ - -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 \ - -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 \ - -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 \ - -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=1 -DHAVE_SYS_SIGNAME=1 \ - -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 \ - -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 \ - -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 \ - -DHAVE_NICE=1 -DHAVE_REVOKE=1 -DHAVE_SETLOCALE_CTYPE=0 \ - -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 \ - -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=0 -DHAVE_STRSIGNAL=0 \ - -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \ - -DHAVE_SYS_ERRLIST_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \ - -DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=522 -CPPFLAGS+= -D${${PROG:L}_tf:C/(Mir${MAN:E}{0,1}){2}/4/:S/x/mksh_BUILD/:U} -CPPFLAGS+= -I. -COPTS+= -std=c89 -Wall -.endif - -USE_PRINTF_BUILTIN?= 0 -.if ${USE_PRINTF_BUILTIN} == 1 -.PATH: ${BSDSRCDIR}/usr.bin/printf -SRCS+= printf.c -CPPFLAGS+= -DMKSH_PRINTF_BUILTIN -.endif - -DEBUGFILE?= No -.if ${DEBUGFILE:L} == "yes" -CPPFLAGS+= -DDF=mksh_debugtofile -.endif - -MANLINKS= [ false pwd sh sleep test true -BINLINKS= ${MANLINKS} echo domainname kill -.for _i in ${BINLINKS} -LINKS+= ${BINDIR}/${PROG} ${BINDIR}/${_i} -.endfor -.for _i in ${MANLINKS} -MLINKS+= ${PROG}.1 ${_i}.1 -.endfor - -OPTGENS!= cd ${SRCDIR:Q} && echo *.opt -.for _i in ${OPTGENS} -GENERATED+= ${_i:R}.gen -${_i:R}.gen: ${_i} ${SRCDIR}/Build.sh - /bin/sh ${SRCDIR:Q}/Build.sh -G ${SRCDIR:Q}/${_i:Q} -.endfor -CLEANFILES+= ${GENERATED} - -${PROG} beforedepend: ${GENERATED} - -regress: ${PROG} check.pl check.t - -rm -rf regress-dir - mkdir -p regress-dir - echo export FNORD=666 >regress-dir/.mkshrc - HOME=$$(realpath regress-dir) perl ${SRCDIR}/check.pl \ - -s ${SRCDIR}/check.t -v -p ./${PROG} \ - -C shell:legacy-no,int:32,fastbox - -test-build: .PHONY - -rm -rf build-dir - mkdir -p build-dir -.if ${USE_PRINTF_BUILTIN} == 1 - cp ${BSDSRCDIR}/usr.bin/printf/printf.c build-dir/ -.endif - cd build-dir; env CC=${CC:Q} CFLAGS=${CFLAGS:M*:Q} \ - CPPFLAGS=${CPPFLAGS:M*:Q} LDFLAGS=${LDFLAGS:M*:Q} \ - LIBS= NOWARN=-Wno-error TARGET_OS= CPP= /bin/sh \ - ${SRCDIR}/Build.sh -Q -r ${_TBF} && ./test.sh -v -f - -CLEANFILES+= lksh.cat1 -test-build-lksh: .PHONY - cd ${SRCDIR} && exec ${MAKE} lksh.cat1 test-build _TBF=-L - -bothmans: .PHONY - cd ${SRCDIR} && exec ${MAKE} MAN='lksh.1 mksh.1' __MANALL - -cleandir: clean-extra - -clean-extra: .PHONY - -rm -rf build-dir regress-dir printf.o printf.ln - -mksh_tf=xMakefile${OStype:S/${MACHINE_OS}/1/1g}${OSNAME} -distribution: - sed 's!\$$I''d\([:$$]\)!$$M''irSecuCron\1!g' \ - ${SRCDIR}/dot.mkshrc >${DESTDIR}/etc/skel/.mkshrc - chown ${BINOWN}:${CONFGRP} ${DESTDIR}/etc/skel/.mkshrc - chmod 0644 ${DESTDIR}/etc/skel/.mkshrc - -.include - -.ifmake cats -V_GROFF!= pkg_info -e 'groff-*' -V_GHOSTSCRIPT!= pkg_info -e 'ghostscript-*' -. if empty(V_GROFF) || empty(V_GHOSTSCRIPT) -. error empty V_GROFF=${V_GROFF} or V_GHOSTSCRIPT=${V_GHOSTSCRIPT} -. endif -.endif - -CLEANFILES+= ${MANALL:S/.cat/.ps/} ${MAN:S/$/.pdf/} ${MANALL:S/$/.gz/} -CLEANFILES+= ${MAN:S/$/.htm/} ${MAN:S/$/.htm.gz/} -CLEANFILES+= ${MAN:S/$/.txt/} ${MAN:S/$/.txt.gz/} -CATS_KW= mksh, ksh, sh -CATS_TITLE_mksh_1=mksh - The MirBSD Korn Shell -cats: ${MANALL} ${MANALL:S/.cat/.ps/} -.if "${MANALL:Nlksh.cat1:Nmksh.cat1}" != "" -. error Adjust here. -.endif -.for _m _n in mksh 1 - x=$$(ident ${SRCDIR:Q}/${_m}.${_n} | \ - awk '/Mir''OS:/ { print $$4$$5; }' | \ - tr -dc 0-9); (( $${#x} == 14 )) || exit 1; exec \ - ${MKSH} ${BSDSRCDIR:Q}/contrib/hosted/tg/ps2pdfmir -c \ - -o ${_m}.${_n}.pdf '[' /Author '(The MirOS Project)' \ - /Title '('${CATS_TITLE_${_m}_${_n}:Q}')' \ - /Subject '(BSD Reference Manual)' /ModDate "(D:$$x)" \ - /Creator '(GNU groff version ${V_GROFF:S/groff-//} \(MirPorts\))' \ - /Producer '(Artifex Ghostscript ${V_GHOSTSCRIPT:S/ghostscript-//:S/-artifex//} \(MirPorts\))' \ - /Keywords '('${CATS_KW:Q}')' /DOCINFO pdfmark \ - -f ${_m}.ps${_n} -.endfor - set -e; . ${BSDSRCDIR:Q}/scripts/roff2htm; set_target_absolute; \ - for m in ${MANALL}; do \ - bn=$${m%.*}; ext=$${m##*.cat}; \ - [[ $$bn != $$m ]]; [[ $$ext != $$m ]]; \ - gzip -n9 <"$$m" >"$$m.gz"; \ - col -bx <"$$m" >"$$bn.$$ext.txt"; \ - rm -f "$$bn.$$ext.txt.gz"; gzip -n9 "$$bn.$$ext.txt"; \ - do_conversion_verbose "$$bn" "$$ext" "$$m" "$$bn.$$ext.htm"; \ - rm -f "$$bn.$$ext.htm.gz"; gzip -n9 "$$bn.$$ext.htm"; \ - done - -.ifmake d -. ifmake obj || depend || all || install || regress || test-build -d: -. else -d: all -. endif -.endif - -dr: - p=$$(realpath ${PROG:Q}) && cd ${SRCDIR:Q} && exec ${MKSH} \ - ${BSDSRCDIR:Q}/contrib/hosted/tg/sdmksh "$$p" diff --git a/check.t b/check.t index c3c7c58..9ba412b 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.724 2016/02/24 01:47:30 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.727 2016/03/04 14:26:09 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 R52 2016/02/23 + @(#)MIRBSD KSH R52 2016/03/04 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R52 2016/02/23 + @(#)LEGACY KSH R52 2016/03/04 description: Check version of legacy shell. stdin: @@ -2249,7 +2249,7 @@ expected-stdout: hi there --- -name: heredoc-4 +name: heredoc-4a description: Check that an error occurs if the heredoc-delimiter is missing. stdin: ! @@ -2259,6 +2259,34 @@ stdin: ! expected-exit: e > 0 expected-stderr-pattern: /.*/ --- +name: heredoc-4an +description: + Check that an error occurs if the heredoc-delimiter is missing. +arguments: !-n! +stdin: ! + cat << EOF + hi + there +expected-exit: e > 0 +expected-stderr-pattern: /.*/ +--- +name: heredoc-4b +description: + Check that an error occurs if the heredoc is missing. +stdin: ! + cat << EOF +expected-exit: e > 0 +expected-stderr-pattern: /.*/ +--- +name: heredoc-4bn +description: + Check that an error occurs if the heredoc is missing. +arguments: !-n! +stdin: ! + cat << EOF +expected-exit: e > 0 +expected-stderr-pattern: /.*/ +--- name: heredoc-5 description: Check that backslash quotes a $, ` and \ and kills a \newline @@ -2657,6 +2685,32 @@ stdin: expected-stdout: = these parens \( ) are a problem = --- +name: heredoc-comsub-5 +description: + Check heredoc and COMSUB mixture in input +stdin: + prefix() { sed -e "s/^/$1:/"; } + XXX() { echo x-en; } + YYY() { echo y-es; } + + prefix A <o1 2>o2 + rv=$? + echo RETVAL: $rv + sed -e "s^${__progname%.exe}\.*e*x*e*: PROG: " -e 's/^/STDOUT: /g' &1 | sed 1q); echo "=$foo="' + "$__progname" -xc 'foo=$(./bash --version 2>&1 | sed q); echo "=$foo="' expected-stdout: =GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)= expected-stderr-pattern: diff --git a/edit.c b/edit.c index a7f1b80..263f1c9 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.293 2016/01/21 18:24:37 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.294 2016/03/04 14:26:12 tg Exp $"); /* * in later versions we might use libtermcap for this, but since external @@ -4601,8 +4601,8 @@ vi_cmd(int argcnt, const char *cmd) static int domove(int argcnt, const char *cmd, int sub) { - int bcount, i = 0, t; - int ncursor = 0; + int ncursor = 0, i = 0, t; + unsigned int bcount; switch (*cmd) { case 'b': diff --git a/eval.c b/eval.c index edd3003..eeadff2 100644 --- a/eval.c +++ b/eval.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.182 2016/02/24 01:47:32 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.185 2016/02/26 19:05:21 tg Exp $"); /* * string expansion @@ -375,8 +375,9 @@ expand( unwind_substsyn: /* restore sp */ sp = varname - 2; - end = (beg = wdcopy(sp, ATEMP)) + - (wdscan(sp, CSUBST) - sp); + beg = wdcopy(sp, ATEMP); + end = (wdscan(cstrchr(sp, '\0') + 1, + CSUBST) - sp) + beg; /* ({) the } or x is already skipped */ if (end < wdscan(beg, EOS)) *end = EOS; @@ -403,8 +404,8 @@ expand( st->stype = stype; st->base = Xsavepos(ds, dp); st->f = f; - if (x.var == &vtemp) { - st->var = tempvar(); + if (x.var == vtemp) { + st->var = tempvar(vtemp->name); st->var->flag &= ~INTEGER; /* can't fail here */ setstr(st->var, @@ -1192,6 +1193,7 @@ varsub(Expand *xp, const char *sp, const char *word, /* can't trim a vector (yet) */ case '%': case '#': + case '?': case '0': case '/': case 0x100 | '#': diff --git a/exec.c b/exec.c index 6cf80e4..5b3fa6e 100644 --- a/exec.c +++ b/exec.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.171 2016/01/21 18:24:39 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.172 2016/03/01 18:30:04 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" @@ -1623,13 +1623,6 @@ herein(struct ioword *iop, char **resbuf) struct temp *h; int i; - /* ksh -c 'cat <heredoc == NULL && !(iop->ioflag & IOHERESTR)) { - warningf(true, Tmissinghere); - /* special to iosetup(): don't print error */ - return (-2); - } - /* lexer substitution flags */ i = (iop->ioflag & IOEVAL) ? (ONEWORD | HEREDOC) : 0; diff --git a/expr.c b/expr.c index d0e06ea..d4c2102 100644 --- a/expr.c +++ b/expr.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.81 2016/01/14 21:17:50 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.83 2016/03/01 18:29:38 tg Exp $"); /* the order of these enums is constrained by the order of opinfo[] */ enum token { @@ -227,7 +227,7 @@ v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok, exprtoken(es); if (es->tok == END) { es->tok = LIT; - es->val = tempvar(); + es->val = tempvar(""); } v = intvar(es, evalexpr(es, MAX_PREC)); @@ -649,7 +649,7 @@ exprtoken(Expr_state *es) cp += len; } if (es->noassign) { - es->val = tempvar(); + es->val = tempvar(""); es->val->flag |= EXPRLVALUE; } else { strndupx(tvar, es->tokp, cp - es->tokp, ATEMP); @@ -665,7 +665,10 @@ exprtoken(Expr_state *es) goto process_tvar; #ifndef MKSH_SMALL } else if (c == '\'') { - ++cp; + if (*++cp == '\0') { + es->tok = END; + evalerr(es, ET_UNEXPECTED, NULL); + } cp += utf_ptradj(cp); if (*cp++ != '\'') evalerr(es, ET_STR, @@ -684,7 +687,7 @@ exprtoken(Expr_state *es) c = *cp++; strndupx(tvar, es->tokp, --cp - es->tokp, ATEMP); process_tvar: - es->val = tempvar(); + es->val = tempvar(""); es->val->flag &= ~INTEGER; es->val->type = 0; es->val->val.s = tvar; @@ -719,17 +722,19 @@ assign_check(Expr_state *es, enum token op, struct tbl *vasn) } struct tbl * -tempvar(void) +tempvar(const char *vname) { struct tbl *vp; + size_t vsize; - vp = alloc(sizeof(struct tbl), ATEMP); + vsize = strlen(vname) + 1; + vp = alloc(offsetof(struct tbl, name[0]) + vsize, ATEMP); + memcpy(vp->name, vname, vsize); vp->flag = ISSET|INTEGER; vp->type = 0; vp->areap = ATEMP; vp->ua.hval = 0; vp->val.i = 0; - vp->name[0] = '\0'; return (vp); } @@ -744,7 +749,7 @@ intvar(Expr_state *es, struct tbl *vp) (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER)) return (vp); - vq = tempvar(); + vq = tempvar(""); if (setint_v(vq, vp, es->arith) == NULL) { if (vp->flag & EXPRINEVAL) evalerr(es, ET_RECURSIVE, vp->name); diff --git a/funcs.c b/funcs.c index a3edfe3..815a049 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.294 2016/01/21 18:24:39 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.295 2016/02/26 20:56:43 tg Exp $"); #if HAVE_KILLPG /* @@ -64,6 +64,8 @@ __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.294 2016/01/21 18:24:39 tg Exp $"); static int c_suspend(const char **); #endif +static int do_whence(const char **, int, bool, bool); + /* getn() that prints error */ static int bi_getn(const char *as, int *ai) @@ -514,14 +516,10 @@ s_put(int c MKSH_A_UNUSED) int c_whence(const char **wp) { - struct tbl *tp; - const char *id; - bool pflag = false, vflag = false, Vflag = false; - int rv = 0, optc, fcflags; - bool iam_whence = wp[0][0] == 'w'; - const char *opts = iam_whence ? "pv" : "pvV"; + int optc; + bool pflag = false, vflag = false; - while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) + while ((optc = ksh_getopt(wp, &builtin_opt, "pv")) != -1) switch (optc) { case 'p': pflag = true; @@ -529,79 +527,82 @@ c_whence(const char **wp) case 'v': vflag = true; break; + case '?': + return (1); + } + wp += builtin_opt.optind; + + return (do_whence(wp, pflag ? FC_PATH : + FC_BI | FC_FUNC | FC_PATH | FC_WHENCE, vflag, false)); +} + +/* note: command without -vV is dealt with in comexec() */ +int +c_command(const char **wp) +{ + int optc, fcflags = FC_BI | FC_FUNC | FC_PATH | FC_WHENCE; + bool vflag = false; + + /* options not sorted to facilitate string pooling */ + while ((optc = ksh_getopt(wp, &builtin_opt, "Vpv")) != -1) + switch (optc) { + case 'p': + fcflags |= FC_DEFPATH; + break; case 'V': - Vflag = true; + vflag = true; + break; + case 'v': + vflag = false; break; case '?': return (1); } wp += builtin_opt.optind; - fcflags = FC_BI | FC_PATH | FC_FUNC; - if (!iam_whence) { - /* Note that -p on its own is deal with in comexec() */ - if (pflag) - fcflags |= FC_DEFPATH; - /* - * Convert command options to whence options - note that - * command -pV uses a different path search than whence -v - * or whence -pv. This should be considered a feature. - */ - vflag = Vflag; - } - if (pflag) - fcflags &= ~(FC_BI | FC_FUNC); + return (do_whence(wp, fcflags, vflag, true)); +} + +static int +do_whence(const char **wp, int fcflags, bool vflag, bool iscommand) +{ + uint32_t h; + int rv = 0; + struct tbl *tp; + const char *id; while ((vflag || rv == 0) && (id = *wp++) != NULL) { - uint32_t h = 0; - + h = hash(id); tp = NULL; - if (!pflag) - tp = ktsearch(&keywords, id, h = hash(id)); - if (!tp && !pflag) { - tp = ktsearch(&aliases, id, h ? h : hash(id)); + + if (fcflags & FC_WHENCE) + tp = ktsearch(&keywords, id, h); + if (!tp && (fcflags & FC_WHENCE)) { + tp = ktsearch(&aliases, id, h); if (tp && !(tp->flag & ISSET)) tp = NULL; } if (!tp) tp = findcom(id, fcflags); - if (vflag || (tp->type != CALIAS && tp->type != CEXEC && - tp->type != CTALIAS)) + + switch (tp->type) { + case CSHELL: + case CFUNC: + case CKEYWD: shf_puts(id, shl_stdout); - if (vflag) { - switch (tp->type) { - case CKEYWD: - case CALIAS: - case CFUNC: - case CSHELL: - shf_puts(" is a", shl_stdout); - break; - } - switch (tp->type) { - case CKEYWD: - case CSHELL: - case CTALIAS: - case CEXEC: - shf_putc(' ', shl_stdout); - break; - } + break; } switch (tp->type) { - case CKEYWD: + case CSHELL: if (vflag) - shf_puts("reserved word", shl_stdout); - break; - case CALIAS: - if (vflag) - shprintf("n %salias for ", - (tp->flag & EXPORT) ? "exported " : null); - if (!iam_whence && !vflag) - shprintf("%s %s=", Talias, id); - print_value_quoted(shl_stdout, tp->val.s); + shprintf(" is a %sshell %s", + (tp->flag & SPEC_BI) ? "special " : "", + Tbuiltin); break; case CFUNC: if (vflag) { + shf_puts(" is a", shl_stdout); if (tp->flag & EXPORT) shf_puts("n exported", shl_stdout); if (tp->flag & TRACE) @@ -615,34 +616,42 @@ c_whence(const char **wp) shf_puts(T_function, shl_stdout); } break; - case CSHELL: - if (vflag) { - if (tp->flag & SPEC_BI) - shf_puts("special ", shl_stdout); - shprintf("%s %s", "shell", Tbuiltin); - } - break; - case CTALIAS: case CEXEC: + case CTALIAS: if (tp->flag & ISSET) { if (vflag) { - shf_puts("is ", shl_stdout); + shprintf("%s is ", id); if (tp->type == CTALIAS) shprintf("a tracked %s%s for ", (tp->flag & EXPORT) ? - "exported " : null, + "exported " : "", Talias); } shf_puts(tp->val.s, shl_stdout); } else { if (vflag) - shf_puts("not found", shl_stdout); + shprintf("%s not found", id); rv = 1; } break; - default: - shf_puts(" is *GOK*", shl_stdout); + case CALIAS: + if (vflag) { + shprintf("%s is an %s%s for ", id, + (tp->flag & EXPORT) ? "exported " : "", + Talias); + } else if (iscommand) + shprintf("%s %s=", Talias, id); + print_value_quoted(shl_stdout, tp->val.s); break; + case CKEYWD: + if (vflag) + shf_puts(" is a reserved word", shl_stdout); + break; +#ifndef MKSH_SMALL + default: + bi_errorf("%s is of unknown type %d", id, tp->type); + return (1); +#endif } if (vflag || !rv) shf_putc('\n', shl_stdout); @@ -650,17 +659,6 @@ c_whence(const char **wp) return (rv); } -/* Deal with command -vV - command -p dealt with in comexec() */ -int -c_command(const char **wp) -{ - /* - * Let c_whence do the work. Note that c_command() must be - * a distinct function from c_whence() (tested in comexec()). - */ - return (c_whence(wp)); -} - /* typeset, global, export, and readonly */ static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool); static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool, diff --git a/histrap.c b/histrap.c index 5932ea3..9dbb2c1 100644 --- a/histrap.c +++ b/histrap.c @@ -27,7 +27,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.154 2016/02/24 01:45:59 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.156 2016/03/04 14:26:13 tg Exp $"); Trap sigtraps[ksh_NSIG + 1]; static struct sigaction Sigact_ign; @@ -1017,23 +1017,26 @@ inittraps(void) { int i; const char *cs; +#if !HAVE_SYS_SIGNAME + const struct mksh_sigpair *pair; +#endif trap_exstat = -1; - /* Populate sigtraps based on sys_signame and sys_siglist. */ + /* populate sigtraps based on sys_signame and sys_siglist */ for (i = 1; i < ksh_NSIG; i++) { sigtraps[i].signal = i; #if HAVE_SYS_SIGNAME cs = sys_signame[i]; #else - const struct mksh_sigpair *pair = mksh_sigpairs; + pair = mksh_sigpairs; while ((pair->nr != i) && (pair->name != NULL)) ++pair; cs = pair->name; #endif if ((cs == NULL) || (cs[0] == '\0')) - sigtraps[i].name = shf_smprintf("%d", i); + sigtraps[i].name = null; else { char *s; @@ -1049,7 +1052,18 @@ inittraps(void) sigtraps[i].name = s; while ((*s = ksh_toupper(*s))) ++s; + /* check for reserved names */ + if (!strcmp(sigtraps[i].name, "EXIT") || + !strcmp(sigtraps[i].name, "ERR")) { +#ifndef MKSH_SMALL + internal_warningf("ignoring invalid signal name %s", + sigtraps[i].name); +#endif + sigtraps[i].name = null; + } } + if (sigtraps[i].name == null) + sigtraps[i].name = shf_smprintf("%d", i); #if HAVE_SYS_SIGLIST sigtraps[i].mess = sys_siglist[i]; #elif HAVE_STRSIGNAL diff --git a/jobs.c b/jobs.c index 38e7b39..86797d0 100644 --- a/jobs.c +++ b/jobs.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.119 2016/02/24 01:44:45 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.120 2016/03/04 14:26:13 tg Exp $"); #if HAVE_KILLPG #define mksh_killpg killpg @@ -1425,8 +1425,8 @@ check_job(Job *j) /* XXX debugging (nasty - interrupt routine using shl_out) */ if (!(j->flags & JF_STARTED)) { - internal_warningf("check_job: job started (flags 0x%x)", - j->flags); + internal_warningf("check_job: job started (flags 0x%X)", + (unsigned int)j->flags); return; } diff --git a/lalloc.c b/lalloc.c index a120760..0aff3aa 100644 --- a/lalloc.c +++ b/lalloc.c @@ -23,7 +23,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.25 2016/02/24 02:08:39 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.26 2016/02/26 21:53:36 tg Exp $"); /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */ #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0) @@ -36,7 +36,7 @@ __RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.25 2016/02/24 02:08:39 tg Exp $"); static struct lalloc_common *findptr(struct lalloc_common **, char *, Area *); #ifndef MKSH_ALLOC_CATCH_UNDERRUNS -#define ALLOC_ISUNALIGNED(p) (((size_t)(p)) % ALLOC_SIZE) +#define ALLOC_ISUNALIGNED(p) (((size_t)(p)) % sizeof(struct lalloc_common)) #else #define ALLOC_ISUNALIGNED(p) (((size_t)(p)) & 4095) #undef remalloc @@ -107,10 +107,10 @@ findptr(struct lalloc_common **lpp, char *ptr, Area *ap) #endif /* get address of ALLOC_ITEM from user item */ /* - * note: the alignment of "ptr" to ALLOC_SIZE is checked + * note: the alignment of "ptr" to ALLOC_ITEM is checked * above; the "void *" gets us rid of a gcc 2.95 warning */ - *lpp = (lp = ptr - ALLOC_SIZE); + *lpp = (lp = ptr - sizeof(ALLOC_ITEM)); /* search for allocation item in group list */ while (ap->next != lp) if ((ap = ap->next) == NULL) { @@ -126,7 +126,7 @@ findptr(struct lalloc_common **lpp, char *ptr, Area *ap) internal_errorf("rogue pointer %zX", (size_t)ptr); #endif } - return ((void *)ap); + return (ap); } void * @@ -150,18 +150,18 @@ aresize(void *ptr, size_t numb, Area *ap) pp->next = lp->next; } - if (notoktoadd(numb, ALLOC_SIZE) || - (lp = remalloc(lp, numb + ALLOC_SIZE)) == NULL + if (notoktoadd(numb, sizeof(ALLOC_ITEM)) || + (lp = remalloc(lp, numb + sizeof(ALLOC_ITEM))) == NULL #ifndef MKSH_SMALL || ALLOC_ISUNALIGNED(lp) #endif ) internal_errorf(Toomem, numb); - /* this only works because Area and ALLOC_ITEM share lalloc_common */ + /* area pointer and items share struct lalloc_common */ lp->next = ap->next; ap->next = lp; /* return user item address */ - return ((char *)lp + ALLOC_SIZE); + return ((char *)lp + sizeof(ALLOC_ITEM)); } void diff --git a/lex.c b/lex.c index 6b0b1bf..38eb119 100644 --- a/lex.c +++ b/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.219 2016/01/21 18:24:41 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.222 2016/03/01 19:22:31 tg Exp $"); /* * states while lexing word @@ -526,33 +526,13 @@ yylex(int cf) *wp++ = COMSUB; /* * We need to know whether we are within double - * quotes, since most shells translate \" to " - * within "…`…\"…`…". This is not done in POSIX - * mode (§2.2.3 Double-Quotes: “The backquote - * shall retain its special meaning introducing - * the other form of command substitution (see - * Command Substitution). The portion of the - * quoted string from the initial backquote and - * the characters up to the next backquote that - * is not preceded by a , having - * escape characters removed, defines that - * command whose output replaces "`...`" when - * the word is expanded.”; §2.6.3 Command - * Substitution: “Within the backquoted style - * of command substitution, shall - * retain its literal meaning, except when - * followed by: '$', '`', or . The - * search for the matching backquote shall be - * satisfied by the first unquoted non-escaped - * backquote; during this search, if a - * non-escaped backquote is encountered[…], - * undefined results occur.”). + * quotes in order to translate \" to " within + * "…`…\"…`…" because, unlike for COMSUBs, the + * outer double quoteing changes the backslash + * meaning for the inside. For more details: + * http://austingroupbugs.net/view.php?id=1015 */ statep->ls_bool = false; -#ifdef austingroupbugs1015_is_still_not_resolved - if (Flag(FPOSIX)) - break; -#endif s2 = statep; base = state_info.base; while (/* CONSTCOND */ 1) { @@ -1000,6 +980,16 @@ yylex(int cf) if (cf & CONTIN) goto Again; } + } else if (c == '\0' && !(cf & HEREDELIM)) { + struct ioword **p = heres; + + while (p < herep) + if ((*p)->ioflag & IOHERESTR) + ++p; + else + /* ksh -c 'cat <delim, 0)); } return (c); } @@ -1173,7 +1163,7 @@ readhere(struct ioword *iop) while (c != '\n') { if (!c) /* oops, reached EOF */ - yyerror("%s '%s' unclosed\n", Theredoc, eof); + yyerror("here document '%s' unclosed\n", eof); /* store character */ Xcheck(xs, xp); Xput(xs, xp, c); @@ -1359,8 +1349,10 @@ getsc_line(Source *s) ksh_tmout_state = TMOUT_READING; alarm(ksh_tmout); } - if (interactive) + if (interactive) { + histsave(&s->line, NULL, HIST_FLUSH, true); change_winsz(); + } #ifndef MKSH_NO_CMDLINE_EDITING if (have_tty && ( #if !MKSH_S_NOVI diff --git a/main.c b/main.c index 2cdb1d5..fa5bb2e 100644 --- a/main.c +++ b/main.c @@ -34,7 +34,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.308 2016/02/24 01:44:46 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.310 2016/02/26 21:53:36 tg Exp $"); extern char **environ; @@ -110,13 +110,13 @@ rndsetup(void) } *bufptr; char *cp; - cp = alloc(sizeof(*bufptr) - ALLOC_SIZE, APERM); + cp = alloc(sizeof(*bufptr) - sizeof(ALLOC_ITEM), APERM); #ifdef DEBUG /* clear the allocated space, for valgrind */ - memset(cp, 0, sizeof(*bufptr) - ALLOC_SIZE); + memset(cp, 0, sizeof(*bufptr) - sizeof(ALLOC_ITEM)); #endif /* undo what alloc() did to the malloc result address */ - bufptr = (void *)(cp - ALLOC_SIZE); + bufptr = (void *)(cp - sizeof(ALLOC_ITEM)); /* PIE or something similar provides us with deltas here */ bufptr->dataptr = &rndsetupstate; /* ASLR in at least Windows, Linux, some BSDs */ @@ -208,6 +208,8 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) /* initialise permanent Area */ ainit(&aperm); + /* max. name length: -2147483648 = 11 (+ NUL) */ + vtemp = alloc(offsetof(struct tbl, name[0]) + 12, APERM); /* set up base environment */ env.type = E_NONE; @@ -933,9 +935,9 @@ newenv(int type) * struct env includes ALLOC_ITEM for alignment constraints * so first get the actually used memory, then assign it */ - cp = alloc(sizeof(struct env) - ALLOC_SIZE, ATEMP); + cp = alloc(sizeof(struct env) - sizeof(ALLOC_ITEM), ATEMP); /* undo what alloc() did to the malloc result address */ - ep = (void *)(cp - ALLOC_SIZE); + ep = (void *)(cp - sizeof(ALLOC_ITEM)); /* initialise public members of struct env (not the ALLOC_ITEM) */ ainit(&ep->area); ep->oenv = e; @@ -1031,7 +1033,7 @@ quitenv(struct shf *shf) /* free the struct env - tricky due to the ALLOC_ITEM inside */ cp = (void *)ep; - afree(cp + ALLOC_SIZE, ATEMP); + afree(cp + sizeof(ALLOC_ITEM), ATEMP); } /* Called after a fork to cleanup stuff left over from parents environment */ diff --git a/misc.c b/misc.c index 908fad5..6e08da2 100644 --- a/misc.c +++ b/misc.c @@ -30,7 +30,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.241 2016/01/21 18:24:43 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.242 2016/03/04 14:26:13 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -1291,7 +1291,7 @@ print_columns(struct shf *shf, unsigned int n, shf_puts(str, shf); else shf_fprintf(shf, "%*s%*s", - max_col, str, nspace, null); + (int)max_col, str, (int)nspace, null); } shf_putchar('\n', shf); } diff --git a/mksh.1 b/mksh.1 index c6f9736..e8b26f9 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.389 2016/02/11 19:00:50 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.392 2016/03/04 18:28:41 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, @@ -76,7 +76,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" use our own definition. And .Dd must come *first*, always. .\" -.Dd $Mdocdate: February 11 2016 $ +.Dd $Mdocdate: March 4 2016 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -1004,13 +1004,14 @@ quotes all characters, except .Ql \` and .Ql \e , -up to the next unquoted double quote. +up to the next unescaped double quote. .Ql $ and .Ql \` inside double quotes have their usual meaning (i.e. parameter, arithmetic, or command substitution) except no field splitting is carried out on the -results of double-quoted substitutions. +results of double-quoted substitutions, and the old-style form of command +substitution has backslash-quoting for double quotes enabled. If a .Ql \e inside a double-quoted string is followed by @@ -1307,13 +1308,13 @@ form, a followed by any of .Ql $ , .Ql \` , -.Ql \&" -.Pq currently, and violating Tn POSIX , or .Ql \e -is stripped (a +is stripped (as is +.Ql \&" +when the substitution is part of a double-quoted string); a backslash .Ql \e -followed by any other character is unchanged). +followed by any other character is unchanged. As a special case in command substitutions, a command of the form .Pf \*(Lt Ar file is interpreted to mean substitute the contents of @@ -4312,6 +4313,11 @@ options (with single letter names) can be found in the parameter 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. .Pp Remaining arguments, if any, are positional parameters and are assigned, in order, to the positional parameters (i.e. $1, $2, etc.). @@ -5141,38 +5147,20 @@ If job monitoring is enabled, the completion status of jobs is printed .Op Fl pv .Op Ar name ... .Xc -For each -.Ar name , -the type of command is listed (reserved word, built-in, alias, -function, tracked alias, or executable). -If the -.Fl p -option is used, a path search is performed even if -.Ar name -is a reserved word, alias, etc. Without the .Fl v -option, -.Ic whence -is similar to -.Ic command Fl v -except that -.Ic whence -will find reserved words and won't print aliases as alias commands. +option, it is the same as +.Ic command Fl v , +except aliases are not printed as alias command. With the .Fl v -option, -.Ic whence -is the same as +option, it is exactly the same as .Ic command Fl V . -Note that for -.Ic whence , -the +In either case, the .Fl p -option does not affect the search path used, as it does for -.Ic command . -If the type of one or more of the names could not be determined, the exit -status is non-zero. +option differs: the search path is not affected in +.Ic whence , +but the search is restricted to the path. .El .Ss Job control Job control refers to the shell's ability to monitor and control jobs which @@ -6596,20 +6584,8 @@ when multiple shells are accessing the file; the rollover process for the in-memory portion of the history is slow, should use .Xr memmove 3 . .Pp -Handling of backslash plus double-quote inside the (deprecated) -.Pf \` Ns Ar command Ns \` -form of command substitution when the substitution itself is -also inside double quotes currently deliberately violates -.Tn POSIX -even in -.Fl o Ic posix -mode until Austin group bug 1015 has been resolved either way, -as the current wording of the standard prohibits the current -and historic practice of several shells which several scripts -(admittedly wrongly) depend on. -.Pp This document attempts to describe -.Nm mksh\ R52b +.Nm mksh\ R52c and up, .\" with vendor patches from insert-your-name-here, compiled without any options impacting functionality, such as diff --git a/sh.h b/sh.h index 7ea718b..8d85994 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.762 2016/02/24 02:08:39 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.768 2016/03/04 18:28:42 tg Exp $"); #endif -#define MKSH_VERSION "R52 2016/02/23" +#define MKSH_VERSION "R52 2016/03/04" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -578,7 +578,7 @@ char *ucstrstr(char *, const char *); #define mkssert(e) do { } while (/* CONSTCOND */ 0) #endif -#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 522) +#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 523) #error Must run Build.sh to compile this. extern void thiswillneverbedefinedIhope(void); int @@ -703,21 +703,21 @@ struct lalloc_common { struct lalloc_common *next; }; +#ifdef MKSH_ALLOC_CATCH_UNDERRUNS struct lalloc_item { struct lalloc_common *next; -#ifdef MKSH_ALLOC_CATCH_UNDERRUNS size_t len; char dummy[8192 - sizeof(struct lalloc_common *) - sizeof(size_t)]; -#endif }; +#endif /* 2. sizes */ +#ifdef MKSH_ALLOC_CATCH_UNDERRUNS #define ALLOC_ITEM struct lalloc_item -#define ALLOC_SIZE (sizeof(ALLOC_ITEM)) -#ifndef MKSH_ALLOC_CATCH_UNDERRUNS -#define ALLOC_OVERHEAD ALLOC_SIZE -#else #define ALLOC_OVERHEAD 0 +#else +#define ALLOC_ITEM struct lalloc_common +#define ALLOC_OVERHEAD (sizeof(ALLOC_ITEM)) #endif /* 3. group structure */ @@ -850,11 +850,13 @@ EXTERN struct { /* null value for variable; comparison pointer for unset */ EXTERN char null[] E_INIT(""); /* helpers for string pooling */ -EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented"); -EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes"); #if defined(__GNUC__) #define Tsynerr "syntax error" +#define Tintovfl "integer overflow %zu %c %zu prevented" +#define Toomem "can't allocate %zu data bytes" #else +EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented"); +EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes"); EXTERN const char Tsynerr[] E_INIT("syntax error"); #endif EXTERN const char Tselect[] E_INIT("select"); @@ -887,12 +889,6 @@ EXTERN const char T_funny_command[] E_INIT("funny $() command"); EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution"); #endif #define Tbadsubst (Tfg_badsubst + 10) /* "bad substitution" */ -#if defined(__GNUC__) -#define Tmissinghere "missing here document" -#else -EXTERN const char Tmissinghere[] E_INIT("missing here document"); -#endif -#define Theredoc (Tmissinghere + 8) /* "here document" */ EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n"); #define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */ @@ -1216,7 +1212,7 @@ struct tbl { char name[4]; }; -EXTERN struct tbl vtemp; +EXTERN struct tbl *vtemp; /* set by global() and local() */ EXTERN bool last_lookup_was_array; @@ -1285,7 +1281,7 @@ enum namerefflag { #define FC_BI (FC_SPECBI | FC_NORMBI) #define FC_PATH BIT(3) /* do path search */ #define FC_DEFPATH BIT(4) /* use default path in path search */ - +#define FC_WHENCE BIT(5) /* for use by command and whence */ #define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */ #define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */ @@ -1768,7 +1764,7 @@ size_t utf_ptradj(const char *) MKSH_A_PURE; int utf_wcwidth(unsigned int) MKSH_A_PURE; #endif int ksh_access(const char *, int); -struct tbl *tempvar(void); +struct tbl *tempvar(const char *); /* funcs.c */ int c_hash(const char **); int c_pwd(const char **); @@ -2025,7 +2021,7 @@ char *shf_smprintf(const char *, ...) ssize_t shf_vfprintf(struct shf *, const char *, va_list) MKSH_A_FORMAT(__printf__, 2, 0); /* syn.c */ -int assign_command(const char *, bool); +int assign_command(const char *, bool) MKSH_A_PURE; void initkeywords(void); struct op *compile(Source *, bool); bool parse_usec(const char *, struct timeval *); diff --git a/shf.c b/shf.c index 3b63c7b..ecf9ba7 100644 --- a/shf.c +++ b/shf.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, - * 2012, 2013, 2015 + * 2012, 2013, 2015, 2016 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -25,7 +25,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.69 2015/12/31 20:38:59 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.70 2016/03/04 14:26:16 tg Exp $"); /* flags to shf_emptybuf() */ #define EB_READSW 0x01 /* about to switch to reading */ @@ -197,7 +197,8 @@ shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf) { /* can't have a read+write string */ if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR))) - internal_errorf("%s: flags 0x%X", "shf_sopen", sflags); + internal_errorf("%s: flags 0x%X", "shf_sopen", + (unsigned int)sflags); if (!shf) { shf = alloc(sizeof(struct shf), ATEMP); @@ -452,7 +453,8 @@ shf_read(char *buf, ssize_t bsize, struct shf *shf) ssize_t ncopy, orig_bsize = bsize; if (!(shf->flags & SHF_RD)) - internal_errorf("%s: flags 0x%X", "shf_read", shf->flags); + internal_errorf("%s: flags 0x%X", "shf_read", + (unsigned int)shf->flags); if (bsize <= 0) internal_errorf("%s: %s %zd", "shf_write", "bsize", bsize); @@ -489,7 +491,8 @@ shf_getse(char *buf, ssize_t bsize, struct shf *shf) char *orig_buf = buf; if (!(shf->flags & SHF_RD)) - internal_errorf("%s: flags 0x%X", "shf_getse", shf->flags); + internal_errorf("%s: flags 0x%X", "shf_getse", + (unsigned int)shf->flags); if (bsize <= 0) return (NULL); @@ -525,7 +528,8 @@ int shf_getchar(struct shf *shf) { if (!(shf->flags & SHF_RD)) - internal_errorf("%s: flags 0x%X", "shf_getchar", shf->flags); + internal_errorf("%s: flags 0x%X", "shf_getchar", + (unsigned int)shf->flags); if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0)) return (-1); @@ -541,7 +545,8 @@ int shf_ungetc(int c, struct shf *shf) { if (!(shf->flags & SHF_RD)) - internal_errorf("%s: flags 0x%X", "shf_ungetc", shf->flags); + internal_errorf("%s: flags 0x%X", "shf_ungetc", + (unsigned int)shf->flags); if ((shf->flags & SHF_ERROR) || c == -1 || (shf->rp == shf->buf && shf->rnleft)) @@ -578,7 +583,8 @@ int shf_putchar(int c, struct shf *shf) { if (!(shf->flags & SHF_WR)) - internal_errorf("%s: flags 0x%X", "shf_putchar", shf->flags); + internal_errorf("%s: flags 0x%X", "shf_putchar", + (unsigned int)shf->flags); if (c == -1) return (-1); @@ -633,7 +639,8 @@ shf_write(const char *buf, ssize_t nbytes, struct shf *shf) ssize_t n, ncopy, orig_nbytes = nbytes; if (!(shf->flags & SHF_WR)) - internal_errorf("%s: flags 0x%X", "shf_write", shf->flags); + internal_errorf("%s: flags 0x%X", "shf_write", + (unsigned int)shf->flags); if (nbytes < 0) internal_errorf("%s: %s %zd", "shf_write", "nbytes", nbytes); @@ -764,7 +771,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) const char *s; char c, *cp; int tmp = 0, flags; - ssize_t field, precision, len; + size_t field, precision, len; unsigned long lnum; /* %#o produces the longest output */ char numbuf[(8 * sizeof(long) + 2) / 3 + 1]; @@ -791,7 +798,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) */ flags = 0; field = precision = 0; - for ( ; (c = *fmt++) ; ) { + while ((c = *fmt++)) { switch (c) { case '#': flags |= FL_HASH; @@ -821,12 +828,17 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) case '*': tmp = VA(int); - if (flags & FL_DOT) - precision = tmp; - else if ((field = tmp) < 0) { - field = -field; - flags |= FL_RIGHT; - } + if (tmp < 0) { + if (flags & FL_DOT) + precision = 0; + else { + field = (unsigned int)-tmp; + flags |= FL_RIGHT; + } + } else if (flags & FL_DOT) + precision = (unsigned int)tmp; + else + field = (unsigned int)tmp; continue; case 'l': @@ -848,26 +860,23 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) bool overflowed = false; tmp = ksh_numdig(c); - while (c = *fmt++, ksh_isdigit(c)) { + while (c = *fmt++, ksh_isdigit(c)) if (notok2mul(2147483647, tmp, 10)) overflowed = true; - tmp = tmp * 10 + ksh_numdig(c); - } + else + tmp = tmp * 10 + ksh_numdig(c); --fmt; if (overflowed) tmp = 0; if (flags & FL_DOT) - precision = tmp; + precision = (unsigned int)tmp; else - field = tmp; + field = (unsigned int)tmp; continue; } break; } - if (precision < 0) - precision = 0; - if (!c) /* nasty format */ break; @@ -953,7 +962,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) *--cp = (flags & FL_UPPER) ? 'X' : 'x'; *--cp = '0'; } - } + } } len = numbuf + sizeof(numbuf) - (s = cp); if (flags & FL_DOT) { @@ -999,7 +1008,6 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) if (field > precision) { field -= precision; if (!(flags & FL_RIGHT)) { - field = -field; /* skip past sign or 0x when padding with 0 */ if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { if (*s == '+' || *s == '-' || @@ -1012,7 +1020,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) shf_putc(*s, shf); s++; nwritten++; - if (--precision > 0 && + if (--precision && ksh_eq(*s, 'X', 'x')) { shf_putc(*s, shf); s++; @@ -1023,19 +1031,16 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) c = '0'; } else c = flags & FL_ZERO ? '0' : ' '; - if (field < 0) { - nwritten += -field; - while (field < 0) { - shf_putc(c, shf); - ++field; - } - } + nwritten += field; + while (field--) + shf_putc(c, shf); + field = 0; } else c = ' '; } else field = 0; - if (precision > 0) { + if (precision) { const char *q; nwritten += precision; @@ -1044,11 +1049,9 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) shf_putc(*s, shf); } while (++s < q); } - if (field > 0) { - nwritten += field; - for ( ; field > 0 ; --field) - shf_putc(c, shf); - } + nwritten += field; + while (field--) + shf_putc(c, shf); } return (shf_error(shf) ? -1 : nwritten); diff --git a/syn.c b/syn.c index 210f7c0..d645e0f 100644 --- a/syn.c +++ b/syn.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.110 2016/01/21 18:24:44 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.111 2016/02/26 21:24:58 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -31,6 +31,7 @@ struct nesting_state { }; struct yyrecursive_state { + struct ioword *old_heres[HERES]; struct yyrecursive_state *next; struct ioword **old_herep; int old_symbol; @@ -1175,7 +1176,9 @@ yyrecursive(int subtype MKSH_A_UNUSED) ys->old_reject = reject; ys->old_symbol = symbol; ACCEPT; + memcpy(ys->old_heres, heres, sizeof(heres)); ys->old_herep = herep; + herep = heres; ys->old_salias = sALIAS; sALIAS = 0; ys->next = e->yyrecursive_statep; @@ -1202,6 +1205,7 @@ yyrecursive_pop(bool popall) e->yyrecursive_statep = ys->next; sALIAS = ys->old_salias; + memcpy(heres, ys->old_heres, sizeof(heres)); herep = ys->old_herep; reject = ys->old_reject; symbol = ys->old_symbol; diff --git a/tree.c b/tree.c index 94e8ce1..5dbebd0 100644 --- a/tree.c +++ b/tree.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.81 2016/01/21 18:24:45 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.83 2016/03/04 14:26:16 tg Exp $"); #define INDENT 8 @@ -631,8 +631,8 @@ wdscan(const char *wp, int c) break; default: internal_warningf( - "wdscan: unknown char 0x%x (carrying on)", - wp[-1]); + "wdscan: unknown char 0x%X (carrying on)", + (unsigned char)wp[-1]); } } @@ -817,7 +817,7 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel) return (--wp); case ADELIM: if (*wp == /*{*/'}') { - shf_puts("]ADELIM(})", shf); + shf_puts(/*{*/ "]ADELIM(})", shf); return (wp + 1); } shf_puts("ADELIM=", shf); @@ -852,10 +852,10 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel) shf_puts("EXPRSUB<", shf); goto dumpsub; case OQUOTE: - shf_fprintf(shf, "OQUOTE{%d", ++quotelevel); + shf_fprintf(shf, "OQUOTE{%d" /*}*/, ++quotelevel); break; case CQUOTE: - shf_fprintf(shf, "%d}CQUOTE", quotelevel); + shf_fprintf(shf, /*{*/ "%d}CQUOTE", quotelevel); if (quotelevel) quotelevel--; else diff --git a/var.c b/var.c index ba852dd..c4bd39d 100644 --- a/var.c +++ b/var.c @@ -28,7 +28,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.198 2016/01/21 18:24:45 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.201 2016/03/01 20:28:33 tg Exp $"); /*- * Variables @@ -242,18 +242,26 @@ global(const char *n) if (!ksh_isalphx(c)) { if (array) errorf(Tbadsubst); - vp = &vtemp; + vp = vtemp; vp->flag = DEFINED; vp->type = 0; vp->areap = ATEMP; - *vp->name = c; if (ksh_isdigit(c)) { - if (getn(vn, &c) && (c <= l->argc)) - /* setstr can't fail here */ - setstr(vp, l->argv[c], KSH_RETURN_ERROR); + if (getn(vn, &c)) { + /* main.c:main_init() says 12 */ + shf_snprintf(vp->name, 12, "%d", c); + if (c <= l->argc) { + /* setstr can't fail here */ + setstr(vp, l->argv[c], + KSH_RETURN_ERROR); + } + } else + vp->name[0] = '\0'; vp->flag |= RDONLY; goto out; } + vp->name[0] = c; + vp->name[1] = '\0'; vp->flag |= RDONLY; if (vn[1] != '\0') goto out; @@ -320,7 +328,7 @@ local(const char *n, bool copy) vn = array_index_calc(n, &array, &val); h = hash(vn); if (!ksh_isalphx(*vn)) { - vp = &vtemp; + vp = vtemp; vp->flag = DEFINED|RDONLY; vp->type = 0; vp->areap = ATEMP; @@ -479,13 +487,12 @@ void setint(struct tbl *vq, mksh_ari_t n) { if (!(vq->flag&INTEGER)) { - struct tbl *vp = &vtemp; - vp->flag = (ISSET|INTEGER); - vp->type = 0; - vp->areap = ATEMP; - vp->val.i = n; + vtemp->flag = (ISSET|INTEGER); + vtemp->type = 0; + vtemp->areap = ATEMP; + vtemp->val.i = n; /* setstr can't fail here */ - setstr(vq, str_val(vp), KSH_RETURN_ERROR); + setstr(vq, str_val(vtemp), KSH_RETURN_ERROR); } else vq->val.i = n; vq->flag |= ISSET; @@ -827,12 +834,13 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) /* check target value for being a valid variable name */ ccp = skip_varname(qval, false); if (ccp == qval) { - if (ksh_isdigit(qval[0])) { - int c; + int c; - if (getn(qval, &c)) - goto nameref_rhs_checked; - } else if (qval[1] == '\0') switch (qval[0]) { + if (!(c = (unsigned char)qval[0])) + goto nameref_empty; + else if (ksh_isdigit(c) && getn(qval, &c)) + goto nameref_rhs_checked; + else if (qval[1] == '\0') switch (c) { case '$': case '!': case '?':