diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 1999-06-15 01:18:37 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 1999-06-15 01:18:37 +0000 |
commit | b6f2d26d5b213fdd95fe8f3a8aaa9c02e181070c (patch) | |
tree | 3940e971a5fd11eb5754339ba24122db7dcdece3 /bin/ksh | |
parent | ed796a820653ef1e6c63e0bae7a6f19bbff18fbb (diff) |
patches from pdksh 5.2.13.11
Diffstat (limited to 'bin/ksh')
38 files changed, 781 insertions, 373 deletions
diff --git a/bin/ksh/BUG-REPORTS b/bin/ksh/BUG-REPORTS index ae9a59829ef..0c935b4bc58 100644 --- a/bin/ksh/BUG-REPORTS +++ b/bin/ksh/BUG-REPORTS @@ -1,4 +1,4 @@ -$OpenBSD: BUG-REPORTS,v 1.10 1999/01/19 20:41:50 millert Exp $ +$OpenBSD: BUG-REPORTS,v 1.11 1999/06/15 01:18:32 millert Exp $ List of reported problems (problems reported and fixed before 5.0.4 not included). Unresolved problems (may or may not still exist) marked by *, @@ -87,8 +87,6 @@ problems believed to be fixed marked by x. detected (if the shell exits before reading the whole file). [see Mail.XXX] -* pdksh 5.2.12, - : MAILCHECK isn't preserved from the envirnment on startup. - * pdksh 5.2.12, (reported by Michael Staats): emacs: file completion does not complete as much as possible when file is ~/something (will list possible completions but won't fill in to the first difference). @@ -1341,3 +1339,19 @@ x pdksh 5.2.13.5, (reported with fix by Martin Lucina <mato@kotelna.sk>): x pdksh 5.2.13.5, (reported by Charles M. Hannum <root@ihack.net>): An exit trap set in a subshell is not executed (unless explicit exit used). [fixed in 5.2.14: exec.c(execute): changed exit(rv) to unwind(LEXIT).] + +x pdksh 5.2.12, - : MAILCHECK isn't preserved from the envirnment on startup. + [fixed in 5.2.14: changed main's initcoms[].] + +x pdksh 5.2.13, (reported by Marc Olzheim): time at the end of a pipeline + doesn't print anything. + [fixed in 5.2.14: exec.c(execute): clear XEXEC when calling timex().] + +x pdksh 5.2.13, (reported by David J. McMahon): here documents in subshells + don't work if the parent exits before the subshell. + [fixed in 5.2.14: heredocs now saved in memory, written to temp when needed.] + +x pdksh 5.2.13, (reported by Seiichi Namba): emacs: keys bound in .profile/$ENV + are overridden by stty settings (eg, binding ^U in .profile has no effect). + [fixed in 5.2.14: emacs.c: added x_bound array to track what user has set.] + diff --git a/bin/ksh/CONTRIBUTORS b/bin/ksh/CONTRIBUTORS index b1fc67c8065..230d3bff7bc 100644 --- a/bin/ksh/CONTRIBUTORS +++ b/bin/ksh/CONTRIBUTORS @@ -1,4 +1,4 @@ -$OpenBSD: CONTRIBUTORS,v 1.7 1999/01/10 17:55:01 millert Exp $ +$OpenBSD: CONTRIBUTORS,v 1.8 1999/06/15 01:18:32 millert Exp $ This is a partial history of this shell gleened from old change logs and readmes (most of which are still in the misc directory) and the source @@ -93,8 +93,8 @@ Other contributors: * Stefan Dalibor (<Stefan.Dalibor@informatik.uni-erlangen.de>): fix for COLUMNS never being set in x_init(). * Arnon Kanfi (<arnon@gilly.datatools.com>): fix for prompt. - * Marc Olzheim (<marcolz@stack.urc.tue.nl>): patches to ifdef KSH the - mail check code and aliases. + * Marc Olzheim (<marcolz@stack.nl>): patches to ifdef KSH the mail check + code and aliases; enum patches for old K&R compilers; handle missing dup2. * Lars Hecking (<lhecking@nmrc.ucc.ie>): fixes so shell compiles as sh again. * Bill Kish (<kish@browncow.com>): added prompt delimiter hack for @@ -122,3 +122,6 @@ Other contributors: completion. * Martin Lucina <mato@kotelna.sk>: fix for argument parsing in exit command, fix for KSH_CHECK_H_TYPE. + * Mark Funkenhauser <mark@interix.com>: added $LINENO support. + * Corinna Vinschen <Corinna@Vinschen.de> and Steven Hein <ssh@sgi.com>: + port to cyngin environment on win95/winnt. diff --git a/bin/ksh/ChangeLog b/bin/ksh/ChangeLog index fd076daf232..2d4dd58f206 100644 --- a/bin/ksh/ChangeLog +++ b/bin/ksh/ChangeLog @@ -1,3 +1,156 @@ +Thu May 13 17:23:17 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * emacs.c(x_bound,bind_if_not_bound): new variable/fucntion. + * emacs.c(x_bind): set bit in x_bound[]. + * emacs.c(x_emacs_keys): call bind_if_not_bound. + +Thu May 13 14:23:12 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * sh.h: ifdefs for __CYGWIN__ for path defines. + * path.c(simplify_path): ifdefs for __CYGWIN__; preserve leading + double-slash on pathnames. + * c_ksh.c(c_cd): use cygwin_conv_to_full_posix_path(). + * edit.c(x_mode): default eof char to ^D. + + [fixes from Corinna Vinschen and Steven Hein, obtained from + ftp://ftp.franken.de/pub/win32/develop/gnuwin32/cygwin/ + porters/Vinschen_Corinna/B20/] + +Wed May 12 12:30:09 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * exit.c(x_mode): set fields of edchars to -1 if corrisponding char + is unset. + * exit.c(x_init): initialize edchars to -2, not -1. + * emacs.c(x_emacs_keys): check if char is >= 0 before setting. + +Wed May 12 11:31:24 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * shf.c(shf_write): don't buffer if buffer is empty and we're + writting a large amount. + * shf.c(shf_open): changed to use shf_reopen instead of shf_fdopen + so alloca failing won't lose the fd. + +Wed May 12 10:19:43 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * sh.h: deleted TT_HEREDOC_RAW define. + * tree.h(struct ioword): added heredoc field. + * tree.c(iocopy,iofree): copy/free heredoc field; remove special case + for IOHERE and name field. + * tree.c(ptree): changed to use heredoc content string (not open temp). + * lex.c(yylex): initialize heredoc field. + * lex.c(readhere): save to string instead of a temp file. + * exec.c(herein): changed first are from file name to heredoc content + string; changed all calls. Changed to always create a new temp file + and write content to it. + +Tue May 11 11:38:22 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * tree.c(iofree): free delim field; don't free name of IOHERE iowords. + +Tue May 11 10:57:53 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * sh.h(func_heredocs): deleted. + * sh.h(EF_FAKE_SIGDIE): added. + * lex.c(readhere): put function heredocs at bottom of env stack. + * main.c(quitenv,cleanup_proc_env): deleted remove_temps(func_heredocs) + calls. + + * main.c(quitenv): moved exit of no oenv to en after reclaim. + * main.c(cleanup_parents_env): free ep->savefd and set to 0. + * main.c(unwind,quitenv): moved code for E_NONE from unwind() + to quitenv(). + +Mon May 10 17:04:03 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * exec.c(herein): restore source to osource after yylex(). + +Mon May 10 12:14:40 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * tree.c(iocopy): don't copy IOHERE name (it belongs to a struct temp). + * tree.c(wdscan): added default case to print internal error. + +Mon May 10 10:39:34 NDT 1999 Michael Rendell (michael@deimos.cs.mun.ca) + + * sh.h(Temp_type): new enum (TT_HEREDOC_RAW, TT_HEREDOC_EXP, + TT_HIST_FILE). + * sh.h(struct temp): added type field. + * io.c(maketemp): added type and tlist arguments; changed + all calls. + +Tue Apr 27 11:31:48 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * exec.c(execute): clear XEXEC in the call to timex() so time + can be used at the end of a pipeline. + +Fri Apr 23 16:29:01 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * mail.c(mcheck): don't check if MAILCHECK is set, just check if + mplist is null. + * mail.c(mcset): new function. + * var.c(setspec): case MAILCHECK: call mcset. + * var.c(unspecial): new function. + * var.c(unsetspec): call unspecial for LINENO, MAILCHECK, RANDOM, + SECONDS, TMOUT. + +Fri Apr 23 15:34:39 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * main.c(initcoms): put MAILCHECK, SECONDS, TMOUT in an eval to + preserve previous values. + * var.c(getspec): case V_SECONDS: don't do anything special if + variable not set. + +Thu Apr 22 15:03:27 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * var.c(setstr): error if var is RDONLY. + * var.c(global): non-letter params: set RDONLY flag after setstr call. + * c_ksh.c(c_getopts), eval.c(expand), exec.c(execute): + removed readonly check. + + * sh.h(KSH_UNWIND_ERROR, KSH_RETURN_ERROR): new defines. + * var.c(setstr): added error_ok argument; changed all calls. + * c_ksh.c(c_getopts): clear READONLY and INTEGER flags for OPTARG; + return non-zero if variable can't be set. + * var.c(typeset): if fake_assign fails, unset the variable's value + and carry on for rest of array, then unwind. + * expr.c(expand,v_expand): changed all calls to use KSH_UNWIND_ERROR + or KSH_RETURN_ERROR. + +Tue Apr 20 16:52:24 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * configure.in: added check dup2. + * sh.h: added dup2 prototype. + * aclocal.m4: replace AC_HEADER_DIRENT so it checks -lndir. + + * missing.c(dup2): new function. + Based on code from Marc Olzheim. + +Fri Apr 16 16:32:27 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * syn.c(lineno_offset): removed variable and all references. + * tree.c(tcopy): copy lineno field. + * var.c(user_lineno): new variable. + * var.c(setspec): added case for V_LINENO (sets user_lineno). + * var.c(getspec): V_LINENO: add in user_lineno. + +Fri Apr 16 15:26:26 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * tree.h(struct op): added lineno field. + * table.h(V_LINENO, current_lineno): new define/variable. + * exec.c(execute): set current_lineno for TCOM. + * syn.c(lineno_offset): new variable. + * syn.c(get_command): set t->lineno. + * syn.c(function_body): save/restore lineno_offset; + * syn.c(compile): initialize lineno_offset + * var.c(initvar,getspec): added V_LINENO entry. + + Changes from Mark Funkenhauser. + +Fri Apr 16 12:18:08 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca) + + * expr.c,misc.c(getoptions): added int casts to avoid errors from + old K&R compilers. + Fixes from Marc Olzheim. + Fri Jan 15 12:51:53 NST 1999 Michael Rendell (michael@panda.cs.mun.ca) * expr.c: pass es as first param to all functions; deleted @@ -333,7 +486,7 @@ Wed Oct 30 11:23:17 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) * exec.c(comexec): case CFUNC: set $0 to kshname if non-function function. -$OpenBSD: ChangeLog,v 1.10 1999/01/19 20:41:51 millert Exp $ +$OpenBSD: ChangeLog,v 1.11 1999/06/15 01:18:32 millert Exp $ Tue Oct 29 11:34:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca) diff --git a/bin/ksh/Makefile b/bin/ksh/Makefile index 76970d8cbd6..c5c1b33dc74 100644 --- a/bin/ksh/Makefile +++ b/bin/ksh/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.10 1999/01/10 17:55:01 millert Exp $ +# $OpenBSD: Makefile,v 1.11 1999/06/15 01:18:32 millert Exp $ PROG= ksh SRCS= alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c \ @@ -27,4 +27,7 @@ siglist.out: config.h sh.h siglist.in siglist.sh emacs.out: emacs.c /bin/sh ${.CURDIR}/emacs-gen.sh ${.CURDIR}/emacs.c > emacs.out +check test: + /bin/sh ${.CURDIR}/tests/th.sh ${.CURDIR}/tests/th -s ${.CURDIR}/tests -p ./ksh -C pdksh,sh,ksh,posix,posix-upu + .include <bsd.prog.mk> diff --git a/bin/ksh/NEWS b/bin/ksh/NEWS index 735463a57b5..9322173dded 100644 --- a/bin/ksh/NEWS +++ b/bin/ksh/NEWS @@ -1,6 +1,11 @@ Version 5.2.14pre * bug fixes + * emacs: bind commands in .profile/$ENV no longer overridden by tty + settings. + * heredocs: now saved in memory to avoid temp files disappear too soon. + * time: commands at the end of a pipeline can now be timed. + * on startup: MAILCHECK,TMOUT,SECONDS values from environment are honoured. * trap: exit traps now executed in subshells (without explicit exit call). * eval: if given empty command, exist status is that of last command substitution (if any). @@ -18,6 +23,9 @@ Version 5.2.14pre * job control: resuming suspended gnu su no longer hoses su'd shell. * job control: fixed possible core dump when waiting for jobs. +* LINENO variable now supported. +* port to cygwin environment on win95/winnt. + Version 5.2.13 @@ -45,7 +53,7 @@ Version 5.2.13 * editing: completion after "cmd " now completes files (was command). -$OpenBSD: NEWS,v 1.9 1999/01/19 20:41:51 millert Exp $ +$OpenBSD: NEWS,v 1.10 1999/06/15 01:18:32 millert Exp $ Version 5.2.12 diff --git a/bin/ksh/NOTES b/bin/ksh/NOTES index fa009dcadd6..9db5173cfd7 100644 --- a/bin/ksh/NOTES +++ b/bin/ksh/NOTES @@ -1,11 +1,11 @@ -$OpenBSD: NOTES,v 1.6 1999/01/08 20:24:57 millert Exp $ +$OpenBSD: NOTES,v 1.7 1999/06/15 01:18:33 millert Exp $ General features of at&t ksh88 that are not (yet) in pdksh: - exported aliases and functions (not in ksh93). - set -t. - signals/traps not cleared during functions. - trap DEBUG, local ERR and EXIT traps in functions. - - ERRNO, LINENO parameters. + - ERRNO parameter. - doesn't have posix file globbing (eg, [[:alpha:]], etc.). - use of an `agent' to execute unreadable/setuid/setgid shell scripts (don't ask). @@ -18,7 +18,7 @@ Known bugs (see also BUG-REPORTS and PROJECTS files): " \t\n") others lose their special meaning. IFS/PATH taken care of, still need to sort out some others (eg, TMOUT). Parsing,Lexing: - - line numbers in errors are wrong for nested construct. Need to + - line numbers in errors are wrong for nested constructs. Need to keep track of the line a command started on (can use for LINENO parameter as well). - a $(..) expression nested inside double quotes inside another $(..) @@ -75,6 +75,11 @@ Known differences between pdksh & at&t ksh (that may change) - if the command 'sleep 5 && /bin/echo blah' is run interactively and is the sleep is stopped (^Z), the echo is run immediately in pdksh. In at&t ksh, the whole thing is stopped. + - LINENO: + - in ksh88 variable is always 1 (can't be changed) in interac mode; + in pdksh it changes. + - Value of LINENO after it has been set by the script in one file + is bizarre when used in another file. Known differences between pdksh & at&t ksh (that are not likely to change) - at&t ksh seems to catch or ignore SIGALRM - pdksh dies upon receipt diff --git a/bin/ksh/README b/bin/ksh/README index 1c5c8870067..0ada87e0185 100644 --- a/bin/ksh/README +++ b/bin/ksh/README @@ -1,4 +1,4 @@ -$OpenBSD: README,v 1.7 1998/10/29 04:09:19 millert Exp $ +$OpenBSD: README,v 1.8 1999/06/15 01:18:33 millert Exp $ Last updated October '97 for pdksh-5.2.13. (check ftp://ftp.cs.mun.ca:/pub/pdksh/ or @@ -190,4 +190,8 @@ as well as the following, if relevant (if you aren't sure, include them) * the contents of config.log (this is created by the configure script) * if you are using gcc (the GNU C compiler), which version it is. +BTW, the most frequently reported bug is + echo hi | read a; echo $a # Does not print hi +I'm aware of this and there is no need to report it. + Michael Rendell, michael@cs.mun.ca diff --git a/bin/ksh/c_ksh.c b/bin/ksh/c_ksh.c index 1dde0c7a844..c87a37918de 100644 --- a/bin/ksh/c_ksh.c +++ b/bin/ksh/c_ksh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: c_ksh.c,v 1.11 1999/01/10 17:55:01 millert Exp $ */ +/* $OpenBSD: c_ksh.c,v 1.12 1999/06/15 01:18:33 millert Exp $ */ /* * built-in Korn commands: c_* @@ -8,6 +8,10 @@ #include "ksh_stat.h" #include <ctype.h> +#ifdef __CYGWIN__ +#include <sys/cygwin.h> +#endif /* __CYGWIN__ */ + int c_cd(wp) char **wp; @@ -129,7 +133,8 @@ c_cd(wp) * setting in at&t ksh) */ if (current_wd[0]) - setstr(oldpwd_s, current_wd); /* SETSTR no die, don't set */ + /* Ignore failure (happens if readonly or integer) */ + setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); if (!ISABSPATH(Xstring(xs, xp))) { #ifdef OS2 @@ -149,8 +154,15 @@ c_cd(wp) /* Set PWD */ if (pwd) { - set_current_wd(pwd); - setstr(pwd_s, pwd); /* SETSTR no die, leave unchanged */ +#ifdef __CYGWIN__ + char ptmp[PATH]; /* larger than MAX_PATH */ + cygwin_conv_to_full_posix_path(pwd, ptmp); +#else /* __CYGWIN__ */ + char *ptmp = pwd; +#endif /* __CYGWIN__ */ + set_current_wd(ptmp); + /* Ignore failure (happens if readonly or integer) */ + setstr(pwd_s, ptmp, KSH_RETURN_ERROR); } else { set_current_wd(null); pwd = Xstring(xs, xp); @@ -1064,7 +1076,7 @@ c_let(wp) bi_errorf("no arguments"); else for (wp++; *wp; wp++) - if (!evaluate(*wp, &val, TRUE)) { + if (!evaluate(*wp, &val, KSH_RETURN_ERROR)) { rv = 2; /* distinguish error from zero result */ break; } else @@ -1297,8 +1309,9 @@ c_getopts(wp) const char *options; const char *var; int optc; + int ret; char buf[3]; - struct tbl *vq; + struct tbl *vq, *voptarg; if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; @@ -1364,21 +1377,27 @@ c_getopts(wp) user_opt.uoptind = user_opt.optind; } + voptarg = global("OPTARG"); + voptarg->flag &= ~RDONLY; /* at&t ksh clears ro and int */ + /* Paranoia: ensure no bizarre results. */ + if (voptarg->flag & INTEGER) + typeset("OPTARG", 0, INTEGER, 0, 0); if (user_opt.optarg == (char *) 0) - unset(global("OPTARG"), 0); + unset(voptarg, 0); else - setstr(global("OPTARG"), user_opt.optarg); /* SETSTR: no fail, cause exit code to be non-zero */ + /* This can't fail (have cleared readonly/integer) */ + setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); + + ret = 0; vq = global(var); - if (vq->flag & RDONLY) { - bi_errorf("%s is readonly", var); - return 1; - } + /* Error message already printed (integer, readonly) */ + if (!setstr(vq, buf, KSH_RETURN_ERROR)) + ret = 1; if (Flag(FEXPORT)) typeset(var, EXPORT, 0, 0, 0); - setstr(vq, buf); /* SETSTR: no fail, cause exit code to be !0 */ - return optc < 0 ? 1 : 0; + return optc < 0 ? 1 : ret; } #ifdef EMACS diff --git a/bin/ksh/c_sh.c b/bin/ksh/c_sh.c index abe9c8ea471..6b2f0f3fa45 100644 --- a/bin/ksh/c_sh.c +++ b/bin/ksh/c_sh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: c_sh.c,v 1.11 1999/01/10 17:55:02 millert Exp $ */ +/* $OpenBSD: c_sh.c,v 1.12 1999/06/15 01:18:33 millert Exp $ */ /* * built-in Bourne commands @@ -34,7 +34,7 @@ c_shift(wp) arg = wp[builtin_opt.optind]; if (arg) { - evaluate(arg, &val, FALSE); + evaluate(arg, &val, KSH_UNWIND_ERROR); n = val; } else n = 1; @@ -387,6 +387,7 @@ c_read(wp) cp--; Xput(cs, cp, '\0'); vp = global(*wp); + /* Must be done before setting export. */ if (vp->flag & RDONLY) { shf_flush(shf); bi_errorf("%s is read only", *wp); @@ -394,7 +395,10 @@ c_read(wp) } if (Flag(FEXPORT)) typeset(*wp, EXPORT, 0, 0, 0); - setstr(vp, Xstring(cs, cp)); /* SETSTR: fail */ + if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) { + shf_flush(shf); + return 1; + } } shf_flush(shf); @@ -424,13 +428,6 @@ c_eval(wp) if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; - /* XXX what is this? - { - int i; - for (i = builtin_opt.optind; wp[i]; i++) - shellf("eval[%s]\n", wp[i]); - } - */ s = pushs(SWORDS, ATEMP); s->u.strv = wp + builtin_opt.optind; /* diff --git a/bin/ksh/c_test.c b/bin/ksh/c_test.c index 49654f344f9..8ea1b4c94b7 100644 --- a/bin/ksh/c_test.c +++ b/bin/ksh/c_test.c @@ -1,4 +1,4 @@ -/* $OpenBSD: c_test.c,v 1.5 1998/06/25 19:01:47 millert Exp $ */ +/* $OpenBSD: c_test.c,v 1.6 1999/06/15 01:18:33 millert Exp $ */ /* * test(1); version 7-like -- author Erik Baalbergen @@ -365,8 +365,8 @@ test_eval(te, op, opnd1, opnd2, do_eval) { long v1, v2; - if (!evaluate(opnd1, &v1, TRUE) - || !evaluate(opnd2, &v2, TRUE)) + if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR) + || !evaluate(opnd2, &v2, KSH_RETURN_ERROR)) { /* error already printed.. */ te->flags |= TEF_ERROR; diff --git a/bin/ksh/c_ulimit.c b/bin/ksh/c_ulimit.c index 8ac133a81b8..c2bfced2508 100644 --- a/bin/ksh/c_ulimit.c +++ b/bin/ksh/c_ulimit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: c_ulimit.c,v 1.7 1999/01/08 20:24:57 millert Exp $ */ +/* $OpenBSD: c_ulimit.c,v 1.8 1999/06/15 01:18:33 millert Exp $ */ /* ulimit -- handle "ulimit" builtin @@ -171,7 +171,7 @@ c_ulimit(wp) else { long rval; - if (!evaluate(wp[0], &rval, TRUE)) + if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR)) return 1; /* Avoid problems caused by typos that * evaluate misses due to evaluating unset diff --git a/bin/ksh/edit.c b/bin/ksh/edit.c index 17992e47ff4..79bee4ab6df 100644 --- a/bin/ksh/edit.c +++ b/bin/ksh/edit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: edit.c,v 1.9 1999/01/10 17:55:02 millert Exp $ */ +/* $OpenBSD: edit.c,v 1.10 1999/06/15 01:18:33 millert Exp $ */ /* * Command line editing - common code @@ -42,9 +42,9 @@ static char vdisable_c; void x_init() { - /* set to -1 to force initial binding */ + /* set to -2 to force initial binding */ edchars.erase = edchars.kill = edchars.intr = edchars.quit - = edchars.eof = -1; + = edchars.eof = -2; /* default value for deficient systems */ edchars.werase = 027; /* ^W */ @@ -287,6 +287,24 @@ x_mode(onoff) set_tty(tty_fd, &cb, TF_WAIT); +#ifdef __CYGWIN__ + if (edchars.eof == '\0') + edchars.eof = '\4'; +#endif /* __CYGWIN__ */ + + /* Convert unset values to internal `unset' value */ + if (edchars.erase == vdisable_c) + edchars.erase = -1; + if (edchars.kill == vdisable_c) + edchars.kill = -1; + if (edchars.intr == vdisable_c) + edchars.intr = -1; + if (edchars.quit == vdisable_c) + edchars.quit = -1; + if (edchars.eof == vdisable_c) + edchars.eof = -1; + if (edchars.werase == vdisable_c) + edchars.werase = -1; if (memcmp(&edchars, &oldchars, sizeof(edchars)) != 0) { #ifdef EMACS x_emacs_keys(&edchars); diff --git a/bin/ksh/emacs.c b/bin/ksh/emacs.c index a89027658ba..8f716707d3c 100644 --- a/bin/ksh/emacs.c +++ b/bin/ksh/emacs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: emacs.c,v 1.8 1999/01/19 20:41:52 millert Exp $ */ +/* $OpenBSD: emacs.c,v 1.9 1999/06/15 01:18:33 millert Exp $ */ /* * Emacs-like command line editing and history @@ -110,6 +110,7 @@ static char *xmp; /* mark pointer */ static Findex x_last_command; static Findex (*x_tab)[X_TABSZ]; /* key definition */ static char *(*x_atab)[X_TABSZ]; /* macro definitions */ +static unsigned char x_bound[(X_TABSZ * X_NTABS + 7) / 8]; #define KILLSIZE 20 static char *killstack[KILLSIZE]; static int killsp, killtp; @@ -1461,6 +1462,14 @@ x_bind(a1, a2, macro, list) x_tab[prefix][key] = f; x_atab[prefix][key] = sp; + /* Track what the user has bound so x_emacs_keys() won't toast things */ + if (f == XFUNC_insert) + x_bound[(prefix * X_TABSZ + key) / 8] &= + ~(1 << ((prefix * X_TABSZ + key) % 8)); + else + x_bound[(prefix * X_TABSZ + key) / 8] |= + (1 << ((prefix * X_TABSZ + key) % 8)); + return 0; } @@ -1488,16 +1497,35 @@ x_init_emacs() x_atab[i][j] = NULL; } +static void +bind_if_not_bound(p, k, func) + int p, k; + int func; +{ + /* Has user already bound this key? If so, don't override it */ + if (x_bound[((p) * X_TABSZ + (k)) / 8] + & (1 << (((p) * X_TABSZ + (k)) % 8))) + return; + + x_tab[p][k] = func; +} + void x_emacs_keys(ec) X_chars *ec; { - x_tab[0][ec->erase] = XFUNC_del_back; - x_tab[0][ec->kill] = XFUNC_del_line; - x_tab[0][ec->werase] = XFUNC_del_bword; - x_tab[0][ec->intr] = XFUNC_abort; - x_tab[0][ec->quit] = XFUNC_noop; - x_tab[1][ec->erase] = XFUNC_del_bword; + if (ec->erase >= 0) { + bind_if_not_bound(0, ec->erase, XFUNC_del_back); + bind_if_not_bound(1, ec->erase, XFUNC_del_bword); + } + if (ec->kill >= 0) + bind_if_not_bound(0, ec->kill, XFUNC_del_line); + if (ec->werase >= 0) + bind_if_not_bound(0, ec->werase, XFUNC_del_bword); + if (ec->intr >= 0) + bind_if_not_bound(0, ec->intr, XFUNC_abort); + if (ec->quit >= 0) + bind_if_not_bound(0, ec->quit, XFUNC_noop); } static int diff --git a/bin/ksh/eval.c b/bin/ksh/eval.c index 3e63507acec..5ec7f433cba 100644 --- a/bin/ksh/eval.c +++ b/bin/ksh/eval.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eval.c,v 1.8 1999/01/10 17:55:02 millert Exp $ */ +/* $OpenBSD: eval.c,v 1.9 1999/06/15 01:18:33 millert Exp $ */ /* * Expansion - quoting, separation, substitution, globbing @@ -265,7 +265,7 @@ expand(cp, wp, f) v.type = 10; /* not default */ v.name[0] = '\0'; v_evaluate(&v, substitute(sp, 0), - FALSE); + KSH_UNWIND_ERROR); sp = strchr(sp, 0) + 1; for (p = str_val(&v); *p; ) { Xcheck(ds, dp); @@ -398,12 +398,6 @@ expand(cp, wp, f) st = st->prev; continue; case '=': - if (st->var->flag & RDONLY) - /* XXX POSIX says this is only - * fatal for special builtins - */ - errorf("%s: is read only", - st->var->name); /* Restore our position and substitute * the value of st->var (may not be * the assigned value in the presence @@ -414,10 +408,17 @@ expand(cp, wp, f) * global would cause with things * like x[i+=1] to be evaluated twice. */ + /* Note: not exported by FEXPORT + * in at&t ksh. + */ + /* XXX POSIX says readonly is only + * fatal for special builtins (setstr + * does readonly check). + */ setstr(st->var, debunk( (char *) alloc(strlen(dp) + 1, - ATEMP), dp)); - /* SETSTR: fail operation */ + ATEMP), dp), + KSH_UNWIND_ERROR); x.str = str_val(st->var); type = XSUB; if (f&DOBLANK) diff --git a/bin/ksh/exec.c b/bin/ksh/exec.c index 7e25a8d18e2..236da3efbfd 100644 --- a/bin/ksh/exec.c +++ b/bin/ksh/exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec.c,v 1.16 1999/01/19 20:41:52 millert Exp $ */ +/* $OpenBSD: exec.c,v 1.17 1999/06/15 01:18:33 millert Exp $ */ /* * execute command tree @@ -21,7 +21,7 @@ static int comexec ARGS((struct op *t, struct tbl *volatile tp, char **ap, static void scriptexec ARGS((struct op *tp, char **ap)); static int call_builtin ARGS((struct tbl *tp, char **wp)); static int iosetup ARGS((struct ioword *iop, struct tbl *tp)); -static int herein ARGS((char *hname, int sub)); +static int herein ARGS((const char *content, int sub)); #ifdef KSH static char *do_selectargs ARGS((char **ap, bool_t print_menu)); #endif /* KSH */ @@ -108,6 +108,8 @@ execute(t, flags) */ subst_exstat = 0; + current_lineno = t->lineno; /* for $LINENO */ + /* POSIX says expand command words first, then redirections, * and assignments last.. */ @@ -320,36 +322,20 @@ execute(t, flags) } rv = 0; /* in case of a continue */ if (t->type == TFOR) { - struct tbl *vq; - while (*ap != NULL) { - vq = global(t->str); - if (vq->flag & RDONLY) - errorf("%s is read only", t->str); - /* SETSTR: fail (put readonly check in setstr, - * controlled by a flag?) - */ - setstr(vq, *ap++); + setstr(global(t->str), *ap++, KSH_UNWIND_ERROR); rv = execute(t->left, flags & XERROK); } } #ifdef KSH else { /* TSELECT */ - struct tbl *vq; - for (;;) { if (!(cp = do_selectargs(ap, is_first))) { rv = 1; break; } is_first = FALSE; - vq = global(t->str); - if (vq->flag & RDONLY) - errorf("%s is read only", t->str); - /* SETSTR: fail (put readonly check in setstr, - * controlled by a flag?) - */ - setstr(vq, cp); + setstr(global(t->str), cp, KSH_UNWIND_ERROR); rv = execute(t->left, flags & XERROK); } } @@ -409,7 +395,10 @@ execute(t, flags) break; case TTIME: - rv = timex(t, flags); + /* Clear XEXEC so nested execute() call doesn't exit + * (allows "ls -l | time grep foo"). + */ + rv = timex(t, flags & ~XEXEC); break; case TEXEC: /* an eval'd TCOM */ @@ -478,8 +467,9 @@ comexec(t, tp, ap, flags) if (!Flag(FSH) && Flag(FTALKING) && *(lastp = ap)) { while (*++lastp) ; - /* SETSTR: can't fail */ - setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp); + /* setstr() can't fail here */ + setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp, + KSH_RETURN_ERROR); } #endif /* KSH */ @@ -724,8 +714,9 @@ comexec(t, tp, ap, flags) #ifdef KSH if (!Flag(FSH)) { /* set $_ to program's full path */ - /* SETSTR: can't fail */ - setstr(typeset("_", LOCAL|EXPORT, 0, 0, 0), tp->val.s); + /* setstr() can't fail here */ + setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), + tp->val.s, KSH_RETURN_ERROR); } #endif /* KSH */ @@ -886,8 +877,8 @@ shcomexec(wp) struct tbl * findfunc(name, h, create) const char *name; - unsigned int h; - int create; + unsigned int h; + int create; { struct block *l; struct tbl *tp = (struct tbl *) 0; @@ -948,7 +939,7 @@ define(name, t) tp->val.t = tcopy(t->left, tp->areap); tp->flag |= (ISSET|ALLOC); if (t->u.ksh_func) - tp->flag |= FKSH; + tp->flag |= FKSH; return 0; } @@ -1329,6 +1320,9 @@ iosetup(iop, tp) case IOWRITE: flags = O_WRONLY | O_CREAT | O_TRUNC; + /* The stat() is here to allow redirections to + * things like /dev/null without error. + */ if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode))) flags |= O_EXCL; @@ -1341,7 +1335,7 @@ iosetup(iop, tp) case IOHERE: do_open = 0; /* herein() returns -2 if error has been printed */ - u = herein(cp, iop->flag & IOEVAL); + u = herein(iop->heredoc, iop->flag & IOEVAL); /* cp may have wrong name */ break; @@ -1429,67 +1423,64 @@ iosetup(iop, tp) * if unquoted here, expand here temp file into second temp file. */ static int -herein(hname, sub) - char *hname; +herein(content, sub) + const char *content; int sub; { - int fd; + volatile int fd = -1; + struct source *s, *volatile osource; + struct shf *volatile shf; + struct temp *h; + int i; /* ksh -c 'cat << EOF' can cause this... */ - if (hname == (char *) 0) { + if (content == (char *) 0) { warningf(TRUE, "here document missing"); return -2; /* special to iosetup(): don't print error */ } + + /* Create temp file to hold content (done before newenv so temp + * doesn't get removed too soon). + */ + h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps); + if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) { + warningf(TRUE, "can't %s temporary file %s: %s", + !shf ? "create" : "open", + h->name, strerror(errno)); + if (shf) + shf_close(shf); + return -2 /* special to iosetup(): don't print error */; + } + + osource = source; + newenv(E_ERRH); + i = ksh_sigsetjmp(e->jbuf, 0); + if (i) { + source = osource; + quitenv(); + shf_close(shf); /* after quitenv */ + close(fd); + return -2; /* special to iosetup(): don't print error */ + } if (sub) { - char *cp; - struct source *s, *volatile osource = source; - struct temp *h; - struct shf *volatile shf; - int i; - - /* must be before newenv() 'cause shf uses ATEMP */ - shf = shf_open(hname, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); - if (shf == NULL) - return -1; - newenv(E_ERRH); - i = ksh_sigsetjmp(e->jbuf, 0); - if (i) { - if (shf) - shf_close(shf); - source = osource; - quitenv(); /* after shf_close() due to alloc */ - return -2; /* special to iosetup(): don't print error */ - } - /* set up yylex input from here file */ - s = pushs(SFILE, ATEMP); - s->u.shf = shf; + /* Do substitutions on the content of heredoc */ + s = pushs(SSTRING, ATEMP); + s->start = s->str = content; source = s; if (yylex(ONEWORD) != LWORD) internal_errorf(1, "herein: yylex"); - shf_close(shf); - shf = (struct shf *) 0; - cp = evalstr(yylval.cp, 0); - - /* write expanded input to another temp file */ - h = maketemp(ATEMP); - h->next = e->temps; e->temps = h; - if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) - /* shf closeed by error handler */ - errorf("%s: %s", h->name, strerror(errno)); - shf_puts(cp, shf); - if (shf_close(shf) == EOF) { - close(fd); - shf = (struct shf *) 0; - errorf("error writing %s: %s", h->name, - strerror(errno)); - } - shf = (struct shf *) 0; + source = osource; + shf_puts(evalstr(yylval.cp, 0), shf); + } else + shf_puts(content, shf); - quitenv(); - } else { - fd = open(hname, O_RDONLY, 0); - if (fd < 0) - return -1; + quitenv(); + + if (shf_close(shf) == EOF) { + close(fd); + warningf(TRUE, "error writing %s: %s", h->name, + strerror(errno)); + return -2; /* special to iosetup(): don't print error */ } return fd; diff --git a/bin/ksh/expr.c b/bin/ksh/expr.c index 1a9f4c9fa97..ddfcb53a04a 100644 --- a/bin/ksh/expr.c +++ b/bin/ksh/expr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: expr.c,v 1.6 1999/01/19 20:41:52 millert Exp $ */ +/* $OpenBSD: expr.c,v 1.7 1999/06/15 01:18:34 millert Exp $ */ /* * Korn expression evaluation @@ -39,7 +39,7 @@ enum token { /* things that don't appear in the opinfo[] table */ VAR, LIT, END, BAD }; -#define IS_BINOP(op) (((int)op) >= O_EQ && ((int)op) <= O_COMMA) +#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA) #define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN) enum prec { @@ -185,7 +185,7 @@ v_evaluate(vp, expr, error_ok) curstate.evaling->flag &= ~EXPRINEVAL; quitenv(); if (i == LAEXPR) { - if (error_ok) + if (error_ok == KSH_RETURN_ERROR) return 0; errorf(null); } @@ -208,8 +208,8 @@ v_evaluate(vp, expr, error_ok) if (vp->flag & INTEGER) setint_v(vp, v); else - /* SETSTR: can't fail; if pretending, allow fail */ - setstr(vp, str_val(v)); + /* can fail if readony */ + setstr(vp, str_val(v), error_ok); quitenv(); @@ -482,6 +482,15 @@ token(es) evalerr(es, ET_STR, "missing ]"); cp += len; } +#ifdef KSH + else if (c == '(' /*)*/ ) { + /* todo: add math functions (all take single argument): + * abs acos asin atan cos cosh exp int log sin sinh sqrt + * tan tanh + */ + ; + } +#endif /* KSH */ if (es->noassign) { es->val = tempvar(); es->val->flag |= EXPRLVALUE; @@ -552,9 +561,9 @@ assign_check(es, op, vasn) struct tbl *vasn; { if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE)) - evalerr(es, ET_LVALUE, opinfo[op].name); + evalerr(es, ET_LVALUE, opinfo[(int) op].name); else if (vasn->flag & RDONLY) - evalerr(es, ET_RDONLY, opinfo[op].name); + evalerr(es, ET_RDONLY, opinfo[(int) op].name); } static struct tbl * @@ -590,7 +599,7 @@ intvar(es, vp) evalerr(es, ET_RECURSIVE, vp->name); es->evaling = vp; vp->flag |= EXPRINEVAL; - v_evaluate(vq, str_val(vp), FALSE); + v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR); vp->flag &= ~EXPRINEVAL; es->evaling = (struct tbl *) 0; } diff --git a/bin/ksh/history.c b/bin/ksh/history.c index c962e957604..1f02e938697 100644 --- a/bin/ksh/history.c +++ b/bin/ksh/history.c @@ -1,4 +1,4 @@ -/* $OpenBSD: history.c,v 1.10 1999/01/10 17:55:02 millert Exp $ */ +/* $OpenBSD: history.c,v 1.11 1999/06/15 01:18:34 millert Exp $ */ /* * command history @@ -225,8 +225,7 @@ c_fc(wp) /* Run editor on selected lines, then run resulting commands */ - tf = maketemp(ATEMP); - tf->next = e->temps; e->temps = tf; + tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps); if (!(shf = tf->shf)) { bi_errorf("cannot create temp file %s - %s", tf->name, strerror(errno)); @@ -241,8 +240,8 @@ c_fc(wp) } if (!Flag(FSH)) { - /* SETSTR: ignore fail (arbitrary) */ - setstr(local("_", FALSE), tf->name); + /* Ignore setstr errors here (arbitrary) */ + setstr(local("_", FALSE), tf->name, KSH_RETURN_ERROR); } /* XXX: source should not get trashed by this.. */ diff --git a/bin/ksh/io.c b/bin/ksh/io.c index b2e98a73b3b..8866a990b6e 100644 --- a/bin/ksh/io.c +++ b/bin/ksh/io.c @@ -1,4 +1,4 @@ -/* $OpenBSD: io.c,v 1.7 1999/01/10 17:55:02 millert Exp $ */ +/* $OpenBSD: io.c,v 1.8 1999/06/15 01:18:34 millert Exp $ */ /* * shell buffered IO and formatted output @@ -494,31 +494,35 @@ coproc_cleanup(reuse) } #endif /* KSH */ + /* * temporary files */ struct temp * -maketemp(ap) +maketemp(ap, type, tlist) Area *ap; + Temp_type type; + struct temp **tlist; { static unsigned int inc; struct temp *tp; int len; int fd; char *path; - const char *tmp; + const char *dir; - tmp = tmpdir ? tmpdir : "/tmp"; + dir = tmpdir ? tmpdir : "/tmp"; /* The 20 + 20 is a paranoid worst case for pid/inc */ - len = strlen(tmp) + 3 + 20 + 20 + 1; + len = strlen(dir) + 3 + 20 + 20 + 1; tp = (struct temp *) alloc(sizeof(struct temp) + len, ap); tp->name = path = (char *) &tp[1]; tp->shf = (struct shf *) 0; + tp->type = type; while (1) { /* Note that temp files need to fit 8.3 DOS limits */ shf_snprintf(path, len, "%s/sh%05u.%03x", - tmp, (unsigned) procpid, inc++); + dir, (unsigned) procpid, inc++); /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't * really there. */ @@ -535,12 +539,16 @@ maketemp(ap) && errno != EISDIR #endif /* EISDIR */ ) - /* Error must be printed by called: don't know here if + /* Error must be printed by caller: don't know here if * errorf() or bi_errorf() should be used. */ break; } tp->next = NULL; tp->pid = procpid; + + tp->next = *tlist; + *tlist = tp; + return tp; } diff --git a/bin/ksh/ksh.1 b/bin/ksh/ksh.1 index 2ef4cde62c9..466b947ec4b 100644 --- a/bin/ksh/ksh.1 +++ b/bin/ksh/ksh.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ksh.1,v 1.20 1999/06/14 03:13:58 pjanzen Exp $ +.\" $OpenBSD: ksh.1,v 1.21 1999/06/15 01:18:34 millert Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -1335,7 +1335,7 @@ and below. .It Ev LINENO The line number of the function or shell script that is currently being -executed. Not yet implemented. +executed. .It Ev LINES Set to the number of lines on the terminal or window. Not yet implemented. .It Ev MAIL @@ -4702,6 +4702,13 @@ and a copy of your script). New version of .Nm pdksh can be obtained from ftp://ftp.cs.mun.ca/pub/pdksh. +.Pp +BTW, the most frequently reported bug is: +.Bd -literal -offset indent +echo hi | read a; echo $a\ \ \ # Does not print hi +.Ed +.Pp +I'm aware of this and there is no need to report it. .Sh AUTHORS This shell is based on the public domain 7th edition Bourne shell clone by Charles Forsyth and parts of the BRL shell by Doug A. Gwyn, Doug Kingston, diff --git a/bin/ksh/ksh.1tbl b/bin/ksh/ksh.1tbl index 87858d03d22..c56f42d0240 100644 --- a/bin/ksh/ksh.1tbl +++ b/bin/ksh/ksh.1tbl @@ -1,4 +1,4 @@ -.\" $OpenBSD: ksh.1tbl,v 1.20 1999/06/14 03:13:58 pjanzen Exp $ +.\" $OpenBSD: ksh.1tbl,v 1.21 1999/06/15 01:18:34 millert Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -1335,7 +1335,7 @@ and below. .It Ev LINENO The line number of the function or shell script that is currently being -executed. Not yet implemented. +executed. .It Ev LINES Set to the number of lines on the terminal or window. Not yet implemented. .It Ev MAIL @@ -4702,6 +4702,13 @@ and a copy of your script). New version of .Nm pdksh can be obtained from ftp://ftp.cs.mun.ca/pub/pdksh. +.Pp +BTW, the most frequently reported bug is: +.Bd -literal -offset indent +echo hi | read a; echo $a\ \ \ # Does not print hi +.Ed +.Pp +I'm aware of this and there is no need to report it. .Sh AUTHORS This shell is based on the public domain 7th edition Bourne shell clone by Charles Forsyth and parts of the BRL shell by Doug A. Gwyn, Doug Kingston, diff --git a/bin/ksh/lex.c b/bin/ksh/lex.c index 78e8ee06c67..ecba1a46910 100644 --- a/bin/ksh/lex.c +++ b/bin/ksh/lex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lex.c,v 1.13 1999/01/19 20:41:55 millert Exp $ */ +/* $OpenBSD: lex.c,v 1.14 1999/06/15 01:18:34 millert Exp $ */ /* * lexical analysis and source input @@ -665,6 +665,7 @@ Done: iop->name = (char *) 0; iop->delim = (char *) 0; + iop->heredoc = (char *) 0; Xfree(ws, wp); /* free word */ yylval.iop = iop; return REDIR; @@ -783,46 +784,27 @@ gethere() static void readhere(iop) - register struct ioword *iop; + struct ioword *iop; { - struct shf *volatile shf; - struct temp *h; register int c; char *volatile eof; char *eofp; int skiptabs; - int i; + XString xs; + char *xp; + int xpos; eof = evalstr(iop->delim, 0); - if (e->flags & EF_FUNC_PARSE) { - h = maketemp(APERM); - h->next = func_heredocs; - func_heredocs = h; - } else { - h = maketemp(ATEMP); - h->next = e->temps; - e->temps = h; - } - iop->name = h->name; - if (!(shf = h->shf)) - yyerror("cannot create temporary file %s - %s\n", - h->name, strerror(errno)); - - newenv(E_ERRH); - i = ksh_sigsetjmp(e->jbuf, 0); - if (i) { - quitenv(); - shf_close(shf); - unwind(i); - } - if (!(iop->flag & IOEVAL)) ignore_backslash_newline++; + Xinit(xs, xp, 256, ATEMP); + for (;;) { eofp = eof; skiptabs = iop->flag & IOSKIP; + xpos = Xsavepos(xs, xp); while ((c = getsc()) != 0) { if (skiptabs) { if (c == '\t') @@ -831,29 +813,30 @@ readhere(iop) } if (c != *eofp) break; + Xcheck(xs, xp); + Xput(xs, xp, c); eofp++; } /* Allow EOF here so commands with out trailing newlines * will work (eg, ksh -c '...', $(...), etc). */ - if (*eofp == '\0' && (c == 0 || c == '\n')) + if (*eofp == '\0' && (c == 0 || c == '\n')) { + xp = Xrestpos(xs, xp, xpos); break; + } ungetsc(c); - shf_write(eof, eofp - eof, shf); while ((c = getsc()) != '\n') { if (c == 0) yyerror("here document `%s' unclosed\n", eof); - shf_putc(c, shf); + Xcheck(xs, xp); + Xput(xs, xp, c); } - shf_putc(c, shf); + Xcheck(xs, xp); + Xput(xs, xp, c); } - shf_flush(shf); - if (shf_error(shf)) - yyerror("error saving here document `%s': %s\n", - eof, strerror(shf_errno(shf))); - /*XXX add similar checks for write errors everywhere */ - quitenv(); - shf_close(shf); + Xput(xs, xp, '\0'); + iop->heredoc = Xclose(xs, xp); + if (!(iop->flag & IOEVAL)) ignore_backslash_newline--; } diff --git a/bin/ksh/lex.h b/bin/ksh/lex.h index 427d20cabef..334e46ca6eb 100644 --- a/bin/ksh/lex.h +++ b/bin/ksh/lex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lex.h,v 1.4 1998/06/25 19:02:07 millert Exp $ */ +/* $OpenBSD: lex.h,v 1.5 1999/06/15 01:18:35 millert Exp $ */ /* * Source input, lexer and parser @@ -12,7 +12,7 @@ typedef struct source Source; struct source { const char *str; /* input pointer */ int type; /* input type */ - char const *start; /* start of current buffer */ + const char *start; /* start of current buffer */ union { char **strv; /* string [] */ struct shf *shf; /* shell file */ diff --git a/bin/ksh/mail.c b/bin/ksh/mail.c index 2a9d429e524..c0f0b1fe17c 100644 --- a/bin/ksh/mail.c +++ b/bin/ksh/mail.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mail.c,v 1.8 1999/01/10 17:55:03 millert Exp $ */ +/* $OpenBSD: mail.c,v 1.9 1999/06/15 01:18:35 millert Exp $ */ /* * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by @@ -27,9 +27,10 @@ typedef struct mbox { * same list is used for both since they are exclusive. */ -static mbox_t *mplist; -static mbox_t mbox; +static mbox_t *mplist; +static mbox_t mbox; static time_t mlastchkd; /* when mail was last checked */ +static time_t mailcheck_interval; static void munset ARGS((mbox_t *mlist)); /* free mlist and mval */ static mbox_t * mballoc ARGS((char *p, char *m)); /* allocate a new mbox */ @@ -40,21 +41,16 @@ mcheck() { register mbox_t *mbp; time_t now; - long mailcheck; struct tbl *vp; struct stat stbuf; - if (getint(global("MAILCHECK"), &mailcheck) < 0) - return; - now = time((time_t *) 0); if (mlastchkd == 0) mlastchkd = now; - if (now - mlastchkd >= mailcheck) { + if (now - mlastchkd >= mailcheck_interval) { mlastchkd = now; - vp = global("MAILPATH"); - if (vp && (vp->flag & ISSET)) + if (mplist) mbp = mplist; else if ((vp = global("MAIL")) && (vp->flag & ISSET)) mbp = &mbox; @@ -85,6 +81,13 @@ mcheck() } void +mcset(interval) + long interval; +{ + mailcheck_interval = interval; +} + +void mbset(p) register char *p; { @@ -192,8 +195,8 @@ mbox_t *mbp; */ if (!Flag(FSH)) #endif - /* SETSTR: ignore fail (arbitrary; havn't checked at&t) */ - setstr((vp = local("_", FALSE)), mbp->mb_path); + /* Ignore setstr errors here (arbitrary) */ + setstr((vp = local("_", FALSE)), mbp->mb_path, KSH_RETURN_ERROR); shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0)); diff --git a/bin/ksh/main.c b/bin/ksh/main.c index 1b2dbe531cd..1e751cb7563 100644 --- a/bin/ksh/main.c +++ b/bin/ksh/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.14 1999/04/27 18:18:19 millert Exp $ */ +/* $OpenBSD: main.c,v 1.15 1999/06/15 01:18:35 millert Exp $ */ /* * startup, main loop, enviroments and error handling @@ -24,10 +24,9 @@ static int is_restricted ARGS((char *name)); * shell initialization */ -static const char initifs [] = "IFS= \t\n"; /* must be R/W */ +static const char initifs[] = "IFS= \t\n"; -static const char initsubs [] = - "${PS2=> } ${PS3=#? } ${PS4=+ }"; +static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }"; static const char version_param[] = #ifdef KSH @@ -37,27 +36,14 @@ static const char version_param[] = #endif /* KSH */ ; -/* -MAILCHECK: - typeset -i MAILCHECK - : "${MAILCHECK=600}" -SECONDS: - typeset -i SECONDS - initialize seconds to $SECONDS -TMOUT: - typeset -i - do setspec -*/ - static const char *const initcoms [] = { "typeset", "-x", "SHELL", "PATH", "HOME", NULL, "typeset", "-r", version_param, NULL, "typeset", "-i", "PPID", NULL, - "typeset", "-i", "OPTIND=1", + "typeset", "-i", "OPTIND=1", NULL, #ifdef KSH - "MAILCHECK=600", "RANDOM", "SECONDS=0", "TMOUT=0", + "eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL, #endif /* KSH */ - NULL, "alias", /* Standard ksh aliases */ "hash=alias -t", /* not "alias -t --": hash -r needs to work */ @@ -188,8 +174,8 @@ main(argc, argv) */ { struct tbl *vp = global("PATH"); - /* SETSTR: can't fail */ - setstr(vp, def_path); + /* setstr can't fail here */ + setstr(vp, def_path, KSH_RETURN_ERROR); } @@ -255,16 +241,16 @@ main(argc, argv) * bogus value */ if (current_wd[0] || pwd != null) - /* SETSTR: can't fail */ - setstr(pwd_v, current_wd); + /* setstr can't fail here */ + setstr(pwd_v, current_wd, KSH_RETURN_ERROR); } ppid = getppid(); setint(global("PPID"), (long) ppid); #ifdef KSH setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid)); #endif /* KSH */ - /* SETSTR: can't fail */ - setstr(global(version_param), ksh_version); + /* setstr can't fail here */ + setstr(global(version_param), ksh_version, KSH_RETURN_ERROR); /* execute initialization statements */ for (wp = (char**) initcoms; *wp != NULL; wp++) { @@ -284,8 +270,8 @@ main(argc, argv) */ if (!(vp->flag & ISSET) || (!ksheuid && !strchr(str_val(vp), '#'))) - /* SETSTR: can't fail */ - setstr(vp, safe_prompt); + /* setstr can't fail here */ + setstr(vp, safe_prompt, KSH_RETURN_ERROR); } /* Set this before parsing arguments */ @@ -673,32 +659,10 @@ unwind(i) ksh_siglongjmp(e->jbuf, i); /*NOTREACHED*/ - case E_NONE: /* bottom of the stack */ - { - if (Flag(FTALKING)) - hist_finish(); - j_exit(); - remove_temps(func_heredocs); - if (i == LINTR) { - int sig = exstat - 128; - - /* ham up our death a bit (at&t ksh - * only seems to do this for SIGTERM) - * Don't do it for SIGQUIT, since we'd - * dump a core.. - */ - if (sig == SIGINT || sig == SIGTERM) { - setsig(&sigtraps[sig], SIG_DFL, - SS_RESTORE_CURR|SS_FORCE); - kill(0, sig); - } - } -#ifdef MEM_DEBUG - chmem_allfree(); -#endif /* MEM_DEBUG */ - exit(exstat); - /* NOTREACHED */ - } + case E_NONE: + if (i == LINTR) + e->flags |= EF_FAKE_SIGDIE; + /* Fall through... */ default: quitenv(); @@ -729,9 +693,7 @@ quitenv() register struct env *ep = e; register int fd; - if (ep->oenv == NULL) /* cleanup_parents_env() was called */ - exit(exstat); /* exit child */ - if (ep->oenv->loc != ep->loc) + if (ep->oenv && ep->oenv->loc != ep->loc) popblock(); if (ep->savefd != NULL) { for (fd = 0; fd < NUFILE; fd++) @@ -742,6 +704,36 @@ quitenv() shf_reopen(2, SHF_WR, shl_out); } reclaim(); + + /* Bottom of the stack. + * Either main shell is exiting or cleanup_parents_env() was called. + */ + if (ep->oenv == NULL) { + if (ep->type == E_NONE) { /* Main shell exiting? */ + if (Flag(FTALKING)) + hist_finish(); + j_exit(); + if (ep->flags & EF_FAKE_SIGDIE) { + int sig = exstat - 128; + + /* ham up our death a bit (at&t ksh + * only seems to do this for SIGTERM) + * Don't do it for SIGQUIT, since we'd + * dump a core.. + */ + if (sig == SIGINT || sig == SIGTERM) { + setsig(&sigtraps[sig], SIG_DFL, + SS_RESTORE_CURR|SS_FORCE); + kill(0, sig); + } + } +#ifdef MEM_DEBUG + chmem_allfree(); +#endif /* MEM_DEBUG */ + } + exit(exstat); + } + e = e->oenv; afree(ep, ATEMP); } @@ -760,10 +752,13 @@ cleanup_parents_env() /* close all file descriptors hiding in savefd */ for (ep = e; ep; ep = ep->oenv) { - if (ep->savefd) + if (ep->savefd) { for (fd = 0; fd < NUFILE; fd++) if (ep->savefd[fd] > 0) close(ep->savefd[fd]); + afree(ep->savefd, &ep->area); + ep->savefd = (short *) 0; + } } e->oenv = (struct env *) 0; } @@ -776,7 +771,6 @@ cleanup_proc_env() for (ep = e; ep; ep = ep->oenv) remove_temps(ep->temps); - remove_temps(func_heredocs); } /* remove temp files and free ATEMP Area */ diff --git a/bin/ksh/misc.c b/bin/ksh/misc.c index 00b13c3ffd6..af2e4438640 100644 --- a/bin/ksh/misc.c +++ b/bin/ksh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.9 1999/01/08 20:25:01 millert Exp $ */ +/* $OpenBSD: misc.c,v 1.10 1999/06/15 01:18:35 millert Exp $ */ /* * Miscellaneous functions @@ -259,7 +259,7 @@ char * getoptions() { int i; - char m[FNFLAGS + 1]; + char m[(int) FNFLAGS + 1]; register char *cp = m; for (i = 0; i < NELEM(options); i++) diff --git a/bin/ksh/missing.c b/bin/ksh/missing.c index 7f507fe66b9..2bcffac1d07 100644 --- a/bin/ksh/missing.c +++ b/bin/ksh/missing.c @@ -1,4 +1,4 @@ -/* $OpenBSD: missing.c,v 1.3 1997/06/19 13:58:45 kstailey Exp $ */ +/* $OpenBSD: missing.c,v 1.4 1999/06/15 01:18:35 millert Exp $ */ /* * Routines which may be missing on some machines @@ -269,3 +269,27 @@ ksh_opendir(d) return opendir(d); } #endif /* OPENDIR_DOES_NONDIR */ + +#ifndef HAVE_DUP2 +int +dup2(oldd, newd) + int oldd; + int newd; +{ + int old_errno; + + if (fcntl(oldd, F_GETFL, 0) == -1) + return -1; /* errno == EBADF */ + + if (oldd == newd) + return newd; + + old_errno = errno; + + close(newd); /* in case its open */ + + errno = old_errno; + + return fcntl(oldd, F_DUPFD, newd); +} +#endif /* !HAVE_MEMSET */ diff --git a/bin/ksh/path.c b/bin/ksh/path.c index c0a4c6abeb9..8acf0d854c3 100644 --- a/bin/ksh/path.c +++ b/bin/ksh/path.c @@ -1,4 +1,4 @@ -/* $OpenBSD: path.c,v 1.5 1998/10/29 04:09:21 millert Exp $ */ +/* $OpenBSD: path.c,v 1.6 1999/06/15 01:18:35 millert Exp $ */ #include "sh.h" #include "ksh_stat.h" @@ -14,6 +14,9 @@ /* * $Log: path.c,v $ + * Revision 1.6 1999/06/15 01:18:35 millert + * patches from pdksh 5.2.13.11 + * * Revision 1.5 1998/10/29 04:09:21 millert * Bug fixes from pdksh-unstable-5.2.13.4, including "official" versions of * some that we had already fixed locally. @@ -179,10 +182,10 @@ simplify_path(path) if ((isrooted = ISROOTEDPATH(path))) very_start++; -#ifdef OS2 +#if defined (OS2) || defined (__CYGWIN__) if (path[0] && path[1] == ':') /* skip a: */ very_start += 2; -#endif /* OS2 */ +#endif /* OS2 || __CYGWIN__ */ /* Before After * /foo/ /foo @@ -192,13 +195,19 @@ simplify_path(path) * .. .. * ./foo foo * foo/../../../bar ../../bar - * OS2: + * OS2 and CYGWIN: * a:/foo/../.. a:/ * a:. a: * a:.. a:.. * a:foo/../../blah a:../blah */ +#ifdef __CYGWIN__ + /* preserve leading double-slash on pathnames (for UNC paths) */ + if (path[0] && ISDIRSEP(path[0]) && path[1] && ISDIRSEP(path[1])) + very_start++; +#endif /* __CYGWIN__ */ + for (cur = t = start = very_start; ; ) { /* treat multiple '/'s as one '/' */ while (ISDIRSEP(*t)) diff --git a/bin/ksh/proto.h b/bin/ksh/proto.h index 42f2b72990e..3261f519553 100644 --- a/bin/ksh/proto.h +++ b/bin/ksh/proto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proto.h,v 1.6 1999/01/08 20:25:01 millert Exp $ */ +/* $OpenBSD: proto.h,v 1.7 1999/06/15 01:18:35 millert Exp $ */ /* * prototypes for PD-KSH @@ -134,7 +134,7 @@ void coproc_write_close ARGS((int fd)); int coproc_getfd ARGS((int mode, const char **emsgp)); void coproc_cleanup ARGS((int reuse)); #endif /* KSH */ -struct temp *maketemp ARGS((Area *ap)); +struct temp *maketemp ARGS((Area *ap, Temp_type type, struct temp **tlist)); /* jobs.c */ void j_init ARGS((int mflagset)); void j_exit ARGS((void)); @@ -159,6 +159,7 @@ void pprompt ARGS((const char *cp, int ntruncate)); /* mail.c */ #ifdef KSH void mcheck ARGS((void)); +void mcset ARGS((long interval)); void mbset ARGS((char *p)); void mpset ARGS((char *mptoparse)); #endif /* KSH */ @@ -258,7 +259,7 @@ struct tbl * global ARGS((const char *n)); struct tbl * local ARGS((const char *n, bool_t copy)); char * str_val ARGS((struct tbl *vp)); long intval ARGS((struct tbl *vp)); -void setstr ARGS((struct tbl *vq, const char *s)); +int setstr ARGS((struct tbl *vq, const char *s, int error_ok)); struct tbl *setint_v ARGS((struct tbl *vq, struct tbl *vp)); void setint ARGS((struct tbl *vq, long n)); int getint ARGS((struct tbl *vp, long *nump)); diff --git a/bin/ksh/sh.1 b/bin/ksh/sh.1 index db0d257db0f..722cf611a7a 100644 --- a/bin/ksh/sh.1 +++ b/bin/ksh/sh.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sh.1,v 1.13 1999/06/14 03:13:59 pjanzen Exp $ +.\" $OpenBSD: sh.1,v 1.14 1999/06/15 01:18:35 millert Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -1149,7 +1149,7 @@ started. The version of shell and the date the version was created (read-only). .It Ev LINENO The line number of the function or shell script that is currently being -executed. Not yet implemented. +executed. .It Ev LINES Set to the number of lines on the terminal or window. Not yet implemented. .It Ev OLDPWD @@ -3493,6 +3493,13 @@ and a copy of your script). New version of .Nm pdksh can be obtained from ftp://ftp.cs.mun.ca/pub/pdksh. +.Pp +BTW, the most frequently reported bug is: +.Bd -literal -offset indent +echo hi | read a; echo $a\ \ \ # Does not print hi +.Ed +.Pp +I'm aware of this and there is no need to report it. .Sh AUTHORS This shell is based on the public domain 7th edition Bourne shell clone by Charles Forsyth and parts of the BRL shell by Doug A. Gwyn, Doug Kingston, diff --git a/bin/ksh/sh.1tbl b/bin/ksh/sh.1tbl index e13435e1792..c53584f22bc 100644 --- a/bin/ksh/sh.1tbl +++ b/bin/ksh/sh.1tbl @@ -1,4 +1,4 @@ -.\" $OpenBSD: sh.1tbl,v 1.13 1999/06/14 03:13:59 pjanzen Exp $ +.\" $OpenBSD: sh.1tbl,v 1.14 1999/06/15 01:18:35 millert Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -1149,7 +1149,7 @@ started. The version of shell and the date the version was created (read-only). .It Ev LINENO The line number of the function or shell script that is currently being -executed. Not yet implemented. +executed. .It Ev LINES Set to the number of lines on the terminal or window. Not yet implemented. .It Ev OLDPWD @@ -3493,6 +3493,13 @@ and a copy of your script). New version of .Nm pdksh can be obtained from ftp://ftp.cs.mun.ca/pub/pdksh. +.Pp +BTW, the most frequently reported bug is: +.Bd -literal -offset indent +echo hi | read a; echo $a\ \ \ # Does not print hi +.Ed +.Pp +I'm aware of this and there is no need to report it. .Sh AUTHORS This shell is based on the public domain 7th edition Bourne shell clone by Charles Forsyth and parts of the BRL shell by Doug A. Gwyn, Doug Kingston, diff --git a/bin/ksh/sh.h b/bin/ksh/sh.h index 94bba638ed5..2d61648ae7a 100644 --- a/bin/ksh/sh.h +++ b/bin/ksh/sh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sh.h,v 1.8 1999/01/19 20:41:56 millert Exp $ */ +/* $OpenBSD: sh.h,v 1.9 1999/06/15 01:18:36 millert Exp $ */ /* * Public Domain Bourne/Korn shell @@ -239,6 +239,10 @@ extern int ksh_execve(char *cmd, char **args, char **env, int flags); # define ksh_jmp_buf jmp_buf #endif /* HAVE_SIGSETJMP */ +#ifndef HAVE_DUP2 +extern int dup2 ARGS((int, int)); +#endif /* !HAVE_DUP2 */ + /* Find a integer type that is at least 32 bits (or die) - SIZEOF_* defined * by autoconf (assumes an 8 bit byte, but I'm not concerned). * NOTE: INT32 may end up being more than 32 bits. @@ -290,15 +294,16 @@ extern int ksh_execve(char *cmd, char **args, char **env, int flags); * ISROOTEDPATH() means a .. as the first component is a no-op, * ISRELPATH() means $PWD can be tacked on to get an absolute path. * - * OS Path ISABSPATH ISROOTEDPATH ISRELPATH - * unix /foo yes yes no - * unix foo no no yes - * unix ../foo no no yes - * os2 a:/foo yes yes no - * os2 a:foo no no no - * os2 /foo no yes no - * os2 foo no no yes - * os2 ../foo no no yes + * OS Path ISABSPATH ISROOTEDPATH ISRELPATH + * unix /foo yes yes no + * unix foo no no yes + * unix ../foo no no yes + * os2+cyg a:/foo yes yes no + * os2+cyg a:foo no no no + * os2+cyg /foo no yes no + * os2+cyg foo no no yes + * os2+cyg ../foo no no yes + * cyg //foo yes yes no */ #ifdef OS2 # define PATHSEP ';' @@ -320,9 +325,15 @@ extern char *ksh_strrchr_dirsep(const char *path); # define DIRSEP '/' # define DIRSEPSTR "/" # define ISDIRSEP(c) ((c) == '/') +#ifdef __CYGWIN__ +# define ISABSPATH(s) \ + (((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])) || ISDIRSEP((s)[0])) +# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0]))) +#else /* __CYGWIN__ */ # define ISABSPATH(s) ISDIRSEP((s)[0]) -# define ISROOTEDPATH(s) ISABSPATH(s) # define ISRELPATH(s) (!ISABSPATH(s)) +#endif /* __CYGWIN__ */ +# define ISROOTEDPATH(s) ISABSPATH(s) # define FILECHCONV(c) c # define FILECMP(s1, s2) strcmp(s1, s2) # define FILENCMP(s1, s2, n) strncmp(s1, s2, n) @@ -422,6 +433,7 @@ EXTERN struct env { /* struct env.flag values */ #define EF_FUNC_PARSE BIT(0) /* function being parsed */ #define EF_BRKCONT_PASS BIT(1) /* set if E_LOOP must pass break/continue on */ +#define EF_FAKE_SIGDIE BIT(2) /* hack to get info from unwind to quitenv */ /* Do breaks/continues stop at env type e? */ #define STOP_BRKCONT(t) ((t) == E_NONE || (t) == E_PARSE \ @@ -516,18 +528,20 @@ EXTERN char space [] I__(" "); EXTERN char newline [] I__("\n"); EXTERN char slash [] I__("/"); -/* temp/here files. the file is removed when the struct is freed */ +enum temp_type { + TT_HEREDOC_EXP, /* expanded heredoc */ + TT_HIST_EDIT /* temp file used for history editing (fc -e) */ +}; +typedef enum temp_type Temp_type; +/* temp/heredoc files. The file is removed when the struct is freed. */ struct temp { struct temp *next; struct shf *shf; int pid; /* pid of process parsed here-doc */ + Temp_type type; char *name; }; -/* here documents in functions are treated specially (the get removed when - * shell exis) */ -EXTERN struct temp *func_heredocs; - /* * stdio and our IO routines */ @@ -714,6 +728,10 @@ EXTERN int x_cols I__(80); /* tty columns */ # endif /* __NeXT */ #endif /* KSH_SYSTEM_PROFILE */ +/* Used by v_evaluate() and setstr() to control action when error occurs */ +#define KSH_UNWIND_ERROR 0 /* unwind the stack (longjmp) */ +#define KSH_RETURN_ERROR 1 /* return 1/0 for success/failure */ + #include "shf.h" #include "table.h" #include "tree.h" diff --git a/bin/ksh/shf.c b/bin/ksh/shf.c index d6382098138..e3b27a1bd07 100644 --- a/bin/ksh/shf.c +++ b/bin/ksh/shf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: shf.c,v 1.5 1999/01/19 20:41:56 millert Exp $ */ +/* $OpenBSD: shf.c,v 1.6 1999/06/15 01:18:36 millert Exp $ */ /* * Shell file I/O routines @@ -33,18 +33,32 @@ shf_open(name, oflags, mode, sflags) int mode; int sflags; { + struct shf *shf; + int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; int fd; + /* Done before open so if alloca fails, fd won't be lost. */ + shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); + shf->areap = ATEMP; + shf->buf = (unsigned char *) &shf[1]; + shf->bsize = bsize; + shf->flags = SHF_ALLOCS; + /* Rest filled in by reopen. */ + fd = open(name, oflags, mode); - if (fd < 0) + if (fd < 0) { + afree(shf, shf->areap); return NULL; + } if ((sflags & SHF_MAPHI) && fd < FDBASE) { int nfd; nfd = ksh_dupbase(fd, FDBASE); close(fd); - if (nfd < 0) + if (nfd < 0) { + afree(shf, shf->areap); return NULL; + } fd = nfd; } sflags &= ~SHF_ACCMODE; @@ -52,7 +66,7 @@ shf_open(name, oflags, mode, sflags) : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR); - return shf_fdopen(fd, sflags, (struct shf *) 0); + return shf_reopen(fd, sflags, shf); } /* Set up the shf structure for a file descriptor. Doesn't fail. */ @@ -697,7 +711,10 @@ shf_write(buf, nbytes, shf) if (nbytes < 0) internal_errorf(1, "shf_write: nbytes %d", nbytes); - if ((ncopy = shf->wnleft)) { + /* Don't buffer if buffer is empty and we're writting a large amount. */ + if ((ncopy = shf->wnleft) + && (shf->wp != shf->buf || nbytes < shf->wnleft)) + { if (ncopy > nbytes) ncopy = nbytes; memcpy(shf->wp, buf, ncopy); diff --git a/bin/ksh/syn.c b/bin/ksh/syn.c index 068d7d40552..087e0f7063b 100644 --- a/bin/ksh/syn.c +++ b/bin/ksh/syn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syn.c,v 1.11 1998/10/29 04:09:21 millert Exp $ */ +/* $OpenBSD: syn.c,v 1.12 1999/06/15 01:18:36 millert Exp $ */ /* * shell parser (C version) @@ -227,6 +227,7 @@ get_command(cf) REJECT; syniocf &= ~(KEYWORD|ALIAS); t = newtp(TCOM); + t->lineno = source->line; while (1) { cf = (t->u.evalflags ? ARRAYVAR : 0) | (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); @@ -295,6 +296,7 @@ get_command(cf) CHAR, 't', EOS }; /* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */ t = newtp(TCOM); + t->lineno = source->line; ACCEPT; XPput(args, wdcopy(let_cmd, ATEMP)); musthave(LWORD,LETEXPR); @@ -551,6 +553,7 @@ function_body(name, ksh_func) t = newtp(TFUNCT); t->str = sname; t->u.ksh_func = ksh_func; + t->lineno = source->line; /* Note that POSIX allows only compound statements after foo(), sh and * at&t ksh allow any command, go with the later since it shouldn't @@ -580,6 +583,7 @@ function_body(name, ksh_func) t->left->args[1] = (char *) 0; t->left->vars = (char **) alloc(sizeof(char *), ATEMP); t->left->vars[0] = (char *) 0; + t->left->lineno = 1; } if (!old_func_parse) e->flags &= ~EF_FUNC_PARSE; diff --git a/bin/ksh/table.h b/bin/ksh/table.h index cdadbb9b6bd..f88c178b272 100644 --- a/bin/ksh/table.h +++ b/bin/ksh/table.h @@ -1,4 +1,4 @@ -/* $OpenBSD: table.h,v 1.4 1998/06/25 19:02:22 millert Exp $ */ +/* $OpenBSD: table.h,v 1.5 1999/06/15 01:18:36 millert Exp $ */ /* $From: table.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */ @@ -169,6 +169,7 @@ extern const struct builtin shbuiltins [], kshbuiltins []; #define V_POSIXLY_CORRECT 14 #define V_TMOUT 15 #define V_TMPDIR 16 +#define V_LINENO 17 /* values for set_prompt() */ #define PS1 0 /* command */ @@ -179,3 +180,4 @@ EXTERN const char *def_path; /* path to use if PATH not set */ EXTERN char *tmpdir; /* TMPDIR value */ EXTERN const char *prompt; EXTERN int cur_prompt; /* PS1 or PS2 */ +EXTERN int current_lineno; /* LINENO value */ diff --git a/bin/ksh/tree.c b/bin/ksh/tree.c index 69478b5a8fd..24539adc754 100644 --- a/bin/ksh/tree.c +++ b/bin/ksh/tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tree.c,v 1.7 1998/10/29 04:09:21 millert Exp $ */ +/* $OpenBSD: tree.c,v 1.8 1999/06/15 01:18:36 millert Exp $ */ /* * command tree climbing @@ -173,22 +173,12 @@ ptree(t, indent, shf) for (ioact = t->ioact; *ioact != NULL; ) { struct ioword *iop = *ioact++; - /* name is 0 when tracing (set -x) */ - if ((iop->flag & IOTYPE) == IOHERE && iop->name) { - struct shf *rshf; - char buf[1024]; - int n; - + /* heredoc is 0 when tracing (set -x) */ + if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) { tputc('\n', shf); - if ((rshf = shf_open(iop->name, O_RDONLY, 0, 0))) { - while ((n = shf_read(buf, sizeof(buf), rshf)) - > 0) - shf_write(buf, n, shf); - shf_close(rshf); - } else - errorf("can't open %s - %s", - iop->name, strerror(errno)); - fptreef(shf, indent, "%s", evalstr(iop->delim, 0)); + shf_puts(iop->heredoc, shf); + fptreef(shf, indent, "%s", + evalstr(iop->delim, 0)); need_nl = 1; } } @@ -523,6 +513,7 @@ tcopy(t, ap) r->left = tcopy(t->left, ap); r->right = tcopy(t->right, ap); + r->lineno = t->lineno; return r; } @@ -584,6 +575,10 @@ wdscan(wp, c) nest--; break; #endif /* KSH */ + default: + internal_errorf(0, + "wdscan: unknown char 0x%x (carrying on)", + wp[-1]); } } @@ -682,6 +677,8 @@ iocopy(iow, ap) q->name = wdcopy(p->name, ap); if (p->delim != (char *) 0) q->delim = wdcopy(p->delim, ap); + if (p->heredoc != (char *) 0) + q->heredoc = str_save(p->heredoc, ap); } ior[i] = NULL; @@ -737,6 +734,10 @@ iofree(iow, ap) for (iop = iow; (p = *iop++) != NULL; ) { if (p->name != NULL) afree((void*)p->name, ap); + if (p->delim != NULL) + afree((void*)p->delim, ap); + if (p->heredoc != NULL) + afree((void*)p->heredoc, ap); afree((void*)p, ap); } } diff --git a/bin/ksh/tree.h b/bin/ksh/tree.h index aac076565b3..ef20c312ce6 100644 --- a/bin/ksh/tree.h +++ b/bin/ksh/tree.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tree.h,v 1.5 1999/01/19 20:41:56 millert Exp $ */ +/* $OpenBSD: tree.h,v 1.6 1999/06/15 01:18:36 millert Exp $ */ /* * command trees for compile/execute @@ -27,6 +27,7 @@ struct op { * select, and functions; * path to execute for TEXEC */ + int lineno; /* TCOM/TFUNC: LINENO for this */ }; /* Tree.type values */ @@ -76,8 +77,9 @@ struct op { struct ioword { int unit; /* unit affected */ int flag; /* action (below) */ - char *name; /* file name */ + char *name; /* file name (unused if heredoc) */ char *delim; /* delimiter for <<,<<- */ + char *heredoc;/* content of heredoc */ }; /* ioword.flag - type of redirection */ diff --git a/bin/ksh/var.c b/bin/ksh/var.c index c6170734b13..71ddc4f9d2e 100644 --- a/bin/ksh/var.c +++ b/bin/ksh/var.c @@ -1,4 +1,4 @@ -/* $OpenBSD: var.c,v 1.9 1999/01/10 17:55:03 millert Exp $ */ +/* $OpenBSD: var.c,v 1.10 1999/06/15 01:18:36 millert Exp $ */ #include "sh.h" #include "ksh_time.h" @@ -20,6 +20,7 @@ static struct table specials; static char *formatstr ARGS((struct tbl *vp, const char *s)); static void export ARGS((struct tbl *vp, const char *val)); static int special ARGS((const char *name)); +static void unspecial ARGS((const char *name)); static void getspec ARGS((struct tbl *vp)); static void setspec ARGS((struct tbl *vp)); static void unsetspec ARGS((struct tbl *vp)); @@ -37,7 +38,7 @@ newblock() l = (struct block *) alloc(sizeof(struct block), ATEMP); l->flags = 0; - ainit(&l->area); + ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */ if (!e->loc) { l->argc = 0; l->argv = (char **) empty; @@ -106,12 +107,13 @@ initvar() { "SECONDS", V_SECONDS }, { "TMOUT", V_TMOUT }, #endif /* KSH */ + { "LINENO", V_LINENO }, { (char *) 0, 0 } }; int i; struct tbl *tp; - tinit(&specials, APERM, 32); /* must be 2^n (currently 16 speciasl) */ + tinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */ for (i = 0; names[i].name; i++) { tp = tenter(&specials, names[i].name, hash(names[i].name)); tp->flag = DEFINED|ISSET; @@ -144,7 +146,7 @@ array_index_calc(n, arrayp, valp) sub = substitute(tmp, 0); afree(tmp, ATEMP); n = str_nsave(n, p - n, ATEMP); - evaluate(sub, &rval, FALSE); + evaluate(sub, &rval, KSH_UNWIND_ERROR); if (rval < 0 || rval > ARRAYMAX) errorf("%s: subscript out of range", n); *valp = rval; @@ -175,7 +177,7 @@ global(n) if (array) errorf("bad substitution"); vp = &vtemp; - vp->flag = (DEFINED|RDONLY); + vp->flag = DEFINED; vp->type = 0; vp->areap = ATEMP; *vp->name = c; @@ -183,10 +185,12 @@ global(n) for (c = 0; digit(*n); n++) c = c*10 + *n-'0'; if (c <= l->argc) - /* SETSTR: can't fail */ - setstr(vp, l->argv[c]); + /* setstr can't fail here */ + setstr(vp, l->argv[c], KSH_RETURN_ERROR); + vp->flag |= RDONLY; return vp; } + vp->flag |= RDONLY; if (n[1] != '\0') return vp; vp->flag |= ISSET|INTEGER; @@ -347,11 +351,18 @@ intval(vp) } /* set variable to string value */ -void -setstr(vq, s) +int +setstr(vq, s, error_ok) register struct tbl *vq; const char *s; + int error_ok; { + if (vq->flag & RDONLY) { + warningf(TRUE, "%s: is read only", vq->name); + if (!error_ok) + errorf(null); + return 0; + } if (!(vq->flag&INTEGER)) { /* string dest */ if ((vq->flag&ALLOC)) { /* debugging */ @@ -374,11 +385,12 @@ setstr(vq, s) vq->flag |= ALLOC; } } else /* integer dest */ - /* XXX is this correct? */ - v_evaluate(vq, s, FALSE); + if (!v_evaluate(vq, s, error_ok)) + return 0; vq->flag |= ISSET; if ((vq->flag&SPECIAL)) setspec(vq); + return 1; } /* set variable to integer */ @@ -393,8 +405,8 @@ setint(vq, n) vp->type = 0; vp->areap = ATEMP; vp->val.i = n; - /* SETSTR: can't fail */ - setstr(vq, str_val(vp)); + /* setstr can't fail here */ + setstr(vq, str_val(vp), KSH_RETURN_ERROR); } else vq->val.i = n; vq->flag |= ISSET; @@ -643,6 +655,7 @@ typeset(var, set, clr, field, base) /* most calls are with set/clr == 0 */ if (set | clr) { + int ok = 1; /* XXX if x[0] isn't set, there will be problems: need to have * one copy of attributes for arrays... */ @@ -679,25 +692,40 @@ typeset(var, set, clr, field, base) if (set & (LJUST|RJUST|ZEROFIL)) t->u2.field = field; if (fake_assign) { - /* SETSTR: XXX make unset, then fail? */ - setstr(t, s); + if (!setstr(t, s, KSH_RETURN_ERROR)) { + /* Somewhat arbitrary action here: + * zap contents of varibale, but keep + * the flag settings. + */ + ok = 0; + if (t->flag & INTEGER) + t->flag &= ~ISSET; + else { + if (t->flag & ALLOC) + afree((void*) t->val.s, + t->areap); + t->flag &= ~(ISSET|ALLOC); + t->type = 0; + } + } if (free_me) afree((void *) free_me, t->areap); } } + if (!ok) + errorf(null); } if (val != NULL) { if (vp->flag&INTEGER) { /* do not zero base before assignment */ - /* SETSTR: XXX */ - setstr(vp, val); + setstr(vp, val, KSH_UNWIND_ERROR); /* Done after assignment to override default */ if (base > 0) vp->type = base; } else - /* SETSTR: can't fail */ - setstr(vp, val); + /* setstr can't fail (readonly check already done) */ + setstr(vp, val, KSH_RETURN_ERROR); } /* only x[0] is ever exported, so use vpbase */ @@ -841,9 +869,9 @@ makenv() /* integer to string */ char *val; val = str_val(vp); - vp->flag &= ~INTEGER; - /* SETSTR: can't fail */ - setstr(vp, val); + vp->flag &= ~(INTEGER|RDONLY); + /* setstr can't fail here */ + setstr(vp, val, KSH_RETURN_ERROR); } XPput(env, vp->val.s); } @@ -874,12 +902,25 @@ special(name) register struct tbl *tp; tp = tsearch(&specials, name, hash(name)); - return tp ? tp->type : V_NONE; + return tp && (tp->flag & ISSET) ? tp->type : V_NONE; +} + +/* Make a variable non-special */ +static void +unspecial(name) + register const char * name; +{ + register struct tbl *tp; + + tp = tsearch(&specials, name, hash(name)); + if (tp) + tdelete(tp); } #ifdef KSH static time_t seconds; /* time SECONDS last set */ #endif /* KSH */ +static int user_lineno; /* what user set $LINENO to */ static void getspec(vp) @@ -889,7 +930,12 @@ getspec(vp) #ifdef KSH case V_SECONDS: vp->flag &= ~SPECIAL; - setint(vp, (long) (time((time_t *)0) - seconds)); + /* On start up the value of SECONDS is used before seconds + * has been set - don't do anything in this case + * (see initcoms[] in main.c). + */ + if (vp->flag & ISSET) + setint(vp, (long) (time((time_t *)0) - seconds)); vp->flag |= SPECIAL; break; case V_RANDOM: @@ -910,6 +956,11 @@ getspec(vp) setint(vp, (long) user_opt.uoptind); vp->flag |= SPECIAL; break; + case V_LINENO: + vp->flag &= ~SPECIAL; + setint(vp, (long) current_lineno + user_lineno); + vp->flag |= SPECIAL; + break; } } @@ -985,7 +1036,9 @@ setspec(vp) mpset(str_val(vp)); break; case V_MAILCHECK: - /* mail_check_set(intval(vp)); */ + vp->flag &= ~SPECIAL; + mcset(intval(vp)); + vp->flag |= SPECIAL; break; case V_RANDOM: vp->flag &= ~SPECIAL; @@ -1003,6 +1056,12 @@ setspec(vp) ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; break; #endif /* KSH */ + case V_LINENO: + vp->flag &= ~SPECIAL; + /* The -1 is because line numbering starts at 1. */ + user_lineno = (unsigned int) intval(vp) - current_lineno - 1; + vp->flag |= SPECIAL; + break; } } @@ -1035,24 +1094,27 @@ unsetspec(vp) case V_MAILPATH: mpset((char *) 0); break; - case V_TMOUT: - /* at&t ksh doesn't do this. TMOUT becomes unspecial so - * future assignments don't have effect. Could be - * useful (eg, after "TMOUT=60; unset TMOUT", user - * can't get rid of the timeout...). Should be handled - * by generic unset code... - */ - ksh_tmout = 0; - break; #endif /* KSH */ - /* todo: generic action for specials (at&t says variables - * lose their special meaning when unset but global() checks - * the name of new vars to see if they are special) - * lose meaning: _, ERRNO, LINENO, MAILCHECK, - * OPTARG, OPTIND, RANDOM, SECONDS, TMOUT. - * unknown: MAIL, MAILPATH, HISTSIZE, HISTFILE, + + case V_LINENO: +#ifdef KSH + case V_MAILCHECK: /* at&t ksh leaves previous value in place */ + case V_RANDOM: + case V_SECONDS: + case V_TMOUT: /* at&t ksh leaves previous value in place */ +#endif /* KSH */ + unspecial(vp->name); + break; + + /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning, + * but OPTARG does not (still set by getopts) and _ is also still + * set in various places. + * Don't know what at&t does for: + * MAIL, MAILPATH, HISTSIZE, HISTFILE, + * Unsetting these in at&t ksh does not loose the `specialness': * no effect: IFS, COLUMNS, PATH, TMPDIR, * VISUAL, EDITOR, + * pdkshisms: no effect: * POSIXLY_CORRECT (use set +o posix instead) */ } @@ -1165,7 +1227,7 @@ set_array(var, reset, vals) */ for (i = 0; vals[i]; i++) { vq = arraysearch(vp, i); - /* SETSTR: XXX */ - setstr(vq, vals[i]); + /* would be nice to deal with errors here... (see above) */ + setstr(vq, vals[i], KSH_RETURN_ERROR); } } diff --git a/bin/ksh/version.c b/bin/ksh/version.c index 0e7239283ed..2566a0a54f7 100644 --- a/bin/ksh/version.c +++ b/bin/ksh/version.c @@ -1,4 +1,4 @@ -/* $OpenBSD: version.c,v 1.10 1999/01/19 20:41:56 millert Exp $ */ +/* $OpenBSD: version.c,v 1.11 1999/06/15 01:18:36 millert Exp $ */ /* * value of $KSH_VERSION (or $SH_VERSION) @@ -7,4 +7,4 @@ #include "sh.h" const char ksh_version [] = - "@(#)PD KSH v5.2.13.7 99/01/15"; + "@(#)PD KSH v5.2.13.11 99/05/13"; |